Container images are the package format for Kubernetes workloads. Vulnerable base images, supply chain attacks (SolarWinds-style for containers), and unsigned images have all caused real breaches. Securing the image supply chain closes the gap between "deployed" and "trusted."
Know the difference between image tags (mutable) and digests (immutable). Understand image vulnerability scanning basics (CVE databases, CVSS scoring).
Implement image digest pinning in Deployments. Set up vulnerability scanning in CI/CD (Trivy, Grype). Configure registry policies (Kyverno/Gatekeeper) to reject images from untrusted registries.
Design end-to-end supply chain security: SBOM generation, Sigstore/cosign image signing, Connaisseur or Kyverno signature verification at admission, private registry with image promotion gates.
Container images are the package format for Kubernetes workloads. Vulnerable base images, supply chain attacks (SolarWinds-style for containers), and unsigned images have all caused real breaches. Securing the image supply chain closes the gap between "deployed" and "trusted."
Codecov GCS bucket compromised; malicious bash uploader deployed
Malicious script runs in thousands of CI pipelines; Docker credentials exfiltrated
Backdoored Docker Hub images pushed with same tags as legitimate images
Codecov discloses breach; teams audit CI pipelines and registry credentials
Industry adopts image signing (Sigstore/cosign) and digest-pinned image references
The question this raises
If you cannot trust a container image's tag to be stable and untampered, what cryptographic mechanism ensures you deploy exactly what you built?
Your Deployment references image: myapp:v2.1. A teammate pushes a security patch and re-tags the same image myapp:v2.1. Your running pods use the old image; new pods use the patched one. How do you prevent this ambiguity?
Lesson outline
Tags Are Not Trustworthy
A container image tag is a mutable pointer. nginx:1.25 today is not necessarily nginx:1.25 tomorrow. Attackers who compromise a registry account can push backdoored images under existing tags. Only cryptographic digests (sha256) and signed images with verified provenance provide tamper-evident identity for container images.
Digest pinning
Use for: Reference images by sha256 digest in production Deployments: image: nginx@sha256:abc.... The digest is computed from image content -- any change produces a different digest. Ensures exact reproducibility.
Image signing (cosign)
Use for: Sign image after build with cosign. Store signature in registry. Kyverno or Connaisseur webhook verifies signature at admission time. Unsigned or wrongly-signed images rejected before pod creation.
Private registry with promotion gates
Use for: Images must pass vulnerability scan, signing, and SBOM before being promoted from build registry to production registry. Admission controller enforces: only images from production registry allowed. Public images (Docker Hub) cannot be deployed directly.
Source Code (Git)
| [Build]
v
CI/CD Pipeline:
1. docker build myapp:git-abc1234
2. Trivy scan -> CRITICAL CVEs? -> fail build
3. cosign sign myapp:git-abc1234 (keyless via OIDC)
4. SBOM generated (syft)
5. Push to internal registry: registry.company.com/myapp:v2.1
|
v [Deploy]
Kubernetes Admission:
Kyverno policy: only registry.company.com/* images
cosign verifier: signature must be from ci-sa@company.com
-> passes: pod created with image pinned to digest
-> fails: pod rejected -- no signature from trusted CI identity
Trust chain:
Git commit -> signed build -> signed image -> verified admission
Any break in chain -> blocked before deploymentEvery step from source to runtime has a cryptographic link; broken chain = blocked at admission
Image Security Evolution
Public Docker Hub images with mutable tags in production
“Backdoored image pushed under same tag; next deployment or restart pulls compromised version; no detection”
“Digest-pinned images from private registry; cosign signature verified at admission; Docker Hub images blocked by Kyverno policy”
Zero-tolerance CVE policy blocks all deployments
“Scanner finds ANY critical CVE in base image; CI pipeline fails; team cannot deploy; frustration with security tooling”
“Gate on: CRITICAL CVEs with known exploits AND fix available; accept CRITICAL with no fix + alert; review weekly”
Sigstore/cosign keyless signing in CI
01
1. CI build produces image; pushed to registry: image has sha256 digest
02
2. cosign sign --oidc-issuer=https://accounts.google.com IMAGE_DIGEST
03
3. cosign gets OIDC token from CI provider (GitHub Actions, GCP SA)
04
4. Sigstore Fulcio issues short-lived certificate binding OIDC identity to key
05
5. Signature stored in OCI registry (same repo, .sig tag) + logged to Rekor transparency log
06
6. Admission webhook calls cosign verify: checks signature against Rekor + verifies expected OIDC identity
1. CI build produces image; pushed to registry: image has sha256 digest
2. cosign sign --oidc-issuer=https://accounts.google.com IMAGE_DIGEST
3. cosign gets OIDC token from CI provider (GitHub Actions, GCP SA)
4. Sigstore Fulcio issues short-lived certificate binding OIDC identity to key
5. Signature stored in OCI registry (same repo, .sig tag) + logged to Rekor transparency log
6. Admission webhook calls cosign verify: checks signature against Rekor + verifies expected OIDC identity
1apiVersion: kyverno.io/v12kind: ClusterPolicy3metadata:4name: require-signed-images5spec:6validationFailureAction: Enforce7rules:8- name: check-image-signature9match:10resources:11kinds: [Pod]12verifyImages:13- imageReferences:14- "registry.company.com/*"15attestors:keyless: signature must be from this GitHub Actions workflow OIDC identity16- entries:17- keyless:18subject: "https://github.com/myorg/myrepo/.github/workflows/*"19issuer: "https://token.actions.githubusercontent.com"20# Reject any image NOT from registry.company.comThis policy blocks Docker Hub, public ECR, and any non-internal registry images21- name: require-internal-registry22validate:23message: "Only images from registry.company.com are allowed"24pattern:25spec:26containers:27- image: "registry.company.com/*"
Image supply chain failure modes
Using mutable tag in production deployment
spec:
containers:
- name: app
image: myapp:v2.1 # tag is mutable pointer
imagePullPolicy: IfNotPresent
# If myapp:v2.1 is reassigned to backdoored image:
# running pods: still use old cached image
# NEW pods: pull backdoored image
# No alert, no indication of changespec:
containers:
- name: app
image: registry.company.com/myapp@sha256:abc123def456
imagePullPolicy: IfNotPresent
# sha256 digest is immutable: same digest = same image content
# If attacker pushes new image under v2.1: different digest
# Your deployment still references old (safe) imagePin images to their sha256 digest in production Deployments. The digest is computed from image content -- it cannot be reassigned. Use tags in CI to reference images by semantic version; record the digest post-push and use that in production manifests.
| Control | Threat addressed | Implementation effort | Operational cost | When to implement |
|---|---|---|---|---|
| Digest pinning | Tag reassignment attacks | Low | Low | All production clusters now |
| Vulnerability scanning | Known CVE exploitation | Medium | Medium (triage) | CI/CD pipeline gate |
| Private registry + promotion | Untrusted public images | Medium | Medium | Production environments |
| Image signing (cosign) | Backdoored image substitution | High | Low (automated) | Compliance/high-security envs |
| SBOM generation | Supply chain transparency | High | Low | Regulated industries |
Image tag vs digest
📖 What the exam expects
Tag (e.g., nginx:1.25) is a mutable pointer -- it can be reassigned. Digest (sha256:abc...) is immutable -- it uniquely identifies a specific image content.
Toggle between what certifications teach and what production actually requires
Security architecture questions about container supply chain and DevSecOps questions about CI/CD pipeline security.
Common questions:
Strong answer: Mentions cosign + Sigstore for keyless signing, Trivy in CI/CD gate on CRITICAL severity, and Kyverno admission policy requiring images from trusted registries with valid signatures.
Red flags: Using :latest in production, or thinking a tag is a stable identifier for an image.
Related concepts
Explore topics that connect to this one.
Ready to see how this works in the cloud?
Switch to Career Paths for structured paths (e.g. Developer, DevOps) and provider-specific lessons.
View role-based pathsSign in to track your progress and mark lessons complete.
Questions? Discuss in the community or start a thread below.
Join DiscordSign in to start or join a thread.