1:"$Sreact.fragment" 2:I[5379,["915","static/chunks/915-e75e15b01ec6c60e.js","619","static/chunks/619-ba102abea3e3d0e4.js","284","static/chunks/284-7b00ddceae1508d2.js","177","static/chunks/app/layout-f47d2482c80930e1.js"],"ThemeProvider"] 3:I[120,["915","static/chunks/915-e75e15b01ec6c60e.js","619","static/chunks/619-ba102abea3e3d0e4.js","284","static/chunks/284-7b00ddceae1508d2.js","177","static/chunks/app/layout-f47d2482c80930e1.js"],"Header"] 4:I[9766,[],""] 5:I[8924,[],""] 6:I[6613,["915","static/chunks/915-e75e15b01ec6c60e.js","619","static/chunks/619-ba102abea3e3d0e4.js","284","static/chunks/284-7b00ddceae1508d2.js","177","static/chunks/app/layout-f47d2482c80930e1.js"],"Footer"] 7:I[7989,[],"ClientSegmentRoot"] 8:I[2086,["915","static/chunks/915-e75e15b01ec6c60e.js","284","static/chunks/284-7b00ddceae1508d2.js","584","static/chunks/app/blog/layout-56162451cf26531f.js"],"default"] a:I[2401,["915","static/chunks/915-e75e15b01ec6c60e.js","619","static/chunks/619-ba102abea3e3d0e4.js","874","static/chunks/app/blog/securing-your-docker-images/page-8e554d49cb7075d5.js"],"BackToBlog"] 56:I[7150,[],""] :HL["/cv/_next/static/media/4cf2300e9c8272f7-s.p.woff2","font",{"crossOrigin":"","type":"font/woff2"}] :HL["/cv/_next/static/media/93f479601ee12b01-s.p.woff2","font",{"crossOrigin":"","type":"font/woff2"}] :HL["/cv/_next/static/css/d893c1b9853c3059.css","style"] 0:{"P":null,"b":"wIBcpDzxA6-tV9uMd1RSd","p":"/cv","c":["","blog","securing-your-docker-images"],"i":false,"f":[[["",{"children":["blog",{"children":["securing-your-docker-images",{"children":["__PAGE__",{}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/cv/_next/static/css/d893c1b9853c3059.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"__variable_e0e7f9 __variable_49b421 bg-white tracking-tight antialiased dark:bg-zinc-950","children":["$","$L2",null,{"enableSystem":true,"attribute":"class","storageKey":"theme","defaultTheme":"system","children":["$","div",null,{"className":"flex min-h-screen w-full flex-col font-[family-name:var(--font-inter-tight)]","children":["$","div",null,{"className":"relative mx-auto w-full max-w-screen-sm flex-1 px-4 pt-20","children":[["$","$L3",null,{}],["$","$L4",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}],["$","$L6",null,{}]]}]}]}]}]}]]}],{"children":["blog",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["securing-your-docker-images",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[[["$","$La",null,{}],"\n",["$","figure",null,{"children":[["$","img",null,{"src":"https://joeeey.com/static/c161c59028d1e817d0cdce747b9e79e7/d8bb9/covers.png","alt":"Image from joeeey.com","className":"rounded-xl"}],["$","figcaption",null,{"className":"text-center","children":"Why Secure Docker Images Are No Longer Optional in DevOps - Ryan J"}]]}],"\n",["$","h1",null,{"children":"🐳 Why Secure Docker Images Are No Longer Optional in DevOps"}],"\n",["$","p",null,{"children":["In the last few years, the rise of ",["$","strong",null,{"children":"supply chain attacks"}]," and vulnerabilities in common base images has forced engineering teams to rethink how they build and ship containerized workloads. Security in the DevOps pipeline is no longer an afterthought — it’s an essential requirement."]}],"\n",["$","p",null,{"children":"This post walks through:"}],"\n",["$","ul",null,{"children":["\n",["$","li",null,{"children":["Why ",["$","strong",null,{"children":"hardened"}]," and ",["$","strong",null,{"children":"distroless"}]," containers are gaining traction"]}],"\n",["$","li",null,{"children":["How to use ",["$","strong",null,{"children":"multi-stage builds"}]," effectively"]}],"\n",["$","li",null,{"children":"General best practices for securing Docker builds"}],"\n",["$","li",null,{"children":"Examples of hardened images and modern container security tools"}],"\n",["$","li",null,{"children":"A practical comparison of popular hardened/distroless images"}],"\n",["$","li",null,{"children":"Why these practices are an emerging requirement in DevOps"}],"\n"]}],"\n","$Lb","\n","$Lc","\n","$Ld","\n","$Le","\n","$Lf","\n","$L10","\n","$L11","\n","$L12","\n","$L13","\n","$L14","\n","$L15","\n","$L16","\n","$L17","\n","$L18","\n","$L19","\n","$L1a","\n","$L1b","\n","$L1c","\n","$L1d","\n","$L1e","\n","$L1f","\n","$L20","\n","$L21","\n","$L22","\n","$L23","\n","$L24","\n","$L25","\n","$L26","\n","$L27","\n","$L28","\n","$L29","\n","$L2a","\n","$L2b","\n","$L2c","\n","$L2d","\n","$L2e","\n","$L2f","\n","$L30","\n","$L31","\n","$L32","\n","$L33","\n","$L34","\n","$L35","\n","$L36","\n","$L37","\n","$L38","\n","$L39","\n","$L3a","\n","$L3b","\n","$L3c","\n","$L3d","\n","$L3e","\n","$L3f","\n","$L40","\n","$L41","\n","$L42","\n","$L43","\n","$L44","\n","$L45","\n","$L46","\n","$L47","\n","$L48","\n","$L49","\n","$L4a","\n","$L4b","\n","$L4c","\n","$L4d","\n","$L4e","\n","$L4f","\n","$L50","\n","$L51","\n","$L52","\n","$L53"],null,"$L54"]}],{},null,false]},null,false]},null,false]},null,false],"$L55",false]],"m":"$undefined","G":["$56",[]],"s":false,"S":true} 57:I[4431,[],"OutletBoundary"] 59:I[5278,[],"AsyncMetadataOutlet"] 5b:I[4431,[],"ViewportBoundary"] 5d:I[4431,[],"MetadataBoundary"] 5e:"$Sreact.suspense" b:["$","hr",null,{}] c:["$","h2",null,{"children":"🪨 Why Hardened Containers?"}] d:["$","p",null,{"children":["A ",["$","em",null,{"children":"hardened container"}]," is one that’s been stripped down to contain only the minimum software necessary to run an application. The goal is to ",["$","strong",null,{"children":"reduce the attack surface"}],"."]}] e:["$","p",null,{"children":["For example, a typical Ubuntu-based image comes with many binaries (",["$","code",null,{"children":"curl"}],", ",["$","code",null,{"children":"bash"}],", ",["$","code",null,{"children":"wget"}],", etc.) that your application does not need. Each of these tools could introduce vulnerabilities or be exploited in runtime attacks."]}] f:["$","p",null,{"children":"By contrast, hardened containers:"}] 10:["$","ul",null,{"children":["\n",["$","li",null,{"children":"Remove unnecessary shells and utilities"}],"\n",["$","li",null,{"children":"Lock down users (non-root execution)"}],"\n",["$","li",null,{"children":"Include only application dependencies"}],"\n"]}] 11:["$","p",null,{"children":"This reduces CVE exposure and makes it much harder for attackers to pivot inside your container."}] 12:["$","hr",null,{}] 13:["$","h2",null,{"children":"📭 Distroless Containers"}] 14:["$","p",null,{"children":[["$","strong",null,{"children":"Distroless"}]," images take hardening a step further. Instead of shipping a full operating system distribution, Google’s Distroless project provides images that contain ",["$","em",null,{"children":"only"}]," your application runtime."]}] 15:["$","p",null,{"children":"For example:"}] 16:["$","pre",null,{"children":["$","code",null,{"className":"language-dockerfile","children":"# Use Google Distroless as base\nFROM gcr.io/distroless/nodejs20\n\nWORKDIR /app\nCOPY --chown=nonroot:nonroot . .\n\nUSER nonroot\nCMD [\"server.js\"]\n"}]}] 17:["$","p",null,{"children":["Notice what’s missing? There’s ",["$","strong",null,{"children":"no shell, no package manager, no utilities"}],". This means attackers cannot easily run arbitrary commands like ",["$","code",null,{"children":"bash"}]," or ",["$","code",null,{"children":"apt-get"}]," inside your container."]}] 18:["$","hr",null,{}] 19:["$","h2",null,{"children":"☯️ Multi-Stage Builds for Leaner Images"}] 1a:["$","p",null,{"children":["Another essential practice is ",["$","strong",null,{"children":"multi-stage builds"}],". This technique allows you to separate build-time dependencies from runtime dependencies."]}] 1b:["$","h3",null,{"children":"Example: Go Application"}] 1c:["$","pre",null,{"children":["$","code",null,{"className":"language-dockerfile","children":"## Stage 1: Build the Go application\nFROM golang:1.22 AS builder # Use official Golang image for build stage 'builder'\nWORKDIR /src # Set work dir to /src where our code will be\nCOPY . . # Copy all code to /src \nRUN go build -o app # Compile the Go application and output the binary as 'app'\n\n## Stage 2: Create a minimal runtime image\nFROM gcr.io/distroless/base-debian12 # Use a minimal \"distroless\" image (just runtime libraries, no shell or other rubbish)\nCOPY --from=builder /src/app /app # Copy the binary from the build stage into root of runtime image\n\nUSER nonroot # Run application as non-root user for improved security\nENTRYPOINT [\"/app\"] # Set container entrypoint to execute 'app' when container starts\n"}]}] 1d:["$","p",null,{"children":"Here’s what happens:"}] 1e:["$","ul",null,{"children":["\n",["$","li",null,{"children":[["$","strong",null,{"children":"Stage 1 (builder):"}]," Uses the full Golang SDK to compile the app."]}],"\n",["$","li",null,{"children":[["$","strong",null,{"children":"Stage 2 (runtime):"}]," Uses a distroless base image that contains no compiler tools, just your compiled binary."]}],"\n"]}] 1f:["$","p",null,{"children":"The result? Smaller images, fewer dependencies, and less attack surface."}] 20:["$","h3",null,{"children":"🎭 Performance Trade-offs"}] 21:["$","p",null,{"children":["Multi-stage builds are not always quicker on the ",["$","em",null,{"children":"first"}]," build, since Docker builds multiple images (builder + runtime). But in practice, they make builds and deployments ",["$","strong",null,{"children":"faster overall"}],":"]}] 22:["$","ul",null,{"children":["\n",["$","li",null,{"children":["The ",["$","strong",null,{"children":"final image is smaller"}],", so pulling/pushing between registry and clusters is faster."]}],"\n",["$","li",null,{"children":[["$","strong",null,{"children":"Layer caching"}]," works well: once dependencies are built, only code changes trigger rebuilds."]}],"\n",["$","li",null,{"children":["You ",["$","strong",null,{"children":"build once, run everywhere"}],", avoiding redundant rebuilds across environments."]}],"\n"]}] 23:["$","p",null,{"children":"So while the initial build may be slightly longer, subsequent builds and deployments are faster, lighter, and more efficient."}] 24:["$","hr",null,{}] 25:["$","h2",null,{"children":"🔐 General Ways to Secure Docker Builds"}] 26:["$","p",null,{"children":["In addition to distroless and hardened images, you should also consider ",["$","strong",null,{"children":"rootless containers"}]," and ",["$","strong",null,{"children":"read-only volumes"}]," as part of your defense-in-depth strategy."]}] 27:["$","ul",null,{"children":["\n",["$","li",null,{"children":[["$","strong",null,{"children":"Rootless containers"}],": Running Docker or container runtimes in rootless mode prevents the daemon and processes from requiring root on the host. This dramatically reduces the blast radius if a container breakout occurs."]}],"\n",["$","li",null,{"children":[["$","strong",null,{"children":"Read-only volumes"}],": By mounting containers with ",["$","code",null,{"children":"--read-only"}]," (or using Kubernetes security contexts with ",["$","code",null,{"children":"readOnlyRootFilesystem: true"}],"), you ensure the container cannot write to its filesystem except to explicitly mounted writable paths. This mitigates persistence of malware and reduces accidental writes at runtime."]}],"\n"]}] 28:["$","h3",null,{"children":"Example: Enforcing Rootless & Read-only"}] 29:["$","p",null,{"children":["$","strong",null,{"children":"Docker run:"}]}] 2a:["$","pre",null,{"children":["$","code",null,{"className":"language-bash","children":"docker run --read-only --user 1000:1000 my-secure-app\n"}]}] 2b:["$","p",null,{"children":["$","strong",null,{"children":"Kubernetes Pod securityContext:"}]}] 2c:["$","pre",null,{"children":["$","code",null,{"className":"language-yaml","children":"apiVersion: v1\nkind: Pod\nmetadata:\n name: secure-pod\nspec:\n containers:\n - name: app\n image: my-secure-app:latest\n securityContext:\n runAsNonRoot: true # Ensures container does not run as root user; fails if container attempts to run as UID 0\n runAsUser: 1000 # Explicitly runs the container process as user ID 1000 inside the container\n readOnlyRootFilesystem: true # Mounts root filesystem as read-only; prevents write access to container filesystem at runtime\n allowPrivilegeEscalation: false # Prevents processes from gaining additional privileges (sudo)\n"}]}] 2d:["$","p",null,{"children":"This configuration enforces that the container does not run as root, cannot escalate privileges, and operates with a read-only root filesystem."}] 2e:["$","h3",null,{"children":"💡 Other Kubernetes Security Tips"}] 2f:["$","h3",null,{"children":"Capabilities"}] 30:["$","p",null,{"children":"You can drop or add Linux capabilities to restrict what the container process can do:"}] 31:["$","pre",null,{"children":["$","code",null,{"className":"language-yaml","children":"capabilities:\n drop:\n - ALL # Drop all capabilities by default\n add:\n - NET_BIND_SERVICE # Only allow binding to privileged ports <1024\n"}]}] 32:["$","h3",null,{"children":"Seccomp Profiles"}] 33:["$","p",null,{"children":"Seccomp profiles limit the system calls a container can make:"}] 34:["$","pre",null,{"children":["$","code",null,{"className":"language-yaml","children":"seccompProfile:\n type: RuntimeDefault # Use the default runtime seccomp profile\n"}]}] 35:["$","ul",null,{"children":["\n",["$","li",null,{"children":"You can also provide a custom profile to allow or deny specific syscalls, reducing the attack surface."}],"\n"]}] 36:["$","h3",null,{"children":"Other Useful Options"}] 37:["$","ul",null,{"children":["\n",["$","li",null,{"children":[["$","code",null,{"children":"fsGroup"}],": Sets group ownership for mounted volumes."]}],"\n",["$","li",null,{"children":[["$","code",null,{"children":"runAsGroup"}],": Runs container processes as a specific GID."]}],"\n",["$","li",null,{"children":[["$","code",null,{"children":"readOnlyPaths"}]," / ",["$","code",null,{"children":"tmpfsPaths"}],": Limit filesystem paths that are writable."]}],"\n"]}] 38:["$","hr",null,{}] 39:["$","h3",null,{"children":"📝 Summary"}] 3a:["$","p",null,{"children":"Beyond hardened and distroless containers, here are some practical best practices:"}] 3b:["$","ol",null,{"children":["\n",["$","li",null,{"children":["\n",["$","p",null,{"children":[["$","strong",null,{"children":"Pin image versions"}],["$","br",null,{}],"\n","Avoid floating tags like ",["$","code",null,{"children":":latest"}],". Always specify exact versions (",["$","code",null,{"children":"golang:1.22.2"}],")."]}],"\n"]}],"\n",["$","li",null,{"children":["\n",["$","p",null,{"children":[["$","strong",null,{"children":"Run as non-root"}],["$","br",null,{}],"\n","Add ",["$","code",null,{"children":"USER nonroot"}]," (or a dedicated user) to prevent privilege escalation."]}],"\n"]}],"\n",["$","li",null,{"children":["\n",["$","p",null,{"children":[["$","strong",null,{"children":"Scan images"}],["$","br",null,{}],"\n","Use tools like ",["$","strong",null,{"children":"Trivy"}],", ",["$","strong",null,{"children":"Grype"}],", ",["$","strong",null,{"children":"Snyk"}],", and ",["$","strong",null,{"children":"Anchore"}]," to detect vulnerabilities early in CI/CD."]}],"\n"]}],"\n",["$","li",null,{"children":["\n",["$","p",null,{"children":[["$","strong",null,{"children":["Use ",["$","code",null,{"children":".dockerignore"}]]}],["$","br",null,{}],"\n","Prevent unnecessary files (secrets, ",["$","code",null,{"children":".git"}],", etc.) from being copied into your image."]}],"\n"]}],"\n",["$","li",null,{"children":["\n",["$","p",null,{"children":[["$","strong",null,{"children":"Immutable builds"}],["$","br",null,{}],"\n","Build once, deploy everywhere. Don’t rebuild images differently across environments."]}],"\n"]}],"\n",["$","li",null,{"children":["\n",["$","p",null,{"children":[["$","strong",null,{"children":"Limit network exposure"}],["$","br",null,{}],"\n","Explicitly expose only the ports you need."]}],"\n"]}],"\n",["$","li",null,{"children":["\n",["$","p",null,{"children":[["$","strong",null,{"children":"Leverage signing & provenance"}],["$","br",null,{}],"\n","Use ",["$","strong",null,{"children":"cosign"}],", ",["$","strong",null,{"children":"Notary v2"}],", or registry-native signing to sign and verify images before deployment."]}],"\n"]}],"\n",["$","li",null,{"children":["\n",["$","p",null,{"children":[["$","strong",null,{"children":"Apply runtime security"}],["$","br",null,{}],"\n","Use admission controllers (like ",["$","strong",null,{"children":"Kyverno"}]," or ",["$","strong",null,{"children":"OPA/Gatekeeper"}],") to enforce security policies."]}],"\n"]}],"\n",["$","li",null,{"children":["\n",["$","p",null,{"children":[["$","strong",null,{"children":"Use hardened base images"}],["$","br",null,{}],"\n","Instead of generic distributions, rely on hardened alternatives like ",["$","strong",null,{"children":"WizOS"}],", ",["$","strong",null,{"children":"Chainguard Images"}],", or ",["$","strong",null,{"children":"Google’s Distroless"}],". These are designed with minimal attack surface and maintained for security."]}],"\n"]}],"\n",["$","li",null,{"children":["\n",["$","p",null,{"children":[["$","strong",null,{"children":"Perform SBOM generation"}],["$","br",null,{}],"\n","Generate a ",["$","strong",null,{"children":"Software Bill of Materials (SBOM)"}]," using tools like ",["$","strong",null,{"children":"Syft"}]," or ",["$","strong",null,{"children":"Anchore"}]," to track exactly what’s in your images."]}],"\n"]}],"\n",["$","li",null,{"children":["\n",["$","p",null,{"children":[["$","strong",null,{"children":"Least-privilege file permissions"}],["$","br",null,{}],"\n","Ensure filesystem permissions inside the image give the app only what it needs — avoid writing to sensitive paths at runtime."]}],"\n"]}],"\n",["$","li",null,{"children":["\n",["$","p",null,{"children":[["$","strong",null,{"children":"Limit capabilities"}],["$","br",null,{}],"\n","Drop Linux capabilities with ",["$","code",null,{"children":"docker run --cap-drop"}]," or with PodSecurity admission controls in Kubernetes."]}],"\n"]}],"\n",["$","li",null,{"children":["\n",["$","p",null,{"children":[["$","strong",null,{"children":"Use Seccomp and AppArmor"}],["$","br",null,{}],"\n","Apply runtime OS security profiles to restrict syscalls accessible to containers."]}],"\n"]}],"\n"]}] 3c:["$","hr",null,{}] 3d:["$","h2",null,{"children":"Example: Hardened Image with WizOS"}] 3e:["$","p",null,{"children":["$","img",null,{"src":"https://www.datocms-assets.com/75231/1747206812-wiz0s-2x.png?fm=webp","alt":"WizOS"}]}] 3f:["$","p",null,{"children":[["$","a",null,{"href":"https://www.wiz.io/blog/introducing-wizos-hardened-near-zero-cve-base-images","children":"WizOS"}]," provides hardened container images built with strict security standards. Here’s how a Node.js app might look using WizOS:"]}] 40:["$","pre",null,{"children":["$","code",null,{"className":"language-dockerfile","children":"# Stage 1: Build\nFROM node:20 AS builder\nWORKDIR /app\nCOPY package*.json ./\nRUN npm ci --production=false\nCOPY . .\nRUN npm run build\n\n# Stage 2: Hardened Runtime\nFROM wiz.io/wizos-node:latest\nWORKDIR /app\nCOPY --from=builder /app/dist ./\nUSER 1000\nCMD [\"node\", \"server.js\"]\n"}]}] 41:["$","p",null,{"children":["By starting from ",["$","strong",null,{"children":"WizOS hardened images"}],", you inherit security hardening out of the box, such as non-root defaults, minimized packages, and proactive maintenance."]}] 42:["$","hr",null,{}] 43:["$","h2",null,{"children":"🧰 Tools & Services to Improve Container Security"}] 44:["$","ul",null,{"children":["\n",["$","li",null,{"children":[["$","strong",null,{"children":["$","a",null,{"href":"https://www.wiz.io/platform/wiz-code","children":"Wiz"}]}]," - sbom generation, policy-based vulnerability scanning, K8s admission controls, hardened images"]}],"\n",["$","li",null,{"children":[["$","strong",null,{"children":["$","a",null,{"href":"https://trivy.dev/dev/","children":"Trivy"}]}]," — fast vulnerability scanner for images, filesystems, and repos."]}],"\n",["$","li",null,{"children":[["$","strong",null,{"children":["$","a",null,{"href":"https://github.com/anchore/grype?tab=readme-ov-file","children":"Grype"}]}]," — vulnerability scanner focusing on SBOM compatibility."]}],"\n",["$","li",null,{"children":[["$","strong",null,{"children":["$","a",null,{"href":"https://snyk.io/product/container-vulnerability-management/","children":"Snyk"}]}]," — developer-first scanner with fix pull requests and monitoring."]}],"\n",["$","li",null,{"children":[["$","strong",null,{"children":["$","a",null,{"href":"https://anchore.com","children":"Anchore"}]}]," — policy-based image analysis and scanning."]}],"\n",["$","li",null,{"children":[["$","strong",null,{"children":["$","a",null,{"href":"https://github.com/sigstore/cosign","children":"Cosign"}]}]," — image signing and verification for provenance."]}],"\n",["$","li",null,{"children":[["$","strong",null,{"children":["$","a",null,{"href":"https://github.com/anchore/syft?tab=readme-ov-file","children":"Syft"}]}]," — SBOM generation."]}],"\n",["$","li",null,{"children":[["$","strong",null,{"children":["$","a",null,{"href":"https://www.chainguard.dev","children":"Chainguard"}]}]," — hardened images and a secure supply chain offering."]}],"\n",["$","li",null,{"children":[["$","strong",null,{"children":["$","a",null,{"href":"https://notaryproject.dev/docs/user-guides/installation/cli/?ref=anaisurl.com","children":"Notary v2"}]}]," — proven and evolving image signing standard."]}],"\n"]}] 45:["$","hr",null,{}] 46:["$","h2",null,{"children":"🕵🏽 Comparison: Distroless vs WizOS vs Chainguard vs Alpine vs Ubuntu"}] 47:["$","table",null,{"border":"1","cellPadding":"8","cellSpacing":"0","children":[["$","thead",null,{"children":["$","tr",null,{"children":[["$","th",null,{"children":"Feature / Image"}],["$","th",null,{"children":"Distroless"}],["$","th",null,{"children":"WizOS (hardened)"}],["$","th",null,{"children":"Alpine"}],["$","th",null,{"children":"Ubuntu (standard)"}]]}]}],["$","tbody",null,{"children":[["$","tr",null,{"children":[["$","td",null,{"children":"Minimal runtime (no shell)"}],["$","td",null,{"children":"✅"}],["$","td",null,{"children":"✅ (minimal)"}],["$","td",null,{"children":"❌ "}],["$","td",null,{"children":"❌"}]]}],["$","tr",null,{"children":[["$","td",null,{"children":"Non-root default"}],["$","td",null,{"children":"⚠️ (you must set USER)"}],["$","td",null,{"children":"✅"}],["$","td",null,{"children":"⚠️"}],["$","td",null,{"children":"⚠️"}]]}],["$","tr",null,{"children":[["$","td",null,{"children":"Regular security maintenance"}],["$","td",null,{"children":"✅"}],["$","td",null,{"children":"✅"}],["$","td",null,{"children":"✅"}],["$","td",null,{"children":"✅"}]]}],["$","tr",null,{"children":[["$","td",null,{"children":"SBOM / provenance support"}],["$","td",null,{"children":"✅"}],["$","td",null,{"children":"✅"}],["$","td",null,{"children":"Partial"}],["$","td",null,{"children":"Partial"}]]}],["$","tr",null,{"children":[["$","td",null,{"children":"Size (small → large)"}],["$","td",null,{"children":"Small"}],["$","td",null,{"children":"Small → Medium"}],["$","td",null,{"children":"Very small"}],["$","td",null,{"children":"Large"}]]}],["$","tr",null,{"children":[["$","td",null,{"children":"Easy to debug at runtime"}],["$","td",null,{"children":"No (hard)"}],["$","td",null,{"children":"Better"}],["$","td",null,{"children":"Yes"}],["$","td",null,{"children":"Yes"}]]}],["$","tr",null,{"children":[["$","td",null,{"children":"Ideal for CI-built artifacts"}],["$","td",null,{"children":"✅"}],["$","td",null,{"children":"✅"}],["$","td",null,{"children":"✅"}],["$","td",null,{"children":"❌"}]]}]]}]]}] 48:["$","p",null,{"children":["$","strong",null,{"children":"Notes:"}]}] 49:["$","ul",null,{"children":["\n",["$","li",null,{"children":"Distroless is ultra-minimal and reduces runtime tools, which improves security but makes debugging harder."}],"\n",["$","li",null,{"children":"WizOS aims to balance minimalism with developer ergonomics and enterprise-grade maintenance as well as native Wiz CNAPP platform intgration."}],"\n",["$","li",null,{"children":"Ubuntu is feature-rich but carries a larger attack surface and larger image sizes."}],"\n"]}] 4a:["$","hr",null,{}] 4b:["$","h2",null,{"children":"🤔 HTML Table: Benefits of Hardened/Distroless/Multi-stage Methods"}] 4c:["$","table",null,{"children":[["$","thead",null,{"children":["$","tr",null,{"children":[["$","th",null,{"children":"Method"}],["$","th",null,{"children":"Primary Benefit"}],["$","th",null,{"children":"How it Mitigates Vulnerabilities"}]]}]}],["$","tbody",null,{"children":[["$","tr",null,{"children":[["$","td",null,{"children":"Distroless Images"}],["$","td",null,{"children":"Minimal attack surface"}],["$","td",null,{"children":"Removes shells, package managers and utilities attackers use for lateral movement and exploitation."}]]}],["$","tr",null,{"children":[["$","td",null,{"children":"Hardened Base Images (WizOS/Chainguard)"}],["$","td",null,{"children":"Secure-by-default configuration"}],["$","td",null,{"children":"Ships with non-root defaults, patched packages and curated binaries to reduce CVEs and misconfigurations."}]]}],["$","tr",null,{"children":[["$","td",null,{"children":"Multi-Stage Builds"}],["$","td",null,{"children":"Smaller runtime images"}],["$","td",null,{"children":"Keeps build tools and credentials out of runtime image by separating build and runtime stages."}]]}],["$","tr",null,{"children":[["$","td",null,{"children":"Image Scanning (Trivy/Grype/Snyk)"}],["$","td",null,{"children":"Early detection of CVEs"}],["$","td",null,{"children":"Identifies known vulnerabilities in base images and installed packages before deployment."}]]}],["$","tr",null,{"children":[["$","td",null,{"children":"SBOM & Signing (Syft/Cosign)"}],["$","td",null,{"children":"Provenance & supply-chain trust"}],["$","td",null,{"children":"Provides a verifiable list of components and cryptographic signing to ensure image integrity."}]]}],["$","tr",null,{"children":[["$","td",null,{"children":"Runtime Controls (Seccomp/AppArmor/PSP)"}],["$","td",null,{"children":"Reduce runtime privilege"}],["$","td",null,{"children":"Restricts syscalls and capabilities which prevents exploitation of kernel interfaces and privilege escalation."}]]}]]}]]}] 4d:["$","hr",null,{}] 4e:["$","h2",null,{"children":"🎬 Final Thoughts"}] 4f:["$","p",null,{"children":["If you’re still shipping containers built on top of full OS distributions, now’s the time to rethink your approach. Adopting ",["$","strong",null,{"children":"distroless images"}],", ",["$","strong",null,{"children":"hardened distributions"}],", and ",["$","strong",null,{"children":"multi-stage builds"}]," won’t just improve your security posture — it will also:"]}] 50:["$","ul",null,{"children":["\n",["$","li",null,{"children":"Reduce image size"}],"\n",["$","li",null,{"children":"Improve deployment speed"}],"\n",["$","li",null,{"children":"Simplify compliance audits"}],"\n",["$","li",null,{"children":"Reduce headaches!"}],"\n"]}] 51:["$","p",null,{"children":["Container hardening is not about paranoia — it’s about ",["$","strong",null,{"children":"resilience"}],". In today’s DevOps environments, resilience is a requirement, not an option."]}] 52:["$","hr",null,{}] 53:["$","p",null,{"children":"👉 Next steps: Try refactoring one of your Dockerfiles today using multi-stage builds and a hardened base image (Distroless, WizOS, or Chainguard). Run a vulnerability scan before and after, and generate an SBOM. The difference will speak for itself."}] 54:["$","$L57",null,{"children":["$L58",["$","$L59",null,{"promise":"$@5a"}]]}] 55:["$","$1","h",{"children":[null,[["$","$L5b",null,{"children":"$L5c"}],["$","meta",null,{"name":"next-size-adjust","content":""}]],["$","$L5d",null,{"children":["$","div",null,{"hidden":true,"children":["$","$5e",null,{"fallback":null,"children":"$L5f"}]}]}]]}] 9:"$0:f:0:1:2:children:1:props:children:1:props:params" 5c:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","2",{"name":"theme-color","content":"#ffffff"}]] 58:null 60:I[622,[],"IconMark"] 5a:{"metadata":[["$","title","0",{"children":"Ryan Johnston - CV"}],["$","meta","1",{"name":"description","content":"Ryan Johnston - CV"}],["$","link","2",{"rel":"icon","href":"/cv/favicon.ico","type":"image/x-icon","sizes":"16x16"}],["$","$L60","3",{}]],"error":null,"digest":"$undefined"} 5f:"$5a:metadata"