Skip to main content

Image Hardening, Minimal Base Images, and Supply-Chain Scanning

What This Concept Is

A container image is a filesystem plus some metadata. Everything running in production is a container image (or a VM image); therefore everything running in production came from somewhere, was built at some point, had some dependencies pulled in, and can be replaced without telling you. This chain -- from source code to running binary -- is the software supply chain.

Image hardening is the habit of making the image itself as small and as boring as possible:

  • pick a minimal base image (distroless, alpine, scratch) -- if an attacker drops a shell, there should not be one
  • install only what the app needs to run, not to build
  • run as non-root with read-only root filesystem where possible
  • drop Linux capabilities you do not need
  • pin base-image digests, not floating tags

Supply-chain scanning is the set of controls that make the image trustworthy:

  • vulnerability scanning -- check the image for known CVEs (Trivy, Grype, cloud registry scanners) at build and at deploy
  • signing -- cryptographically sign images with a tool like Sigstore / cosign, and have the cluster verify signatures before running
  • provenance -- record how the image was built, by whom, from what source, using what steps. The SLSA framework defines compliance levels for this
  • SBOM -- produce a Software Bill of Materials so you know exactly what is in the image when the next zero-day lands

SLSA explicitly frames itself as "a check-list of standards and controls to prevent tampering, improve integrity, and secure packages and infrastructure", which is the problem shape.

Why It Matters Here

Every major incident class of the last few years has touched the supply chain: typosquatting in package registries, malicious maintainers, build-system compromises, unsigned images, forgotten base-image CVEs. You cannot fully eliminate these, but you can dramatically reduce both likelihood and blast radius with a handful of disciplined controls.

Image hardening addresses "if an attacker lands in this container, what can they do?" The answer should be "almost nothing".

Supply-chain scanning addresses "can we trust what is running?" The answer should be a short, auditable chain of custody from source to signature to cluster verification.

Concrete Example

A service that serves HTTP on port 8080 from Python 3.12. Two shapes of images.

Soft image:

  • FROM python:3.12 (full Debian, 1 GB, package manager, shell, compilers, curl, wget, git)
  • copy the whole repo in
  • run as root
  • no signing, tag latest
  • scanned "sometime" before deploy
  • no SBOM

Hardened image:

  • FROM gcr.io/distroless/python3-debian12@sha256:... (pinned digest, ~50 MB, no shell, no package manager)
  • multi-stage build: dependencies installed in a builder stage, only the app + venv copied into the final image
  • non-root user, read-only root filesystem, dropped capabilities
  • image signed with cosign, signature stored in the registry
  • CI pipeline: Trivy/Grype scans on every build; build fails on critical CVEs; SBOM emitted and stored
  • cluster admission controller only runs images with a valid signature from this org
  • SLSA provenance attestation attached to the image

If an attacker achieves RCE in the Python process, they get no shell, no package manager, no writable root FS, and limited caps. If someone tries to deploy an unsigned image, the cluster refuses.

Common Confusion / Misconception

"Alpine is secure because it is small." Size is an indicator, not a guarantee. A small image with old libraries is still vulnerable. Hardening is about what is there, not how many MB it weighs. Alpine also ships musl libc, which occasionally changes behavior in ways that surprise code expecting glibc.

"We scan in CI, so we are safe." Scan coverage decays. Between build and deploy, new CVEs are published. Between deploy and next build, the image keeps running for months. Production needs scanning at rest (registry scanning + admission controller re-validation), not only at build.

"Signing verifies that the image is good." It verifies "this image came from our pipeline and has not been tampered with". Those are different claims. You still need scanning, provenance, and review for the "good" part. The Sigstore/Rekor transparency log gives you non-repudiation of the signature, not correctness of the code.

"Minimal base images are a silver bullet." If your app bundles a vulnerable library, a distroless base does not save you. SBOM + dependency scanning + patch cadence is the complement. Most post-Log4Shell incident response work was about finding the vulnerable library in deployed images; an SBOM you emit at build time turns that from archaeology into a query.

"SLSA Level 4 is the goal." SLSA levels are staircase targets, not a grade. For most organizations, Level 2 (hosted build, provenance attestation signed by the platform) is a realistic and large improvement over Level 0. Do not let "we'll do L4 later" block shipping L2 today. The SLSA framework explicitly frames itself as "a check-list of standards and controls to prevent tampering, improve integrity, and secure packages and infrastructure".

"Admission control is optional." Without it, signing is theatre. If the cluster will happily run any image pushed to the registry, an attacker who compromises the registry or the build environment does not need a signature. Cosign verify + a policy controller (Kyverno, OPA Gatekeeper, Sigstore Policy Controller) is the enforcement point.

How To Use It

For each container image you ship, answer:

  1. What is the base image, and is the digest pinned?
  2. Is the build reproducible, or at least provenance-attested?
  3. Does the image run as non-root with a read-only root FS?
  4. Is there a scan at build time, at deploy time, and at rest?
  5. Is the image signed, and does the cluster actually verify the signature?
  6. Is there an SBOM, and where does it live?

Check Yourself

  1. Why does a distroless base image reduce post-exploitation options specifically?
  2. What does SLSA add that "we scanned for CVEs" does not?
  3. Why is image signing not a replacement for vulnerability scanning?

Mini Drill or Application

Take a Dockerfile you have shipped. Make a list of every tool available inside the running container (shell, package manager, compilers, curl, etc.). Then rewrite it so that list is as empty as possible while the app still runs. Measure the before/after image size.

See also (external)

Depth Path


Source Backbone

Security and observability require official docs, but these books provide the systems and reliability backbone behind the practices.