Join our Newsletter — 33% off our NHI Course
Home› Guides› Hardened and Minimal Base Images Guide: Distroless, Chainguard-style…
Guide Software & AI Supply Chain

Hardened and Minimal Base Images Guide: Distroless, Chainguard-style and Wolfi

PDF for newsletter subscribers · free to read online

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 27 October 2026 13 min read
On this page

Most container vulnerability findings come from packages the application never uses, inherited from a general-purpose base image. Shells, package managers, compilers and utilities inflate scanner output, slow triage and give an intruder tools to work with after a compromise. Minimal and hardened base images remove that surface: Google's distroless images, Wolfi-based images built with apko, Alpine, and vendor hardened catalogues such as Docker Hardened Images all take different routes to the same goal. This guide compares those options, explains how to migrate with multi-stage builds, how to debug images that have no shell, how to keep them patched and verified, and what to measure. It is for platform engineers, DevSecOps teams and vulnerability managers who own container base images.

Key takeaways

  • Smaller images mean better signal, not immunity. The distroless project says restricting the runtime to what the app needs "improves the signal to noise of scanners" and reduces the provenance burden; your own code and dependencies still need scanning.
  • The C library is the first decision. Distroless (Debian) and Wolfi use glibc; Alpine is built around musl and busybox. Applications with native extensions may behave differently on musl.
  • No shell changes operations. Use exec-form ENTRYPOINT, debug with :debug tags or Kubernetes ephemeral containers, and stop relying on kubectl exec into production.
  • Freshness beats size. A tiny image that is rebuilt rarely accumulates CVEs. Pin by digest, automate digest updates and rebuild on a schedule.
  • Verify what you pull. Distroless images are signed keylessly with cosign and hardened catalogues ship SBOMs, VEX and provenance. Enforce verification at build or admission time.

What "minimal" and "hardened" actually mean

  • Distroless: in the project's words, images that "contain only your application and its runtime dependencies" with no package managers, shells or other programs. The smallest, gcr.io/distroless/static-debian13, is about 2 MiB according to the project README, against about 5 MiB for alpine and 124 MiB for debian.
  • Wolfi and apko: Wolfi is a Linux "(un)distribution" designed for containers, with no kernel of its own, glibc support, granular packages, a build-time SBOM for every package and a focus on the latest upstream releases. apko builds OCI images declaratively from apk packages, is reproducible by default and emits an SBOM. Chainguard sponsors Wolfi and uses it to build its curated minimal images; the Wolfi README warns that Wolfi and Alpine packages are not compatible and must not be mixed.
  • Alpine: a small general-purpose distribution "built around musl libc and busybox". The Alpine project states a container needs no more than 8 MB and that all userland binaries are compiled as position independent executables with stack smashing protection. It still includes a shell and the apk package manager.
  • Vendor hardened images: catalogues that rebuild common runtimes with a reduced footprint, non-root defaults and supply chain metadata. Docker's documentation describes Docker Hardened Images as built on Alpine and Debian with glibc and musl variants, running as non-root by default, with signed SBOMs, VEX statements and SLSA Build Level 3 provenance, and with core features free under Apache 2.0. Paid tiers add FIPS and STIG variants and a remediation SLA, per the same page.
  • scratch: the empty base. Suitable for fully static binaries (for example Go with CGO_ENABLED=0), but you must add CA certificates, time zone data and a non-root user yourself. distroless/static exists to provide exactly those pieces.

Comparing the options

OptionlibcShell and package managerSupply chain metadataBest fitMain trade-off
Full distro (debian, ubuntu)glibcYesDistribution signing; SBOM from your scannerBuild stages, legacy appsLarge package count and scanner noise
Slim variants (debian-slim)glibcYesAs aboveQuick win with no code changeStill a full userland
Alpinemuslbusybox shell, apkSigned apk repositoriesSmall images where musl is testedmusl differences for native modules and some DNS or locale behaviour
Distroless (Debian 13)glibc (none in static)No (busybox only in :debug)Keyless cosign signaturesGo, Java, Node.js, Python, Rust runtimesFixed runtime set; customisation via Bazel rules_distroless
Wolfi and apko built imagesglibcOptional; runtime images can omit bothBuild-time SBOMs, reproducible buildsTeams that want to compose their own minimal imagesWolfi packages track latest versions, so plan for frequent change
Vendor hardened catalogueDepends on vendorSeparate dev and runtime variantsSigned SBOM, VEX, provenance (per vendor docs)Organisations wanting a supported catalogue and SLADependence on the vendor's rebuild cadence and terms
scratchNoneNoOnly what you addStatic binariesYou maintain certificates, users and time zone data

Choosing a base image

  • Static binary (Go, Rust with musl target): distroless/static or scratch. Prefer distroless static over scratch unless you have a reason to manage CA bundles and /etc/passwd yourself.
  • Dynamically linked native code (C, C++, Rust with glibc): distroless/cc or a Wolfi-based glibc image.
  • Interpreted or managed runtimes: the matching distroless runtime (for example java21-debian13, nodejs24-debian13, python3-debian13) or a hardened runtime image. Check native dependencies (Python wheels, Node.js add-ons) against the image's libc and library set.
  • Applications that genuinely need a shell at runtime: a hardened image with a shell, or Alpine, then remove that need over time. Entrypoint scripts are the usual reason, and can often be replaced with configuration or a small init binary.
  • Small organisations: start with distroless or a free hardened catalogue and Renovate or Dependabot digest updates; avoid building your own distribution.
  • Large organisations: publish a small set of approved "golden" base images to an internal registry, built with apko or Bazel, signed by your own pipeline, and block anything else at admission. See the Container Registry Security Guide.

Migrating with multi-stage builds

  1. Inventory current bases. List every FROM line across repositories and registry images, with the scanner finding count for each base. That is your baseline for the "CVEs removed" metric.
  2. Split build and runtime. Keep compilers and package managers in a builder stage and copy only the artefact into the runtime stage. The distroless README notes multi-stage builds need Docker 17.05 or later.
  3. Use exec form for entrypoints. Distroless images have no shell, so ENTRYPOINT ["myapp"] works and shell-form ENTRYPOINT "myapp" does not. The static, base and cc images default to an empty entrypoint, so CMD must also be exec form.
  4. Run as non-root. Use the nonroot tags of distroless images, the non-root default of hardened images, or an explicit USER. Pair this with runAsNonRoot: true and readOnlyRootFilesystem: true in Kubernetes.
  5. Pin the distribution and the digest. The distroless README advises referencing the Debian suffix explicitly because an unsuffixed tag will move to a newer Debian. Docker's build best practices recommend pinning to a digest (FROM image:tag@sha256:...) for supply chain integrity and using automation to update digests on a schedule.
  6. Test in a pilot service. Run functional and load tests, check TLS (CA bundle present), time zone handling, locale, and DNS resolution, and confirm health checks do not call a shell (for example a HEALTHCHECK CMD curl will fail without curl).
  7. Roll out by service tier and keep the previous image digest available so a deployment can be rolled back by digest without rebuilding.

Building your own minimal images

Pulling a public minimal image is the fastest route, but larger estates often need their own internal bases with corporate CA certificates, specific runtime versions or approved libraries. Two declarative approaches avoid hand-written Dockerfiles that slowly regrow a full userland:

  • apko with Wolfi packages: an apko YAML file lists repositories, packages, users and the entrypoint, and apko assembles the image directly from apk packages with no shell steps. The project describes builds as fully reproducible by default and generates an SBOM for each image, which simplifies proving that two builds are the same and that the SBOM matches the bytes.
  • Bazel with rules_oci and rules_distroless: the distroless project itself is built with Bazel, and points to rules_oci for container images and rules_distroless for adding Debian packages, CA certificates and non-root users. This suits organisations that already use Bazel for application builds.
  • Dockerfile from scratch: workable for static binaries, but keep the file small: copy the binary, certificates and a passwd entry, set USER, and nothing else.
RuntimeTypical minimal baseWatch for
Godistroless/static or scratchBuild with CGO_ENABLED=0 or the binary will need a libc; include CA certificates for outbound TLS
Javadistroless/java21-debian13 or a hardened JRE imageDistroless supports only the current Debian LTS Java; JVM options must go in exec-form arguments or environment variables
Node.jsdistroless/nodejs24-debian13Only even-numbered current, active or LTS releases are supported; native add-ons must be built against glibc
Pythondistroless/python3-debian13 or a hardened Python imageCopy a prepared virtual environment or site-packages from the builder; wheels built on musl will not load on glibc and vice versa
Rust and C or C++distroless/ccConfirm the runtime library set covers libgcc and any linked libraries; ldd is not present, so check linkage in the builder

Whichever route you choose, sign internal bases in your own pipeline and publish their SBOMs next to them, so downstream teams can verify a base the same way they verify a public one.

Debugging images without a shell

  • Debug tags: each distroless image set has a :debug (or debug-nonroot) variant with a busybox shell. Use it in development, never as the production tag.
  • Ephemeral containers: the Kubernetes documentation describes kubectl debug adding an ephemeral container to a running Pod, and names distroless images as a case where kubectl exec is insufficient. The --target flag places the debug container in the target container's process namespace, and it must be supported by the container runtime.
  • Debug a copy: kubectl debug --copy-to creates a copy of the Pod with a different image, which avoids touching the production Pod.
  • Control debugging: ephemeral containers are a powerful capability. Restrict the pods/ephemeralcontainers subresource in RBAC to on-call roles and alert on its use. See the Kubernetes RBAC Guide.

Keeping minimal images patched and verified

  • Rebuild often: Docker's best practices advise rebuilding images regularly with updated dependencies and using --pull to fetch the latest base. Distroless tracks Debian and opens automated pull requests when Debian packages update.
  • Know the support window: the distroless support policy sets end of life for Debian 13 images at Debian 14 release plus one year for static, base and cc, and plus three months for Java, Node.js and Python images. Track this as you would any operating system lifecycle.
  • Verify signatures: the distroless README states all images are signed by cosign with keyless signatures, verifiable against the issuer https://accounts.google.com and the identity [email protected]. Enforce verification for every base in CI or at admission. See the Kubernetes Admission Control Guide.
  • Use SBOM and VEX: ingest the image SBOM rather than relying solely on scanner package detection, which can miss packages in images without a package database, and use vendor VEX statements to suppress non-exploitable findings with evidence. See the SBOM Guide and the VEX Guide.
  • Check vulnerability data sources: make sure your scanner supports the distribution's advisory feed (Debian, Alpine secdb, Wolfi advisories) or OSV, otherwise findings will be missing or wrong.

Where identity fits

Minimal images remove tools an attacker would use to harvest credentials, but they do not remove the credentials. A distroless container still receives a mounted service account token, cloud workload identity and environment variables. Keep secrets out of image layers (the builder stage is a common leak point when files are copied wholesale), set automountServiceAccountToken: false where the workload does not call the Kubernetes API, and treat registry pull and push credentials as privileged non-human identities. See the Secrets in Container Images and Build Artefacts Guide and the Docker Hub Tokens Security Guide.

Detection and measurement

Minimal images change what you can detect inside the container: no shell means any shell process in a production container is a strong signal. Monitor:

  • Process execution of sh, bash or busybox in containers built from shell-less bases (runtime security tools or audit rules).
  • Deployments referencing tags rather than digests, or bases outside the approved list.
  • Use of kubectl debug and ephemeral containers in the Kubernetes audit log.
  • Images failing signature verification at admission.
MetricHow to measureDirection
Share of production workloads on approved minimal basesRegistry or cluster inventoryUp
Median OS-package findings per imageScanner results grouped by baseDown
Base image age (days since base digest was published)Compare deployed digest to latestDown, for example under 30 days
Images deployed by digest with verified signaturesAdmission controller logsUp, towards 100%
Workloads running as rootPod security reportsDown

Common failure patterns

  • Shipping the builder: a single-stage Dockerfile on a "minimal" base that then installs compilers and package caches defeats the purpose.
  • Using debug tags in production: a :debug image reintroduces a shell, often because someone needed it once during an incident.
  • Pinning forever: digest pinning without automated updates freezes CVEs in place. Pin and update, never just pin.
  • Mixing ecosystems: adding Alpine packages to a Wolfi image, or copying glibc binaries into Alpine. The Wolfi project says mixing packages with other distributions is unsupported and can create security problems.
  • Trusting scanner silence: a scanner that cannot identify the distribution may report zero findings. Validate scanner coverage on each base before celebrating.
  • Breaking health checks and entrypoints: shell-form commands and curl-based health checks fail silently in testing environments that still use the old base.

Framework mapping

PracticeNIST SP 800-53 Rev. 5NIST CSF 2.0MITRE ATT&CK risk reduced
Remove unneeded packages and shellsCM-7 Least FunctionalityPR.PS-01T1610 Deploy Container (less post-compromise tooling)
Approved base image baselineCM-2, CM-6PR.PS-01T1525 Implant Internal Image
Rebuild and patch on a schedule; track end of lifeSA-22, RA-5PR.PS-02, ID.AM-08Not technique specific
Verify signatures and provenanceCM-14, SR-4, SI-7PR.PS-01T1195.002 Compromise Software Supply Chain
Non-root, read-only runtimeAC-6PR.PS-01T1611 Escape to Host

Practitioner checklist

  • Inventory every base image and record finding counts before migration.
  • Adopt multi-stage builds so only artefacts reach the runtime image.
  • Choose the base by libc and runtime: distroless or Wolfi for glibc, Alpine only where musl is tested.
  • Use exec-form entrypoints and non-root users; set runAsNonRoot and a read-only root filesystem.
  • Pin bases by digest and automate digest updates and rebuilds.
  • Verify base image signatures in CI and at admission.
  • Restrict and audit ephemeral container use; ban :debug tags in production.
  • Track base image end of life and scanner coverage for each distribution.

Standards and references

Related NHI Mgmt Group resources: Container Image Security Guide · NIST SP 800-190 Container Security Guide · n8n Security Guide · Vulnerability Prioritisation Guide

PDF for subscribers

Take this guide with you

Every section, table and checklist in one PDF, with links to the sources and related guides. Subscribe to our weekly NHI & AI Identity Journal and we’ll email you a download link.

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 27 October 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org

PDF Downloads for Newsletter Subscribers

Get the guide

Enter your details and we’ll email you a download link.

The full guide is free to read online. The PDF is a thank you for subscribing.

Fill in all fields marked * and tick the PDF box to continue.