| | @@ -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. |