Supply Chain Best Practices
This is a practical checklist for hardening the container supply chain from build to deploy, grouped so you can adopt it in stages.
How to Use This List
Work top to bottom, since each group builds on the previous one.
Groups A and B are table stakes for any team; groups C through E are where regulated and multi-tenant environments invest most.
Treat each bold item as a control you can point to during an audit or incident review.
Adopt incrementally: pin and mirror first, then sign and gate, then attest and monitor.
A - Sources and Base Images
Mirror critical bases internally. Proxy or copy the base images you depend on (Harbor proxy cache, ECR pull-through) so a public-registry outage or deletion cannot block your builds.
Pin base images by digest. Reference base@sha256:... in Dockerfiles so the same build always starts from identical bytes, not a moving tag.
Prefer minimal, non-root bases. Use distroless or slim images and a non-root USER to shrink the attack surface and the CVE count.
Avoid Docker Hub rate limits. Authenticate pulls or mirror bases so anonymous rate limits do not throttle rollouts at the worst time.
Vet new dependencies. Review and pin third-party images and packages before adopting them, guarding against typosquatting and dependency confusion.
Rebuild bases regularly. Refresh and republish your pinned bases on a cadence so patched OS packages reach downstream images instead of aging in place.
B - Tagging and Immutability
Deploy by digest, never by :latest. Pin the image digest in Kubernetes manifests so what you tested is exactly what runs.
Enforce immutable tags at the registry. Enable immutable-tag rules (Harbor, ECR, ACR) so a release tag cannot be silently overwritten.
Tag every build three ways. Carry a git SHA tag for traceability, a semver tag for humans, and rely on the digest for deployment.
Set retention and garbage collection. Pair immutability with lifecycle policies so storage does not grow without bound.
C - Authentication and Access
Separate push from pull identities. CI pushes with a scoped identity; the cluster pulls read-only, so a compromised cluster cannot poison the registry.
Prefer short-lived OIDC tokens. Use workload identity federation for CI push and cloud node identity for cluster pull instead of static passwords.
Scope credentials least-privilege. Limit robot accounts and IAM roles to specific repositories and actions, and to specific branches where possible.
Keep pull secrets in the right namespace. Attach imagePullSecrets to the workload ServiceAccount, and encrypt secrets at rest with RBAC applied.
Rotate and audit credentials. Rotate any static tokens on a schedule and log registry access to detect anomalies.
D - Signing and Verification
Sign every production image. Use cosign (keyless via OIDC preferred) to bind a trusted identity to each image digest.
Verify signatures at deploy. Enforce an admission policy (Kyverno or the Sigstore policy-controller) that rejects unsigned or untrusted images.
Roll out enforcement safely. Start admission policies in audit mode, confirm no legitimate deploys break, then switch to enforce.
Tune webhook failure policy. Scope verification to the right namespaces and monitor the controller so a webhook outage does not block all deploys.
E - Attestations, Scanning, and Response
Generate an SBOM per image. Emit BuildKit --sbom attestations or run Syft, and attach the SBOM to the image digest.
Scan in CI and continuously. Fail builds on unaccepted HIGH/CRITICAL CVEs and rescan published images as new CVEs appear.
Record provenance. Add SLSA provenance attestations (--provenance=true) so you can prove how each image was built.
Keep SBOMs queryable for triage. Store SBOMs so that when a CVE lands you can identify affected images in minutes, not days.
Rebuild on dependency change. Regenerate SBOMs and re-sign whenever inputs change, since attestations are build-time snapshots.
Monitor for drift and anomalies. Alert on unsigned deploys blocked at admission, unexpected pushes, and images running that are not in your registry inventory.
When You Are Done
You should be able to trace any running pod to a signed digest, its SBOM, and its build provenance.
Unsigned or unknown images should be rejected automatically at admission, not caught by review.
A new critical CVE should be answerable with a query against stored SBOMs rather than a manual audit.
If any of those is still manual, that gap is your next highest-leverage investment.
Revisit the list each quarter, since registries, scanners, and signing tools add capabilities that let you retire manual steps.
The goal is a pipeline where trust is verified automatically at every hop, and a human only intervenes on an exception.
FAQs
What is the single most valuable control?
Deploy by digest with immutable tags enforced, so what you tested is exactly what runs and can be rolled back reliably.
Do I need signing if I already scan images?
Yes. Scanning finds known CVEs, but only signing proves the image was not tampered with after build.
Why mirror base images internally?
To stay buildable during public-registry outages, to avoid rate limits, and to control exactly which base bytes enter your pipeline.
How do I start without breaking deploys?
Run admission and scanning gates in audit mode first, fix findings, then enforce once you have confidence.
Does Kubernetes enforce any of this by default?
No. The kubelet and containerd pull and run images; signing verification and image policy require admission controllers you install.
How often should I rescan already-published images?
On a schedule (daily or weekly), because new CVEs are disclosed constantly for packages inside images that have not changed.
Related
- Why the Software Supply Chain Matters
- Tagging & Immutability
- Registry Authentication
- cosign & Image Signing
- SBOM Generation
Stack versions: This page was written for Kubernetes 1.36.2, Docker Engine 29.6.1 (BuildKit default), containerd (CRI runtime on nodes), Helm 3, Compose v2, Argo CD (latest - verify at build), and Gateway API (GA - verify controller support at build).