A signed image proves it genuinely came from the pipeline that signed it. It proves nothing about what that pipeline actually did to produce it: which source code, with which dependencies, on which machine, with which privileges. A compromised pipeline building a malicious image can sign it just as legitimately as a clean one, signed by the same identity, with the same key. Signing answers “who produced this,” not “how.”
What provenance adds to signing
A provenance attestation is a signed document accompanying the artifact that describes its construction: the exact source commit, build parameters, the identity of the system that ran it, the timestamp. The in-toto specification formalizes this format, independently of whichever tool produces it.
// Simplified provenance attestation (in-toto format)
{
"predicateType": "https://slsa.dev/provenance/v1",
"subject": [{ "name": "registry.example.com/app", "digest": { "sha256": "1e9c...a41f" } }],
"predicate": {
"buildDefinition": {
"buildType": "https://github.com/actions/runner",
"externalParameters": { "repository": "acme/app", "ref": "refs/heads/main" }
},
"runDetails": {
"builder": { "id": "https://github.com/acme/app/.github/workflows/build.yml" }
}
}
}
This attestation answers a question signing alone doesn’t even ask: was this image built by the official pipeline, from the main repository’s code, or by any process capable of obtaining a valid OIDC identity?
SLSA: levels, not a switch
The SLSA framework (Supply-chain Levels for Software Artifacts) defines increasing maturity levels, not a binary compliant/non-compliant state. Level 1 requires documented provenance, generated by an automated process. Level 2 requires that process to run on a hosted build platform, not a developer’s laptop. Level 3 requires build isolation: one build must be unable to read or influence another build’s secrets or artifacts on the same infrastructure.
# GitHub Actions: official SLSA generator, produces level-3 provenance
# without reimplementing the specification yourself
- uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
with:
base64-subjects: "${{ needs.build.outputs.digests }}"
Targeting level 3 directly on a pipeline that doesn’t even have documented provenance today amounts to optimizing a problem before measuring whether it exists. Progressing level by level avoids that trap: each level adds one precise guarantee, independently verifiable from the next.
Verifying an attestation at admission
An attestation nobody verifies has the same value as an ignored signature: none. A Kubernetes admission policy can require, on top of the signature already covered by scanning and signing container images, the presence of a provenance attestation matching a specific builder before admitting a pod.
# Kyverno: requires a provenance attestation signed by the official
# GitHub Actions builder, on top of the image signature
verifyImages:
- imageReferences: ["registry.example.com/*"]
attestations:
- predicateType: https://slsa.dev/provenance/v1
attestors:
- entries:
- keyless:
issuer: "https://token.actions.githubusercontent.com"
This check closes a gap signing alone leaves open: a legitimate OIDC identity, but used from a different pipeline than expected (a fork, an unprotected branch), signs an image that would pass signature verification alone, but not attestation verification requiring a specific builder.
Where it stops being worth it
SLSA level 3 and beyond (full hermetic isolation, bit-for-bit build reproducibility) carries a real infrastructure cost, justified for a software vendor distributed at scale or a supplier under strict regulatory obligations. For a mid-size company shipping its own product internally, level 2 (hosted build, provenance signed and verified at admission) already covers the realistic risk that matters: a compromised pipeline producing a malicious image with nothing catching it before production.
Takeaway
An image signature proves an identity; a provenance attestation proves a build process. SLSA structures that maturity into progressive levels rather than a binary state, and each level only has value if the attestation it produces is actually verified at admission, not just generated and archived. This foundation is part of what gets built when industrializing a CI/CD chain facing real compliance requirements.