Zion Boggan zionboggan.com ↗

supply-chain threat model notes

d155e46   Zion Boggan committed on May 11, 2026 (1 month ago)
docs/supply-chain.md +47 -0
@@ -0,0 +1,47 @@
+# Supply chain notes
+
+## The threat model
+
+The attacks this defends against are the ones where the source code is fine but the
+artifact isn't:
+
+- a registry account is compromised and a tag is repointed at a malicious image
+- a build runner is tampered with and produces a backdoored image
+- a dependency pulled at build time has a known CVE that nobody looked at
+- an image is deployed that nobody can actually account for the contents of
+
+Source-level scanning (the other repo) does nothing for any of these. They all
+happen at or after build time, which is why this is a separate layer.
+
+## How Sigstore answers each one
+
+- **Repointed tag** - the Kyverno policy resolves tags to digests on admission and
+ requires a signature over that digest. Moving a tag doesn't move the signature.
+- **Tampered runner** - the signature is tied to the OIDC identity of the workflow
+ run. An image built somewhere else can't produce a signature from
+ `https://github.com/zionboggan/...`.
+- **Vulnerable dependency** - grype scans the built image and fails the build on a
+ high or critical finding before signing happens, so unsigned-and-vulnerable never
+ even gets to the registry as a release.
+- **Unaccountable contents** - the SBOM is generated from the actual image, signed
+ as an attestation, and required at admission. No SBOM, no deploy.
+
+## Transparency log
+
+Every signature and attestation is recorded in Rekor. That gives an auditable,
+append-only record of what was signed, by which identity, and when. If a signing
+identity is ever misused, the log is where you'd find every artifact it touched.
+
+## Why digests everywhere
+
+Tags are mutable; digests are not. Signing a tag is signing a pointer. Every step
+here - build output, scan target, sign, attest, verify, and the admission rewrite -
+operates on `@sha256:...`. The image that runs in the cluster is byte-for-byte the
+image that was signed.
+
+## Rotating to keys
+
+Keyless suits CI because there's no secret to hold. For an offline or air-gapped
+verifier where you can't reach Fulcio/Rekor at verify time, generate a key pair
+(`cosign generate-key-pair`) or back it with a KMS, sign with `--key`, and verify
+with the public key. The pipeline structure is identical; only the attestor changes.