Migrate from public base images to hardened container images: a step-by-step guide (2026)

By
Yael Nardi
May 16, 2026

A hardened container image is a minimized base image designed to reduce unnecessary packages and improve supply-chain evidence. Depending on the provider and tier, that evidence may include signatures, SBOMs, provenance attestations, VEX data, and published vulnerability-remediation targets. The base image is the one piece of a containerized application many teams inherit without reviewing closely.

It also influences how much attack surface every higher control, from admission policies to runtime monitors, has to defend.

In many regulated cloud environments, the same migration pattern shows up repeatedly. The hard part is rarely just the FROM-line swap. It is producing the audit table that justifies the swap, and the CI/admission policy that prevents future drift back to public, unsigned, or stale images.

This guide walks a four-phase migration from public base images to hardened equivalents: audit, map, stage, and validate.

Key Takeaways

  • Migrating from public to hardened container images is a four-phase project: audit, map, stage the rollout, and validate. Published vendor examples show large reductions, including Docker's up to 95% attack-surface claim and Chainguard's reported 97.6% average CVE reduction for Chainguard Images.
  • Docker's DHI quickstart example compares dhi.io/python:3.13 with python:3.13 and shows 1 High, 5 Medium, 141 Low, and 2 unspecified CVEs removed, size reduced from 412 MB to 35 MB, and packages reduced from 610 to 80. Docker notes that results may vary as images and CVEs change.
  • The audit phase is where many migrations either gain or lose credibility. Chainguard's 2024 report found that Debian-based community-supported images with Chainguard equivalents had nearly 300 CVEs and nearly 300 components on average, and that simple package updates reduced CVEs by less than 6% in its sample.
  • There is no single right hardened image for every workload. Common production-grade options in 2026 include Docker Hardened Images, Chainguard Containers and Wolfi-based images, Red Hat UBI Micro, Canonical Chiselled Ubuntu, BellSoft Alpaquita, Iron Bank, Google distroless images, and source-built minimal alternatives.
  • The migration only sticks if it is enforced in CI and admission control. Without policy for trusted registries, signatures, SBOM or attestation requirements, digest pinning, and image freshness, future builds can drift back to public or stale images.

1. Auditing Your Current Base Images: Understanding Your CVE Exposure

Auditing your current base images means producing a scored inventory of the base images your organization runs in production. The inventory should cover CVE counts by severity, KEV exposure, days since the last upstream rebuild, signature and SBOM availability, and compliance posture.

The output is a migration backlog prioritized by risk, not by whichever Dockerfile is easiest to edit first. This aligns with the inventory and scanning discipline in NIST SP 800-190 and with Chainguard's 2024 report, which measures CVE exposure by image ecosystem.

Many organizations discover during this step that Dockerfile references, running workload images, and registry contents are tracked in separate systems. The goal is to create one source of truth for the base images actually running in production.

Step 1: Inventory Every Base Image Across Your Registries and Clusters

Run a registry-wide and cluster-wide enumeration, not a single image scan:

  • Across registries: use crane catalog, crane manifest, or gcrane to enumerate image:tag pairs where the registry supports it.
  • Across running clusters: use kubectl get pods --all-namespaces -o jsonpath='{.items[*].spec.containers[*].image}' | tr ' ' '\n' | sort -u.
  • Per image: use docker history --no-trunc <image>, docker inspect <image>, or dive to inspect layers and infer the base distribution where the image metadata supports it.
  • For images that ship an SBOM or attestation: parse the SBOM with a tool such as Syft, or retrieve attached attestations with Cosign where the publisher supports them.

The output is a single table with one row per unique base image. Include columns for production workload count, first-introduced date, last upstream rebuild, registry source, and whether the row is backed by scan/SBOM evidence.

Step 2: Score Each Base Image on the Six-Criteria Audit Rubric

The numbers your audit produces may not be small. Chainguard's 2024 report puts the average Debian-based official image in its sample at nearly 280 CVEs and 273 components, Red Hat application images at 190 CVEs on average excluding will not fix, and popular Iron Bank images at nearly 110 CVEs on average.

Snyk has reported that 44% of Docker image scans by Snyk users had known vulnerabilities for which newer and more secure base images were available.

Score by CVE blast radius: severity multiplied by the number of workloads inheriting the image. Do not score by raw CVE count alone. A High CVE in a base image used by 40 services may deserve more urgent treatment than a Critical finding in a single internal tool.

This rubric is meant to prevent a common prioritization failure: treating a single-service Critical finding as automatically more urgent than a High finding inherited by many production workloads.

Step 3: Produce a Prioritized Migration Backlog

The following table is illustrative. Replace the values with scanner output from your own registries, clusters, and SBOMs before using it in an audit package.

Base Image CVE-blast-radius score KEV count Days stale Signed? SBOM? Compliance gap Migration priority
node:20 380 2 47 No No NIST 4.1.1 Wave 1 (week 1–2)
python:3.13 220 0 12 No No NIST 4.1.1 Wave 2 (week 3–4)
nginx:1.27-alpine 90 0 8 No No NIST 4.1.1 Wave 3 (week 5–6)
gcr.io/distroless/static:nonroot 0 0 5 Yes Yes Already passes Skip / keep


This backlog table is the deliverable that justifies the migration to security and platform-engineering audiences. It is also the baseline you measure against after migration.

2. Mapping Public Images to Hardened Equivalents: Finding Your Replacements

Mapping each public base image to a hardened equivalent is a workload-aware decision. The same image can map differently depending on libc requirements, package-manager behavior, FIPS needs, STIG evidence, patch commitments, or available subscription tiers.

Common production-grade options in 2026 include Docker Hardened Images, Chainguard Containers and Wolfi-based images, Red Hat UBI Micro, Canonical Chiselled Ubuntu, BellSoft Alpaquita, Iron Bank, Google distroless images, and source-built minimal alternatives. Compare them across minimization technique, libc, signing and SBOM support, VEX availability, patch commitments, and compliance posture.

Vendor-Neutral Mapping Table

If you currently run Drop-in candidates (production-grade, 2026) Reason
ubuntu:22.04 / ubuntu:24.04 Canonical Chiselled Ubuntu 24.04, dhi.io/ubuntu, source-built minimal Ubuntu Same userspace + LTS security backports + minimization
debian:12-slim dhi.io/debian, Wolfi (Chainguard public), source-built minimal Debian Drop-in for glibc workloads with debian-style package layout
alpine:3.20 dhi.io/alpine, Wolfi (Chainguard public), source-built minimal Alpine musl-compatible; Wolfi switches you to glibc + apk if you want
node:20, node:20-alpine dhi.io/node, cgr.dev/chainguard/node, source-built minimal Node Common migration target; check each vendor's Node image guidance before swapping
python:3.13, python:3.13-slim dhi.io/python, cgr.dev/chainguard/python, gcr.io/distroless/python3-debian12, source-built minimal Python Watch for pip install behavior in shellless variants
openjdk:21, eclipse-temurin:21 BellSoft Alpaquita Liberica JDK, dhi.io/temurin, Chainguard Java, source-built minimal Java LTS Java backports + JVM-tuned minimization
golang:1.24 (build) → gcr.io/distroless/static-debian12 (run) dhi.io/golang → dhi.io/static; Chainguard Go → Chainguard static; source-built minimal Go → source-built minimal static Multi-stage is the canonical Go pattern; keep it
nginx:1.27-alpine dhi.io/nginx, Chainguard nginx, source-built minimal nginx Highest-leverage swap; every gateway pod inherits
redis:7, postgres:16, mongo:7 Vendor-hardened variant if available; otherwise DHI / Chainguard / source-built equivalents Watch for default UID/GID and data-volume permissions
Windows Server Core / Nano Server Microsoft Windows Server Core / Nano Server Official Windows base OS images come from Microsoft Container Registry; custom images layer on top
DoD / FedRAMP-regulated workload Iron Bank (repo1.dso.mil/dsop), Chainguard FIPS variants (700+ variants using NIST-validated cryptographic modules), DHI Select/Enterprise FIPS/STIG Use vendor evidence to support your authorization boundary; image choice alone does not grant FedRAMP authorization

Pick candidates that satisfy your compliance posture first, then optimize for patch commitment, operational fit, and image size.

Docker's December 17, 2025 press release says DHI became free and fully open source under the Apache 2.0 license, with DHI Enterprise available for customization, compliance variants, and SLA-backed updates.

For regulated workloads, compare each vendor's remediation commitments against the FedRAMP vulnerability-management requirements that apply to your authorization boundary and POA&M process.

What Breaks During Migration: The 12 AM Playbook

Risk Class Symptom Root Cause Mitigation
musl ↔ glibc incompatibility Binary segfaults; Error loading shared library Compiled against one libc, run on the other Pick a candidate with the matching libc; do not mix Alpine apks into a Wolfi image
Missing shell at debug time kubectl exec returns OCI runtime exec failed: exec: "sh" Distroless runtime by design Use kubectl debug ephemeral container, cdebug, chainctl images diff, or a temporary -dev rebuild
BusyBox vs. coreutils behavior Shell scripts fail on flag differences Dev variants ship BusyBox; standard utils are stricter Test scripts against the dev-variant build; replace groupadd/useradd with addgroup/adduser
Entrypoint difference from upstream Container starts, app never runs Hardened image set a non-root user or different entrypoint Read the image's spec page; explicitly set USER and ENTRYPOINT in your Dockerfile
Default non-root user App fails to bind port < 1024 or write to /var/log Most hardened images run as a non-root UID Bind to ports ≥ 1024; chown writeable volumes to the hardened-image UID
CA-certificate path differs TLS handshake failures to upstream APIs Distroless variant placed CA bundle at a non-Debian path Use update-ca-certificates in a -dev builder stage and COPY --from=builder /etc/ssl/certs/ca-certificates.crt to the runtime stage
Init / PID 1 reaping Zombie processes accumulate Hardened image is a single binary, not a full init system Use tini as the entrypoint, or pick a variant that ships a minimal init
Custom packages missing command not found for curl, bash, git Hardened runtime intentionally omits these Move into a multi-stage builder (with -dev or upstream image), or add via custom assembly / a private APK repo

These are common migration failure modes to test before canary. CA-certificate path issues are especially easy to misdiagnose because the symptom often looks like an upstream TLS or API outage.

3. Making the Switch: A Safe, Staged Rollout

A safe rollout is a staged pipeline discipline. Pick a low-risk pilot workload, use multi-stage builds to keep upstream tooling out of production, swap one base at a time, pin the new image by digest, run it through dev -> staging -> canary -> blue-green -> 100%, and keep a written rollback plan for every wave.

A practical sequencing rule is to start with application images before attempting to standardize every shared base image. This reduces coordination overhead and lets service owners validate the change in their own CI/CD path.

Pick the Lowest-Risk Pilot Workload First

A workload is a good pilot when it is stateless, runs a single language runtime with few native extensions, has mature canary or blue-green automation, and has a named on-call rotation that owns it.

A workload is a poor pilot when it is stateful, runs sparse cron or batch workloads, lacks automated rollback, or carries a near-term customer-facing SLA risk.

A gateway or API service can be a strong pilot when it is stateless, well-instrumented, and easy to canary. Avoid starting with stateful workloads or sparse test coverage, because early failures can slow adoption across later waves.

Use a Multi-Stage Build to Keep Upstream Tooling Out of Production

# Builder stage uses the upstream image (or vendor's -dev variant); ephemeral
FROM golang:1.24 AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -o /out/server ./cmd/server

# Runtime stage uses the hardened distroless image
FROM <hardened-static-image>:<digest>
COPY --from=builder /out/server /server
USER 65532:65532
ENTRYPOINT ["/server"]

The build-time and runtime images should usually be different. Compilers, package managers, and shell utilities belong in the builder stage unless the workload truly needs them at runtime.

Pin by Digest, Not Only by Tag

FROM nginx:1.27 may pull different bytes over time if the tag is rebuilt. The same is true of hardened-image tags. Pin to an immutable content digest:

# base image: dhi.io/nginx:1.27-alpine
FROM dhi.io/nginx@sha256:<full-digest>  

Renovate can update Docker digests through pull requests, which makes base-image rebuilds visible instead of silently changing behind a mutable tag.

Verify Signature, SBOM, and Provenance Before the Build Runs

Use the verification workflow supported by your chosen vendor. A common Cosign pattern is to verify the image signature and, when attestations are expected, verify the attestation with the correct identity, issuer, and predicate policy before inspecting its contents:

cosign verify \
  --certificate-identity "$EXPECTED_IDENTITY" \
  --certificate-oidc-issuer "$EXPECTED_ISSUER" \
  <hardened-image>@sha256:$PINNED_DIGEST

cosign verify-attestation \
  --certificate-identity "$EXPECTED_IDENTITY" \
  --certificate-oidc-issuer "$EXPECTED_ISSUER" \
  --type "$EXPECTED_ATTESTATION_TYPE" \
  <hardened-image>@sha256:$PINNED_DIGEST

cosign download attestation <hardened-image>@sha256:$PINNED_DIGEST | \
  jq -r '.payload' | base64 -d | jq '.predicate'

Sigstore documents cosign verify-attestation for attestation verification. Treat cosign download attestation as inspection, not proof of trust by itself. Verify provenance and SBOM evidence as a build-pipeline gate when the vendor publishes those attestations.

Stage the Rollout: Dev → Staging → Canary → Blue-Green → 100%

Stage Traffic share Pass criteria Rollback signal
Dev Internal only App boots; smoke test passes; image scan shows < N Critical CVEs Any failure
Staging 0% prod Full integration suite passes; performance regression < 5% on p99 latency Any failure
Canary 1–5% prod 24 h with error rate < pre-migration baseline; no new CVEs introduced Error-rate delta > 0.5%, new Critical CVE introduced, or p99 regression > 10%
Blue-green 100% prod, blue still warm 24 h on green; rollback to blue is one command Any incident in the first 24 h
100% (blue retired) 100% prod 7 days on green, no incidents, scan delta confirmed (post-cutover; rollback now requires CI re-run)

Keep the previous image pinned by digest until the new image has been at 100% production traffic for an agreed observation window.

When to Use AI Migration Agents

Docker's Gordon-assisted DHI migration flow and Chainguard's beta Guardener can help translate Dockerfiles toward hardened-image equivalents, but their output still needs build, test, security, and compliance review. Chainguard documents Guardener sessions as taking from five to more than thirty minutes depending on Dockerfile complexity.

Every AI-assisted Dockerfile should be reviewed, tested, scanned, and digest-pinned before the canary opens.

Update CI/CD Pipelines and Registries

Update GitHub Actions, GitLab CI, Jenkins, or Buildkite to:

  1. Verify the hardened-image signature before docker build where the vendor supports signatures.
  2. Generate or retrieve a fresh SBOM and attach it to the built image.
  3. Scan with at least one supported scanner, and cross-check high-risk images with a second engine.
  4. Fail the build on Critical or unfixed High findings according to your policy.
  5. Push to your registry with digest references captured in deployment metadata.

Where your registry supports it, configure a pull-through cache or mirror for the hardened-image vendor registry. Artifactory, Harbor, ECR, and Google Artifact Registry have registry proxy or remote-cache patterns, but the exact setup and supported upstreams vary.

For workloads that need extra runtime packages and use Minimus, follow the documented Minimus process for requesting a new image type or altered packages. Confirm provenance, support, and SLA terms for any private or customized variant in your Minimus agreement before relying on those terms in an audit package.

4. After the Migration: Validating Your Security Posture and Staying Protected

Validation means proving with evidence that you reduced CVE count, package count, image size, and remediation latency. Then it means enforcing the win in CI and admission control so future builds cannot drift back to public, unsigned, or stale images.

Most teams should not declare victory after the cutover alone. Without policy enforcement, the next rebuild can accidentally reintroduce a public base image or mutable tag.

Measure the Before/After KPIs

KPI Before (python:3.13) After (dhi.io/python:3.13) Delta
CVE count (Critical + High + Medium + Low) 1 H + 5 M + 141 L + 2 unspec 0 / 0 / 0 / 0 -100%
Total package count 610 80 -87%
Image size 412 MB 35 MB -91%
Mean Time to CVE (avg days from disclosure to remediated image in production) 47 d 5 d -89%

Use the Docker quickstart output as an example, and re-run the comparison against the exact tags and platforms in your environment.

For regulated environments, pair this scorecard with scanner output, SBOMs, attestations, image identifiers, scan dates, and POA&M evidence so assessors can trace each claim back to a source artifact.

Enforce in Admission Controllers

Cluster-side policies in Kyverno, OPA Gatekeeper, Connaisseur, Ratify, Portieris, or similar tools can reject pods that do not meet your policy: untrusted registry, missing digest, missing signature, missing attestation, stale scan evidence, or disallowed CVE severity.

Do not copy a placeholder policy into production. For Kyverno, use tested verifyImages rules with explicit static imageReferences, verifyDigest, and the correct attestors for your signing model. For registry allow-lists, use a tested validation policy rather than a pipe-separated string inside a single image pattern.

AWS EKS image-security guidance documents this pattern: use minimal images, SBOMs, attestations, vulnerability scanning, and admission controllers to reject images that do not meet policy.

Automate Base-Image Rebuilds

Without automation, a vendor remediation target does not help production if the new digest never reaches CI. For ordinary Dockerfiles, start with Renovate's built-in Docker support and digest pinning:


{
  "extends": ["config:recommended"],
  "docker": { "enabled": true },
  "regexManagers": [
    {
      "fileMatch": ["(^|/)Dockerfile$"],
      "matchStrings": [
        "FROM\\s+(?<depName>[^@:]+)(:(?<currentValue>[^@\\s]+))?@(?<currentDigest>sha256:[a-f0-9]{64})"
      ],
      "datasourceTemplate": "docker"
    }
  ]
}

After every base-image bump, rebuild, scan, sign, attest, canary, and roll out through the same gates as the initial migration.

Map Base-Image Controls to Compliance Evidence

Framework Control Base-image evidence
NIST SP 800-190 §4.1.1 Image vulnerabilities Image scan report and SBOM/package inventory attached; attestation verified with cosign verify-attestation where supported
NIST SP 800-190 §4.1.2 Image configuration defects Image configuration evidence shows non-root execution, minimized tooling, and no unnecessary package manager in the runtime image
FedRAMP RA-5 Vulnerability Scanning SLA-backed Critical/High remediation can help meet FedRAMP vulnerability-management windows when paired with rebuild, scan, and redeploy automation
FedRAMP CM-6 Configuration STIG-ready or STIG-hardened variant in use; configuration baseline validated against the applicable benchmark or 3PAO-approved hardening profile
FIPS 140-3 Module validation FIPS-validated cryptographic module in use, with the exact CMVP certificate matched to the selected image and FIPS standard
DISA STIG Applicable DISA STIG or vendor GPOS SRG profile STIG-ready or STIG-hardened image variant plus OpenSCAP results for the relevant profile
CIS Docker Benchmark v1.6 §4.1–§4.6 (Image build) Single-purpose, USER directive, no secrets, content trust, COPY > ADD, hadolint pass
CISA KEV KEV catalog Audit table from §1 shows zero KEV CVEs in any production image

Hardened images move you from unbounded CVE firefighting to a smaller, evidence-backed queue. A new CVE alert becomes a workflow: check the SBOM, review VEX or advisory data where available, confirm whether the image is affected, and track the vendor's remediation target.

MITRE ATT&CK T1611 describes container escape-to-host techniques, and its mitigations include removing unnecessary tools and software from containers. Images without shells, package managers, and compilers reduce the tooling available after compromise, but they do not eliminate runtime escape risk.

A hardened base-image migration reduces build-time attack surface and improves audit evidence. It does not replace runtime threat detection, network policy, secrets management, or host/node protection. Treat the hardened base image as the foundation, not the entire stack. Treat admission control and CI policy as the mechanisms that keep the migration from drifting back to public, unsigned, or stale images.

How Minimus Approaches the Migration

Minimus publishes remediation targets in its Trust Center: KEV active exploits within 1 calendar day after an upstream fix is available, Critical/High vulnerabilities within 2 calendar days after an upstream fix is available, and Medium/Low vulnerabilities within 14 calendar days after an upstream fix is available. Minimus also states that new upstream version releases are incorporated into Minimus images within 7 calendar days, subject to exceptions for defects, breaking changes, or validation needs.

Evaluate compatibility per image family, libc, package manager, UID/GID, and entrypoint before treating a replacement as drop-in. Validate scanner output in your pipeline with the exact tools you rely on, such as Trivy, Grype, Snyk, Docker Scout, AWS Inspector, or Anchore.

For workloads that need extra runtime packages, Minimus documents a process to request a new image type or altered packages. Confirm provenance, support, and SLA terms for any private or customized variant in your Minimus agreement. Use the Minimus catalog or Image Gallery if your account provides access, but do not treat private catalog availability as a public claim unless you can cite it.

FAQ: Migrating to Hardened Container Images

How long does it take to migrate from public to hardened container images?

Timelines vary by test coverage, compliance scope, native dependencies, and rollout automation. A low-risk single service can often be migrated in days, while a fleet migration should be planned in waves that include audit, mapping, staged rollout, and post-migration policy enforcement.

Is hardening the same as patching?

No. Hardening is the architectural choice to ship only the components your workload needs and to preserve supply-chain evidence such as signatures, SBOMs, and provenance where available. Patching is the operational cadence with which you rebuild and redeploy after vulnerabilities are fixed upstream. Remediation targets vary by vendor, severity, subscription tier, and upstream fix availability.

What are the options for hardened container images in 2026?

Common options in 2026 include Docker Hardened Images, Chainguard Containers and Wolfi-based images, Red Hat UBI Micro, Canonical Chiselled Ubuntu, BellSoft Alpaquita, Iron Bank, Google distroless images, and source-built minimal alternatives. They differ on minimization technique, libc, signing/SBOM/VEX support, remediation commitments, and compliance posture.

Is there any reason not to migrate to a hardened container image?

There are valid reasons to delay a migration. A workload may depend on a shell, package manager, or interactive tool at runtime, such as a CI runner image, a developer sandbox, or software that expects to install packages at startup. A second reason is lack of automation: if you cannot bump digests, rebuild, scan, and redeploy reliably, a vendor remediation target will not reach production.

How do I find the base image of an existing Docker image?

Start with docker history --no-trunc <image> or a layer-inspection tool such as dive to understand the image layers. Then cross-check docker inspect labels/config, SBOM or provenance metadata, and publisher documentation. docker inspect can expose useful clues, but it usually cannot reliably identify the original base image by itself.

Can I roll back if a hardened image breaks production?

Yes, if you keep the previous image pinned by digest and available until the new image has passed its observation window. The rollback may be a kubectl rollout undo deployment/<service> or the equivalent in your deployment tool. Blue-green and canary patterns are useful because the previous public-image build remains available while the hardened-image build proves itself in production.

Migrating from public to hardened container images is one project with four phases: audit, map, stage, and validate. Run the audit table, build the mapping table, ship the staged rollout, and enforce the result in CI and admission control. The next CVE should become a triage workflow, not a production surprise.

Yael Nardi
CBO
Sign up for minimus

Avoid over 97% of container CVEs

Access hundreds of hardened images, secure Helm charts, the Minimus custom image builder, and more.