Skip to main content
RunBook Academy

Git, CI/CD & GitOpsLIII · Container CIContainer CI

The container supply chain — source to registry

Intermediate⏱ ~24 mingitdocker

What you'll learn

  • Trace every step from a Git commit to a registry tag in a container supply chain
  • Identify what each step introduces (trust, content, attestation, risk)
  • Distinguish build provenance from runtime provenance
  • Recognise why digest pinning is the only contract between CI and a registry

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

A container image is not “the thing docker build produced”. It is the output of a chain that begins at a commit, passes through a build step, picks up layers and configuration, is tagged, signed, and pushed to a registry. Every step in that chain either adds trust or introduces risk. The job of container CI is to make the trust explicit and the risk auditable. This lesson walks that chain.

The chain, step by step

Seven steps sit between a commit and a deployable image. They are the same in a GitHub Actions runner, a GitLab runner, or a self-hosted BuildKit cluster:

flowchart LR
    A["Git commit"] --> B["Checkout (CI)"]
    B --> C["Base image pull"]
    C --> D["Layer build (BuildKit)"]
    D --> E["Image assembly"]
    E --> F["Test and scan"]
    F --> G["Tag and push"]
    G --> H["Registry (digest)"]

What each step introduces matters more than the order:

  • Checkout introduces the exact bytes the build runs against. If the runner checks out the wrong ref, every downstream artifact is wrong; the chain of trust begins here.
  • Base image pull introduces the parent. The image you build inherits every package, certificate, and vulnerability of the parent. A CVE in node:20 is a CVE in your image.
  • Build introduces the layers that make up your application: the source code, the dependencies installed, the build cache writes. Build cache is a separate artifact (LIII-02) and a separate risk.
  • Assembly introduces configuration: the working directory, the entrypoint, environment defaults, the user the process runs as.
  • Test and scan introduces attestation: the SBOM (LIII-05), the vulnerability report, the size budget, the behavioural test results.
  • Tag and push introduces the identifier. A tag is mutable; a digest is not. Whether you push by tag, by digest, or both determines what deploys can resolve.
  • Registry introduces immutable storage once the digest exists, and access control on who can pull or reference it.

What each step can introduce

The chain is not just a sequence of transformations. It is a sequence of trust boundaries:

StepIntroducesFailure mode
CheckoutSource bytesWrong ref checked out
Base pullParent imageCVE in parent
BuildApplication layersSupply-chain compromise
AssemblyRuntime configPrivilege escalation
Test/scanAttestationsFalse negative
Tag/pushIdentifierMutable tag overwritten
RegistryStoragePull-time substitution

The two trust boundaries that matter most for the rest of Part LIII are the build step (because it is where most of the compromise surface lives) and the tag/push step (because it is where the digest becomes the contract downstream).

Build provenance versus runtime provenance

The provenance chain starts at the build. Build provenance answers “given this image digest, what build produced it, from what source, on what runner, with what inputs?”. Runtime provenance answers “what is running in production, where did it come from, and was it deployed by something we trust?”. The two halves meet at the attestation: the signed statement that glues the build to the artifact and the artifact to the deployment.

That attestation - whether it is an in-toto/SLSA provenance attestation (LIII-05 and LIII-06), a sigstore signature, or a vendor provenance record - is what makes the chain auditable. Without it, the chain is a sequence of artefacts that happen to share a name.

Production discipline

Five rules that anchor the rest of Part LIII:

  1. Pin everything by digest where it will be referenced by systems. Tags in source-controlled manifests are bugs waiting to happen; digests are the contract.
  2. Record what the build consumed. Base image digest, source commit, dependency lockfile - all of these belong in the build provenance and therefore in the attestation.
  3. Test and scan before the tag is applied. The tag should only land after the tests, scans, and size checks pass. Tagging first and scanning after is how unscanned images end up in production.
  4. Sign at the registry, not in the runner. The runner can be compromised; the registry signature is what downstream verifiers check (LIII-06).
  5. Treat the chain as the unit of trust. A signature on an image whose provenance you cannot reconstruct is a signature on nothing.

Cross-course references

  • Containerisation for Production Sysadmins - Parts I-IV (Docker foundations) cover the runtime side of the chain (container, image, registry, daemon) that this part consumes.
  • Container Security for Production Sysadmins - Parts I-II (image supply chain) cover the threat model; this lesson’s chain is the surface that threat model targets.

Quiz

Knowledge check · 4 questions

  1. Q1. Why is the SHA-256 digest the only safe contract between a CI pipeline and a container registry, when a tag like app:1.4.0 is not?

  2. Q2. A base image pull at the start of a container build introduces the build environment but not any vulnerabilities into the final image.

  3. Q3. Name the two kinds of provenance that together make a container supply chain auditable, and state which one is produced inside the build step.

  4. Q4. Trace a CVE in a third-party base image back to the build chain and identify the missing controls.

    A production image built two months ago is suddenly flagged for CVE-2024-9999 in glibc. The team uses app:1.4.0 in their Helm values (no digest pin), a self-hosted BuildKit runner, and an in-toto attestation generated by the runner. The base image is FROM debian:bookworm-slim.

Passing score: 75%. Answers are checked in this browser.