M14: Supply Chain Attestations & SLSA
Artifact signing (M13) answers “was this artifact signed by the expected identity?” Supply chain attestations answer a richer set of questions: where did the source come from, what was the build process, who ran the tests, and is the known CVE actually exploitable? This module covers SLSA, in-toto, VEX, and how to wire the full attestation stack into your pipeline.
Learning Objectives
By the end of this module you should be able to:
- Implement SLSA Level 2 or 3 for your build process
- Generate in-toto attestations for build, test, and source
- Issue VEX statements to communicate non-applicable CVEs
- Build an attestation consumer (e.g., admission controller)
- Map SLSA to customer and regulatory requirements
- Explain the difference between signing (M13) and attestations (this module)
1. Signatures vs. Attestations
These are different, complementary mechanisms:
| Aspect | Signature (M13) | Attestation (this module) |
|---|---|---|
| Question | ”Is this artifact signed by X?" | "Is this artifact the result of process P, run on source S, with test T passing?” |
| Issuer | cosign / KMS | SLSA provenance generator, in-toto |
| Content | Binary signature over a digest | Structured claim about a process |
| Storage | OCI referrer | OCI referrer (in-toto predicate) |
| Consumer | cosign verify | Custom verifier (e.g., Kyverno, Ratify) |
A signature says who signed. An attestation says what was done. The two together: an artifact signed by CI, with an attestation that the CI run was triggered by a specific commit, on a hardened runner, with all tests passing.
2. SLSA: Supply Chain Levels for Software Artifacts
SLSA is a framework with four levels. Each level adds a guarantee:
| Level | Build provenance | Signed | Source | Hardened build |
|---|---|---|---|---|
| 0 | None | No | Any | No |
| 1 | Documented | No | Any | No |
| 2 | Documented + tamper-resistant | Yes | Verified | Some |
| 3 | Hardened, two-party, signed | Yes | Verified | Yes (e.g., ephemeral) |
| 4 | Two-party review, hermetic | Yes | Two-party review | Yes |
Most orgs target SLSA L2 as a reasonable goal; L3 is the differentiator. L4 is hyperscaler territory.
What SLSA Requires (L2)
- Build provenance generated and signed
- Provenance is non-forgeable (signed by a separate key)
- Source verified (commit hash in provenance matches git)
- Build platform is trusted (e.g., GitHub Actions with OIDC)
What SLSA L3 Adds
- Hardened build platform
- Provenance is generated by the platform, not the build script
- Build runs in an isolated, ephemeral environment
- Strong separation of duties
3. The in-toto Attestation Framework
in-toto is a CNCF project. Attestations are JSON-LD documents with:
- A
predicateType— what kind of attestation - A
predicate— the actual claim - A
subject— what the attestation is about (image digest, source repo, etc.) - A signature (signed by cosign or KMS)
The standard predicate types:
- SLSA Provenance — describes the build (source, builder, materials)
- SPDX SBOM — inventory of components
- CycloneDX SBOM — same, different format
- VEX — vulnerability exploitability exchange
- Link — generic predicate for any custom claim
- Test Result — what tests ran, what passed
- Code Review — review status of a change
4. Generating Provenance
SLSA GitHub Generator (slsa-github-generator)
A reusable GitHub Actions workflow that produces SLSA L3 provenance.
# .github/workflows/release.yml
name: release
on:
push:
tags: ['v*']
permissions:
id-token: write
contents: read
packages: write
jobs:
build:
uses: slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@v1.9.0
with:
go-version: 1.22
module: github.com/my-org/my-app
artifact-path: dist/my-appThe workflow:
- Builds the Go binary in a hardened GitHub Actions runner
- Generates SLSA provenance with source commit, build config, materials
- Signs the provenance with the workflow’s OIDC identity
- Uploads both binary and provenance to the release
The provenance contains:
{
"_type": "https://in-toto.io/Statement/v0.1",
"predicateType": "https://slsa.dev/provenance/v1",
"subject": [{"name": "my-app", "digest": {"sha256": "abc..."}}],
"predicate": {
"buildDefinition": {
"buildType": "https://slsa.dev/github-actions/v1",
"externalParameters": {
"workflow": {"ref": "refs/tags/v1.2.3", "repository": "https://github.com/my-org/my-app"}
}
},
"runDetails": {
"builder": {"id": "https://github.com/actions/runner/github-hosted"},
"metadata": {"invocationId": "github-actions-run-12345"}
}
}
}A consumer can verify: this artifact was built by GitHub Actions, on commit abc123, in repo my-org/my-app, on tag v1.2.3. If any of those don’t match what’s expected, the artifact is rejected.
5. VEX: Vulnerability Exploitability eXchange
VEX is the answer to “this dep has CVE-2024-XXXX, but I don’t use the vulnerable function.” It’s a structured statement that says: this vuln exists, but it’s not exploitable in this product, for this reason.
VEX States (CycloneDX)
not_affected— the vuln is in a dep, but not reachableaffected— the vuln is reachable, fix is plannedfixed— the vuln was reachable, but a fix has been appliedin_triage— under investigationfalse_positive— the vuln doesn’t apply; scanner was wrongresolved— same as fixed; included for clarityexploitable— the vuln is reachable, no fix available, mitigation requiredresolved_with_pedigree— fixed in a way that may not be obvious
When to Issue VEX
- A scanner reports a vuln in your product
- You determine the vuln is not reachable in your code
- You publish a VEX statement describing the non-applicability
- Customers consume the VEX and clear the finding on their side
VEX Workflow
1. Trivy/Snyk finds CVE-2024-XXXX in image
2. Engineer triages: "we don't call the vulnerable function"
3. Engineer files VEX: state=not_affected, justification=code_not_present
4. VEX is signed and published (attestation to the SBOM)
5. Customer ingests VEX, suppresses the finding
6. Re-scan: VEX-aware scanner shows the finding as cleared
VEX Tools
- cve-bin-tool — generates VEX from reachability analysis
- VulnTotal — multi-scanner aggregation with VEX output
- Manual authoring — for known cases, write the VEX JSON by hand and attach as attestation
6. The Full Attestation Stack
+--------------------+
| Source commit | <-- signed by git
+---------+----------+
|
v
+--------------------+
| Build | <-- SLSA provenance (in-toto)
| (SLSA L3) | signed by CI OIDC
+---------+----------+
|
v
+--------------------+
| Artifact (image) | <-- cosign signature
+---------+----------+
|
+-- SBOM (CycloneDX) <-- signed, in-toto
+-- VEX <-- signed, in-toto
+-- Test results <-- signed, in-toto
+-- Code review <-- signed, in-toto
|
v
+--------------------+
| Deploy target | <-- admission controller
| (K8s, ECS, etc.) | verifies signatures
| | verifies provenance
| | consumes VEX
+--------------------+
Every step is signed. Every claim is verifiable. Every claim can be re-checked at any time without re-running the build.
7. Customer-Facing Attestations
Customers increasingly demand evidence of supply-chain integrity. The artifacts to provide:
- SBOM (CycloneDX or SPDX)
- SLSA provenance (verifiable)
- VEX feed (continuously updated)
- Compliance attestations (SOC2 controls, ISO mappings)
- Vulnerability disclosure policy (how to report a vuln to you)
Distribution channels:
- Public attestation registry
- OCI artifacts alongside your product image
- Web portal with on-demand access
- API with token-based access for enterprise customers
8. SLSA + Customer Requirements
| Customer requirement | SLSA level | Why |
|---|---|---|
| ”Show me your SBOM” | L1 | Documented build = documented inventory |
| ”Show me your build process” | L2 | Provenance is non-forgeable |
| ”Prove the binary came from your source” | L3 | Hardened build, two-party signing |
| ”We need to verify it independently” | L3+ | Verifiable provenance with public keys |
| ”We need to replay your build” | L4 | Hermetic, reproducible |
Most enterprise security questionnaires map to SLSA L2. FedRAMP and similar frameworks are starting to require L3. Plan for L3 as the long-term target.
9. Implementing SLSA L3: The Path
Month 1: Inventory
- Where do you build? (GitHub Actions, GitLab, Jenkins, Buildkite)
- Are builds reproducible? (Same source → same artifact?)
- Is the build platform hardened? (Ephemeral, isolated, no manual access)
- What is the source verification story? (Signed commits, branch protection)
Month 2: Provenance Generation
- Pick a provenance generator (slsa-github-generator, Tekton Chains, in-toto-golang)
- Integrate into the build pipeline
- Verify provenance is generated for every release
- Sign the provenance
Month 3: Verification
- Stand up an admission controller (Kyverno, Ratify)
- Configure it to verify provenance
- Test: unsigned image is rejected
- Roll out to all clusters
Month 4: Hardening
- Migrate to ephemeral runners
- Two-party review on release (release engineer + security engineer)
- Document the SLSA L3 posture
- Audit by an external party
10. Common Pitfalls
| Pitfall | Consequence | Fix |
|---|---|---|
| Provenance generated but not verified | Pointless; deploy accepts anything | Verify at admission |
| Provenance claims source but doesn’t verify | Provenance is just text | Sign and verify against git |
| VEX issued but not machine-readable | Manual suppression, drift | CycloneDX VEX format, signed |
| No transparency log | Cannot detect tampering | Rekor for everything |
| SBOM signed but not attached to image | Customer can’t find it | Attach as OCI referrer |
| L3 aspirations with L0 build platform | Cannot honestly claim L3 | Harden the platform first |
11. Self-Check
- What SLSA level is your build process at, honestly? Use the slsa.dev self-assessment.
- Can a customer today verify that your binary came from your source? If not, generate provenance.
- When a new CVE drops, how long does it take you to publish a VEX for known-not-applicable cases?
12. The Attestation Lifecycle
An attestation has a lifecycle similar to a signature:
- Generation — at build time, by the build platform
- Storage — as an OCI referrer, alongside the artifact
- Distribution — via the registry; consumer pulls by digest
- Verification — at deploy time, by the admission controller
- Re-verification — at any time, by re-pulling the attestation
- Retention — the attestation lives as long as the artifact
The attestation is the evidence trail. The signature is the authentication. Together, they prove both what the artifact is and where it came from.
13. Provenance and Reproducible Builds (Deep Dive)
Reproducible builds (M09) and provenance are complementary:
- Reproducible — given source S, the build produces artifact A, deterministically
- Provenance — a signed claim that A was built from S
Reproducible builds enable independent verification: the customer can rebuild from S and check that the result equals A. Provenance attests that the build was done by a specific platform.
For the highest assurance (SLSA L4, defense, financial regulators), you want both:
- Rebuild from S in a clean environment
- Compare the result to A
- Verify the provenance claims the build was done correctly
- Both checks pass → the artifact is genuine
The combination is rare in practice; most orgs do provenance first, rebuilds second.
14. The in-toto Attestation Predicate Catalog
The in-toto project maintains a list of standard predicate types. As of 2025:
| Predicate | Purpose | Typical use |
|---|---|---|
| SLSA Provenance | Build provenance | SLSA L2+ |
| SPDX SBOM | License + component inventory | M08 |
| CycloneDX SBOM | Same, different format | M08 |
| VEX | Vulnerability applicability | Customer disclosure |
| Link | Generic claim | Custom assertions |
| Test Result | What tests ran, what passed | Compliance |
| Code Review | Review status | Code-review compliance |
| Hera Workflow | Argo Workflows run | Workflow provenance |
| Run Details | Generic build metadata | Custom build systems |
Custom predicates are allowed but should be avoided unless none of the standard types fits.
15. The SLSA Levels in Practice
| Level | What you need | What’s hard |
|---|---|---|
| 0 | Nothing | — |
| 1 | Documented build process | Easy |
| 2 | Signed provenance | Medium (requires OIDC, slsa-github-generator or similar) |
| 3 | Hardened build platform | Hard (ephemeral runners, two-party review) |
| 4 | Two-party review, hermetic builds | Very hard (reproducible builds, isolation) |
Most orgs target L2. L3 is the differentiator for high-value customers. L4 is rare outside defense and financial regulators.
16. The Hardening Checklist for SLSA L3
For an org targeting SLSA L3:
- All builds run on ephemeral runners (no shared state)
- All builds use OIDC (M12) to authenticate to the build platform
- All build provenance is generated by the platform, not the build script
- All provenance is signed (Rekor transparency log)
- All source is verified (commit hash in provenance matches git)
- All builds are isolated (no network access during build, except to allowed mirrors)
- All build dependencies are pinned (lockfile)
- Two-party review is required for releases
- All consumers verify provenance at deploy
After completing the checklist, the org can honestly claim SLSA L3.
17. Attestation and the Audit Trail
| Control | Attestation evidence |
|---|---|
| SOC 2 CC8.1 (change management) | Provenance is part of the change record |
| ISO A.8.32 (change management) | Provenance for every release |
| FedRAMP SI-7 (software/firmware integrity) | Provenance + signature |
| FedRAMP CM-5 (access restrictions) | Provenance generation is restricted to the build platform |
| SLSA L2/L3 | Provenance is the implementation |
| EU CRA | Provenance + SBOM is the evidence |
| US EO 14028 | Provenance + SBOM is the requirement |
The audit asks “how do you know the artifact was built correctly?” The answer is the provenance. The verification is the cryptographic check at deploy.
18. The Transparency Log: Rekor and Friends
Rekor is one of several transparency logs in the supply-chain space:
- Rekor (Sigstore) — generic, free, public
- Binary Transparency (Google) — for binaries
- in-toto.io/gossip — peer-to-peer log
- TUF / The Update Framework — for software updates
The pattern: an append-only log of claims, cryptographically verifiable, no central authority. The log is the audit trail that no one party can forge.
For most orgs, Rekor is sufficient. For air-gapped environments, run your own.
19. Attestation in the Customer-Facing Posture
The customer-facing supply-chain posture document (M18) includes:
- SBOM (M08)
- Provenance (this module)
- VEX (this module)
- Vulnerability disclosure policy
- Compliance certifications (SOC 2, ISO 27001)
- Build platform hardening (SLSA level claim)
- Test coverage and methodology
The customer can verify each claim independently. The posture is the single document the customer uses to assess supply-chain risk.