SBOMs, SPDX/CycloneDX, in-toto Attestations, SLSA Provenance, Signatures, and Verification Workflows: Concepts, Architecture, and Mental Model
Attach and verify supply-chain evidence against immutable image digests by separating SBOM inventory, provenance claims, cryptographic signatures, registry referrers, and policy decisions.
Learning objectives
- Explain the difference between an SBOM, provenance attestation, cryptographic signature, registry referrer, and policy decision.
- Bind every claim to an immutable image digest and platform rather than a mutable tag.
- Read BuildKit attestation metadata without assuming that generated evidence is automatically trustworthy.
- Identify the trust boundary between the builder, registry, signer, verifier, and deployment decision.
- Recognize current format/version realities: BuildKit SBOMs are SPDX-based, provenance can use SLSA v0.2 or v1, and Engine 29 no longer ships Docker Content Trust commands.
1. The practical problem: “we have an SBOM” is not yet a trust decision
Chapter 29 bound vulnerability results to a digest. Chapter 30 adds the evidence needed to answer different questions: what software is in these bytes, how were these bytes produced, who is asserting something about them, and did a verifier accept those assertions under an explicit policy? Those are separate questions. A package list does not prove build integrity. Provenance does not prove the artifact is vulnerability-free. A signature proves only that a key or identity signed a particular payload; it says nothing useful until the verifier knows what identity was expected and what was signed.
A mutable tag such as demo:release is useful for
discovery, not for evidence identity. Resolve it to a digest, record
that digest, and verify every downstream object against it.
2. Mental model: subject → evidence → verifier → policy
flowchart TD
A[Source + build inputs] --> B[Builder identity and build process]
B --> C[Immutable image digest]
C --> D[SBOM attestation: what is inside]
C --> E[Provenance attestation: how it was built]
C --> F[Signature: who vouches for this subject]
D --> G[OCI registry/referrer storage]
E --> G
F --> G
G --> H[Verifier checks subject + identity + policy]
H --> I[Promote / deploy / reject]
The build starts with source, Dockerfile, base images, build parameters, and a builder. BuildKit produces an image whose digest identifies the manifest or index. It may also generate attestations. An SBOM describes components. Provenance describes build facts and materials. A signature adds cryptographic evidence from a signing key or workload identity. Registries can store associated artifacts and expose them through OCI-compatible relationships. A verifier then checks subject digest, evidence syntax, cryptographic identity, and organization policy before making a promotion or deployment decision.
Notice the arrows: the verifier does not ask whether “a signature exists.” It asks whether a signature from an expected identity covers the exact subject digest, whether required attestations are attached to that subject, and whether their claims match policy.
3. Define the state before touching it
| State | Evidence to record | Why it matters |
|---|---|---|
| Subject image | repository + immutable digest + platform | All later evidence must name the same subject. |
| SBOM | format, document identity, packages/files, generator | Inventory accuracy and format are independent of cryptographic trust. |
| Provenance | predicate type/version, build type, builder ID, materials, parameters | Explains how the subject was produced and what the builder claims. |
| Attestation object | attestation/referrer digest and media type | Lets you distinguish evidence objects from the application image itself. |
| Signature | signature/bundle, key or certificate identity, algorithm | Binds a cryptographic assertion to the subject/payload. |
| Transparency evidence | log/bundle inclusion where used | Adds public/auditable evidence in keyless Sigstore flows; not required by the local-key lab. |
| Policy | expected subject, signer, predicate, builder/material constraints | Transforms raw evidence into an explicit allow/reject decision. |
| Verification | tool/version, timestamp, result | Verification is an action with software and time context, not a permanent property. |
4. SBOM: inventory evidence, not authenticity
Docker BuildKit can generate an SBOM attestation during the build
with --sbom=true or --attest type=sbom.
Docker documents that the generated attestation is JSON-encoded SPDX
wrapped as an in-toto predicate. The default scanner plugin is
BuildKit’s Syft-based generator. This is valuable because build-time
scanning can describe artifacts used in build stages that may not
appear in the final filesystem.
SPDX and CycloneDX are both widely used machine-readable BOM standards, but they are not interchangeable labels. The current SPDX specification is 3.0.1; CycloneDX’s current specification is 1.7. BuildKit’s native SBOM attestation path is SPDX-oriented. If your consumer requires CycloneDX, generate or convert it with a tool that explicitly supports that output, and record the generator/version rather than pretending the BuildKit SBOM magically changed format.
5. Provenance: build claims and materials
BuildKit provenance records facts such as build timestamps,
parameters, environment, VCS metadata, source details, and materials
consumed by the build. Buildx creates minimal provenance by default
for build results that can retain attestations. You can request
mode=max for richer evidence and explicitly request
SLSA provenance v1 with version=v1. As of this chapter
baseline, Docker documents v0.2 as the default schema while also
supporting v1.
More provenance is not always better. Maximum mode can expose build arguments or source details that you would not publish to an untrusted registry. The design question is not “min or max?” in isolation; it is “which claims does the verifier need, and which details are safe to disclose in this evidence channel?”
# Read-only inspection of a registry image with attestations
# Replace IMAGE with an actual immutable or tagged registry reference.
docker buildx imagetools inspect "$IMAGE" --format '{{json .Provenance}}'
docker buildx imagetools inspect "$IMAGE" --format '{{json .SBOM}}'
6. Signatures: identity plus subject binding
Signing answers a different question. A signer uses a private key, hardware-backed key, KMS key, or keyless workload identity to produce cryptographic evidence. Verification succeeds only when the verifier trusts the corresponding public key or certificate chain and checks the intended identity. For local education we use a throwaway Cosign keypair because it is deterministic, free, and does not require OIDC or a public transparency service.
Cosign itself warns to sign image digests rather than tags. That
matters because signing a tag creates a time-of-check race: the tag
can move between resolution and signing. The lab therefore resolves
localhost:5005/dca30/app:1 to a digest first, forms
localhost:5005/dca30/app@sha256:..., and signs that
immutable reference.
7. OCI subjects and referrers
OCI Image/Distribution 1.1 standardized a
subject relationship and a Referrers API so registries
and tools can discover signatures, attestations, and other artifacts
associated with a digest. Conceptually, the application image is the
subject; an SBOM, provenance statement, or signature is a separate
object that refers to that subject. That avoids stuffing every
evidence type into the runtime image filesystem.
Registry behavior still matters. A registry may implement OCI 1.1 referrers directly, use a compatibility fallback, impose media-type limits, or garbage-collect unreferenced artifacts differently. Evidence portability therefore includes a registry capability test, not just a tool capability test.
8. Engine 29 compatibility baseline
| Component / behavior | 2026-09-22 lesson baseline | Operational consequence |
|---|---|---|
| Docker Engine / CLI | 29.8.1 current release |
Docker Content Trust commands were removed from the CLI in
Engine 29. Do not copy old
docker trust tutorials into current workflows.
|
| Buildx | 0.37.1 current release | Supports current BuildKit attestation and imagetools workflows; record the learner’s actual version. |
| BuildKit | 0.33.0 current upstream | Current Dockerfile frontend is 1.27.0; builder-packaged versions can differ. |
| Compose | 5.5.1 current release | Not required for the attestation mechanics; record it in the checkpoint preflight for environment identity. |
| containerd / runc | 2.3.5 / 1.5.1 current upstream | Runtime component versions are evidence context, not attestation identities. |
| Cosign | 3.1.3 pinned lab tool | Current release fixes a legacy-bundle verification bypass; use current verification behavior. |
| OCI Image/Distribution | 1.1 artifact/referrer model; image-spec 1.1.1 available | Subject/referrer relationships are registry metadata, not files inside the app image. |
9. Chapter path
Lesson 2 builds and inspects evidence. Lesson 3 makes format, identity, storage, and policy choices explicit. Lesson 4 deliberately breaks subject/identity assumptions and diagnoses the failure. Lesson 5 produces one auditable packet in which the image digest, SBOM, provenance, signature, and policy verdict all agree.
Knowledge check
Why is an SBOM alone insufficient to prove an image is trustworthy?
An SBOM is inventory evidence. It does not authenticate who generated it, prove the build process was authorized, or establish that policy permits the subject.
What should be the common join key across SBOM, provenance, signature, scan result, and deployment record?
The immutable subject image digest, plus platform when the reference is a multi-platform index.
Does provenance prove an image has no vulnerabilities?
No. Provenance describes how an artifact was produced. Vulnerability status requires separate inventory/advisory analysis.
Why does Cosign documentation recommend signing a digest rather than a tag?
A tag is mutable. Digest signing avoids races and proves exactly which manifest or index the signature covers.
An attestation was generated by BuildKit and attached to a registry image. Is it automatically trusted?
No. Generation and storage do not authenticate the builder. Verification must check subject binding and the trusted signer/builder identity or another explicit trust mechanism.
Official references and version notes
2026-09-22. Docker Engine 29.8.1, Buildx 0.37.1, BuildKit 0.33.0, Compose 5.5.1, containerd 2.3.5, runc 1.5.1, and Cosign 3.1.3 were current upstream references when this lesson was authored. Your installed Docker Desktop/Engine bundle can package different component versions; record actual command output.
- Docker Docs — Build attestations — current BuildKit SBOM/provenance model and image-store requirements.
-
Docker Docs — SBOM attestations
— SPDX/in-toto output and
imagetools inspectworkflow. -
Docker Docs — Provenance attestations
—
mode=min|maxand optional SLSA provenance v1. - Docker Docs — buildx imagetools inspect — registry manifest, SBOM, and provenance inspection.
- Docker Engine 29 release notes — Engine 29 compatibility baseline and removal of Docker Content Trust from the CLI.
-
OCI — Image and Distribution Specifications 1.1
— artifact
subject,artifactType, and Referrers API. - SPDX Specification 3.0.1 — current SPDX specification reference.
- CycloneDX Specification Overview — current CycloneDX 1.7 object model and media types.
- SLSA Specification 1.2 — current SLSA model and provenance guidance.
- Sigstore Cosign v3.1.3 — pinned local signing/verifying tool used as the 2026-09-22 lesson baseline.
-
Docker Official Image — registry
— disposable local registry; lesson baseline pins
registry:3.1.1.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.