# SBOMs and build provenance

> A list of what’s inside an artifact, and a signed record of where and how it was built.

Concept · Application & cloud security · https://levelcode.org/concepts/sbom-and-provenance

When the next Log4Shell lands, two questions decide how bad your week will be: **which of our artifacts contain the vulnerable component?** And **can we trust that what's running is what we built?** SBOMs answer the first and provenance answers the second.

## SBOM: what's inside

A **software bill of materials** lists every component in an artifact, direct and transitive dependencies along with OS packages, with versions and identifiers (package URLs). The two standard formats are **SPDX** and **CycloneDX**.

```bash
syft ghcr.io/acme/api:1.8.2 -o cyclonedx-json > sbom.json   # generate from an image
grype sbom:sbom.json                                       # scan it for known CVEs
```

- **Generate it at build time** from the actual artifact, and store it alongside the artifact.
- **Rescan stored SBOMs whenever new CVEs are published.** You can find affected services in minutes without rebuilding anything.
- **Know the limits.** An SBOM lists components; it doesn't say whether the vulnerable code is reachable. Use [dependency scanning](https://levelcode.org/roadmaps/devsecops/sast-and-sca) with reachability data to prioritise.

## Provenance: where it came from

**Build provenance** is a signed statement, called an *attestation*, that records **which source commit, which build workflow and which builder** produced an artifact with a given digest. It defends against tampering between source and production: a compromised build server, a hand-pushed image, a swapped tarball.

**SLSA** (Supply-chain Levels for Software Artifacts) grades how trustworthy a build's provenance is. The higher levels require builds on a hosted, isolated platform that generates and signs the provenance itself, so the build steps can't forge it.

## Signing without managing keys

**Sigstore** (`cosign`) signs artifacts and attestations using the CI job's [OIDC identity](https://levelcode.org/concepts/workload-identity) instead of a long-lived private key, and records the signature in a public transparency log.

```bash
cosign sign ghcr.io/acme/api@sha256:4c1e…              # in CI, keyless
cosign verify ghcr.io/acme/api@sha256:4c1e… \
  --certificate-identity-regexp 'https://github.com/acme/api/.github/workflows/release.yml@.*' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com
```

## Closing the loop

None of this helps unless something **checks** it. Enforce verification at deploy time: an admission controller such as Kyverno or Sigstore's policy controller only admits images that are signed by your release workflow and come with provenance and an SBOM. Deploy **by digest**, not by mutable tag, so what you verified is what runs.

Pair this with pinned dependencies and [least privilege](https://levelcode.org/concepts/least-privilege) for CI. The [supply chain lesson](https://levelcode.org/roadmaps/devsecops/supply-chain-security) covers the full pipeline.
