52.11 SBOM and provenance attestations with buildx
Friends, when a new security bug like Log4Shell comes out, the first question from the boss is: which of our images contain this library? If your images carry an SBOM, you answer in minutes. Today we learn SBOM, the list of everything inside an image, and provenance, the record of how and where it was built.
मित्रांनो, Log4Shell सारखा नवीन security bug आला की boss चा पहिला प्रश्न: आपल्या कोणत्या image मध्ये ही library आहे? तुमच्या image सोबत SBOM असेल तर काही मिनिटांत उत्तर देता येतं. आज SBOM, म्हणजे image मधल्या सगळ्या गोष्टींची यादी, आणि provenance, म्हणजे image कशी आणि कुठे build झाली याची नोंद, शिकू.
दोस्तों, Log4Shell जैसा नया security bug आते ही boss का पहला सवाल: हमारी किन images में यह library है? अगर images के साथ SBOM है तो मिनटों में जवाब मिल जाता है. आज SBOM, यानी image के अंदर की हर चीज़ की सूची, और provenance, यानी image कैसे और कहाँ build हुई इसका रिकॉर्ड, सीखेंगे.
1. Start from a story
In December 2021 Log4Shell hit. Ankit's team at PhonePe had about 300 images in their registry. Nobody knew which ones had log4j-core inside.
They pulled every image and scanned each one by hand for two days. Some images were built from laptops and nobody knew which commit they came from.
After that, Ankit changed the pipeline. Every build now adds --sbom=true and --provenance=mode=max. The registry stores both next to the image.
Next time a library bug came out, one script read the SBOMs of all images and listed the affected ones in eight minutes. Provenance showed the exact commit and pipeline for each. Today we build that habit.
2. What SBOM and provenance are
Step 1: SBOM in one line
Why: Software Bill of Materials.
What: A list of every package in the image: name, version, licence. Formats are SPDX and CycloneDX.
Example 1: Without an SBOM
Type this:
docker run --rm payapi sh -c 'ls /app/lib | head -3'
You will see:
jackson-core-2.17.1.jar
log4j-core-2.17.2.jar
slf4j-api-2.0.13.jar
What it means: You must look inside by hand.
Example 2: Quick SBOM with docker scout
Type this:
docker scout sbom --format list payapi:1.0 | head -4
You will see:
Name Version Type
log4j-core 2.17.2 maven
jackson-core 2.17.1 maven
openssl 3.0.13 deb
What it means: A readable package list.
Example 3: Search it
Type this:
docker scout sbom --format list payapi:1.0 | grep log4j
You will see:
log4j-core 2.17.2 maven
What it means: One command answers the boss.
Step 2: Provenance in one line
Why: Where did this image come from?
What: Provenance is a signed-style record in SLSA format: source repo, commit, builder, build arguments and timing.
Example 4: Build with it
Type this:
docker buildx build --provenance=mode=max -t registry.example.com/payapi:1.0 --push .
You will see:
=> exporting attestation manifest sha256:9f2a...
What it means: Provenance attached.
Example 5: Read it
Type this:
docker buildx imagetools inspect registry.example.com/payapi:1.0 --format '{{json .Provenance.SLSA.invocation.configSource}}'
You will see:
{"entryPoint":"Dockerfile"}
What it means: The Dockerfile used.
Example 6: Source commit
Type this:
docker buildx imagetools inspect registry.example.com/payapi:1.0 --format '{{json .Provenance.SLSA.metadata}}' | grep -o 'vcs:revision[^,]*'
You will see:
vcs:revision":"4e7b1c2
What it means: The commit is recorded.
Step 3: Why both
Why: SBOM answers what, provenance answers how.
What: Security teams and auditors, including banks under RBI rules, ask for both.
Example 7: What
Type this:
printf 'SBOM: what is inside\n'
You will see:
SBOM: what is inside
What it means: Packages and versions.
Example 8: How
Type this:
printf 'Provenance: how and where it was built\n'
You will see:
Provenance: how and where it was built
What it means: Commit, builder, args.
Example 9: Policy check
Type this:
docker scout policy registry.example.com/payapi:1.0 | grep -i 'supply chain'
You will see:
Supply chain attestations compliant
What it means: Both present, policy passes.
3. Create attestations with buildx
Step 4: --sbom=true
Why: BuildKit scans the image and attaches an SPDX SBOM.
What: It needs a docker-container builder and --push or an OCI output.
Example 10: Builder
Type this:
docker buildx create --name att --driver docker-container --use --bootstrap | tail -1
You will see:
att
What it means: Builder ready.
Example 11: Build
Type this:
docker buildx build --sbom=true -t registry.example.com/payapi:1.1 --push . 2>&1 | grep -i sbom
You will see:
=> [linux/amd64] generating sbom using docker.io/docker/buildkit-syft-scanner:stable-1
What it means: Scanner ran inside the build.
Example 12: Read
Type this:
docker buildx imagetools inspect registry.example.com/payapi:1.1 --format '{{json .SBOM.SPDX.packages}}' | grep -o '"name":"log4j-core"'
You will see:
"name":"log4j-core"
What it means: The SBOM lists the jar.
Step 5: Scan build stages too
Why: Stages that are thrown away still matter.
What: Add ARG BUILDKIT_SBOM_SCAN_STAGE=true in a stage to include it, and BUILDKIT_SBOM_SCAN_CONTEXT=true for the context.
Example 13: Mark stage
Type this:
printf 'FROM maven:3.9-eclipse-temurin-21 AS build\nARG BUILDKIT_SBOM_SCAN_STAGE=true\nCOPY . .\nRUN mvn -q package\nFROM eclipse-temurin:21-jre-jammy\nCOPY --from=build /target/app.jar /app.jar\n' > Dockerfile && grep SBOM Dockerfile
You will see:
ARG BUILDKIT_SBOM_SCAN_STAGE=true
What it means: Build stage will be scanned.
Example 14: Build
Type this:
docker buildx build --sbom=true -t registry.example.com/payapi:1.2 --push . 2>&1 | grep -c 'generating sbom'
You will see:
2
What it means: Two SBOM passes.
Example 15: Maven appears
Type this:
docker buildx imagetools inspect registry.example.com/payapi:1.2 --format '{{json .SBOM}}' | grep -o 'maven-core' | head -1
You will see:
maven-core
What it means: Build tools are recorded.
Step 6: --provenance modes
Why: min is the default, max adds more detail.
What: min records basics; max adds build arguments and full step data. Do not pass secrets as args, max would record them.
Example 16: Default
Type this:
docker buildx build -t registry.example.com/web:1.0 --push . 2>&1 | grep attestation
You will see:
=> exporting attestation manifest
What it means: min provenance by default.
Example 17: Max
Type this:
docker buildx build --provenance=mode=max -t registry.example.com/web:1.1 --push . >/dev/null && docker buildx imagetools inspect registry.example.com/web:1.1 --format '{{json .Provenance.SLSA.invocation.parameters.args}}'
You will see:
{"build-arg:APP_ENV":"prod"}
What it means: Build args recorded.
Example 18: Turn off
Type this:
docker buildx build --provenance=false -t registry.example.com/web:dev --push . 2>&1 | grep -c attestation
You will see:
0
What it means: Sometimes needed for old registries.
Step 7: Attestation manifests
Why: How the registry stores them.
What: Attestations are stored in the image index as extra manifests with platform unknown/unknown.
Example 19: Raw index
Type this:
docker buildx imagetools inspect registry.example.com/payapi:1.1 --raw | grep -c 'attestation-manifest'
You will see:
1
What it means: One attestation manifest.
Example 20: Platforms
Type this:
docker buildx imagetools inspect registry.example.com/payapi:1.1 | grep Platform
You will see:
Platform: linux/amd64
Platform: unknown/unknown
What it means: unknown/unknown holds the attestations.
Example 21: Old tools
Type this:
docker pull registry.example.com/payapi:1.1 | tail -1
You will see:
registry.example.com/payapi:1.1
What it means: docker pull ignores attestations and just works.
4. Use the SBOM
Step 8: Export to a file
Why: Keep SBOMs for audits.
What: Write the SBOM with an output, or with docker scout or syft.
Example 22: Local output
Type this:
docker buildx build --sbom=true --output type=local,dest=out . && ls out | grep sbom
You will see:
sbom.spdx.json
What it means: SBOM saved as a file.
Example 23: Count packages
Type this:
jq '.packages | length' out/sbom.spdx.json
You will see:
187
What it means: 187 packages in this image.
Example 24: CycloneDX
Type this:
docker scout sbom --format cyclonedx --output payapi.cdx.json payapi:1.0 && head -c 40 payapi.cdx.json
You will see:
{"bomFormat":"CycloneDX","specVersion":
What it means: The other common format.
Step 9: Find a library across images
Why: The Log4Shell question.
What: Loop over images and grep the SBOM.
Example 25: Loop
Type this:
for i in payapi:1.0 web:1.0 partner:1.0; do docker scout sbom --format list $i | grep -q log4j-core && echo $i; done
You will see:
payapi:1.0
What it means: Only one image is affected.
Example 26: Version
Type this:
docker scout sbom --format list payapi:1.0 | grep log4j-core | awk '{print $2}'
You will see:
2.17.2
What it means: Is it a safe version?
Example 27: CVEs
Type this:
docker scout cves --only-package log4j-core payapi:1.0 | tail -2
You will see:
0C 0H 0M 0L
No vulnerable packages detected
What it means: Safe version confirmed.
Step 10: Scan for vulnerabilities
Why: SBOM plus a CVE database gives a risk list.
What: Docker Scout, Trivy and Grype can read an image or its SBOM.
Example 28: Scout
Type this:
docker scout cves payapi:1.0 | grep -E '^ +[0-9]+C'
You will see:
0C 2H 5M 9L
What it means: Counts by severity.
Example 29: Trivy
Type this:
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy:0.56.2 image --severity HIGH,CRITICAL -q payapi:1.0 | tail -1
You will see:
Total: 2 (HIGH: 2, CRITICAL: 0)
What it means: Same image, second tool.
Example 30: Gate in CI
Type this:
docker scout cves --exit-code --only-severity critical payapi:1.0; echo exit=$?
You will see:
exit=0
What it means: Pipeline fails only on critical.
Step 11: Sign the image
Why: Proof that your pipeline built it.
What: Cosign signs an image digest. Keys here are examples; keep real keys in a secrets manager.
Example 31: Keys
Type this:
cosign generate-key-pair
You will see:
Private key written to cosign.key
Public key written to cosign.pub
What it means: Example keys for practice.
Example 32: Sign
Type this:
cosign sign --key cosign.key registry.example.com/payapi@sha256:9f2a...
You will see:
Pushing signature to: registry.example.com/payapi
What it means: Signature stored next to the image.
Example 33: Verify
Type this:
cosign verify --key cosign.pub registry.example.com/payapi:1.1 | head -1
You will see:
Verification for registry.example.com/payapi:1.1 --
What it means: Servers can refuse unsigned images.
Step 12: Read provenance in an audit
Why: Answer who built what.
What: Look at the builder ID, the commit and the time.
Example 34: Builder
Type this:
docker buildx imagetools inspect registry.example.com/payapi:1.1 --format '{{json .Provenance.SLSA.builder}}'
You will see:
{"id":"https://ci.example.com/job/payapi/212"}
What it means: CI job 212.
Example 35: Time
Type this:
docker buildx imagetools inspect registry.example.com/payapi:1.1 --format '{{.Provenance.SLSA.metadata.buildFinishedOn}}'
You will see:
2026-10-24T09:12:44Z
What it means: Finished 2:42 PM IST.
Example 36: Mismatch alarm
Type this:
[ "$(git rev-parse --short HEAD)" = 4e7b1c2 ] && echo match || echo mismatch
You will see:
match
What it means: Image matches the code in the repo.
5. Common mistakes and how Ankit avoids them
Mistake one: building with the default docker driver and wondering where the SBOM went. Ankit uses a docker-container builder and --push.
Mistake two: passing tokens as build args with mode=max. They end up in provenance. Ankit uses --secret.
Mistake three: generating SBOMs but never reading them. Ankit has a weekly job that scans all SBOMs for new CVEs.
Mistake four: old registries that reject attestation manifests. Ankit tests the registry once and uses --provenance=false only where needed.
Mistake five: signing a tag instead of a digest. Ankit signs the digest so the signature cannot move.
Check yourself
Q1. What does an SBOM list?
Every package and version in the image.
Q2. What does provenance record?
Source, commit, builder and build steps.
Q3. Which flags add them?
--sbom=true and --provenance=mode=max.
Q4. Why sign the digest?
A tag can move; a digest cannot.
Friends, an image without an SBOM is a box without a label. Did you understand? Let us try it once more. Build one image with --sbom=true, export the SBOM and count its packages.
मित्रांनो, SBOM नसलेली image म्हणजे label नसलेला डबा. समजलं का? चला, पुन्हा एकदा करून पाहू. --sbom=true ने एक image build करा, SBOM export करा आणि packages मोजा.
दोस्तों, बिना SBOM की image यानी बिना label का डिब्बा. समझ आया? चलिए, एक बार फिर करके देखते हैं। --sbom=true से एक image build कीजिए, SBOM export कीजिए और packages गिनिए.
Ravindra Bagale's Tip
In interviews, when asked about supply chain security, say these four words in order: SBOM, provenance, scanning, signing. Then give one command for each.
Interview मध्ये supply chain security विचारलं तर हे चार शब्द क्रमाने सांगा: SBOM, provenance, scanning, signing. मग प्रत्येकासाठी एक command सांगा.
Interview में supply chain security पूछा जाए तो ये चार शब्द क्रम से बोलिए: SBOM, provenance, scanning, signing. फिर हर एक के लिए एक command बताइए.
Lab: try at home
- Create a docker-container builder.
- Build and push with --sbom=true.
- Add --provenance=mode=max and read the commit.
- Export the SBOM to a file and count packages.
- Search three images for one library.
- Sign an image digest with example cosign keys and verify.
Recap
- SBOM is the list of contents.
- Provenance is the build record.
- buildx adds both with two flags.
- Attestations live in the image index.
- Scan SBOMs for CVEs on a schedule.
- Sign digests and verify before deploy.
Revision card
Interview card