From 8ee38a6e44c7f5e90e7c4c75640d0e015dd67968 Mon Sep 17 00:00:00 2001 From: kylerankin Date: Wed, 23 Sep 2026 19:39:11 +0000 Subject: [PATCH] fix(containers): enforce sigstore signatures for projectbluefin images MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit common#847 was closed as completed when #933 merged, but #933 only shipped the trust materials (fulcio_v1.crt.pem, rekor.pub). The enforcing half — #883, which adds a sigstoreSigned scope for ghcr.io/projectbluefin — was closed unmerged, so the base image every consumer pulls is still accepted without signature verification. Add a keyless sigstoreSigned entry for ghcr.io/projectbluefin in system_files/shared/etc/containers/policy.json, referencing the Fulcio/Rekor trust materials already present in the tree: - fulcio.caPath -> fulcio_v1.crt.pem - fulcio.oidcIssuer -> https://token.actions.githubusercontent.com - fulcio.subjectRegExp -> ^https://github\.com/projectbluefin/[^/]+/\.github/workflows/ (the certificate identity the sign-and-publish action emits in build.yml) - rekorPublicKeyPath -> rekor.pub - signedIdentity -> matchRepository The insecureAcceptAnything catch-all is left in place: narrowing it would reject every unlisted registry (Fedora base, rpm-ostree layers, COPRs) and requires validating the full consumed-registry surface first. Hive-Run: projectbluefin/common#1133 Hive-Plan: land the policy enforcement half of #883 Hive-Spec: sec-check#847 Signed-off-by: kylerankin --- .../references/supply-chain.md | 40 +++++++++++++++++++ .../shared/etc/containers/policy.json | 14 +++++++ 2 files changed, 54 insertions(+) diff --git a/docs/skills/release-promotion/references/supply-chain.md b/docs/skills/release-promotion/references/supply-chain.md index aa3f7dfa1..c16a369f9 100644 --- a/docs/skills/release-promotion/references/supply-chain.md +++ b/docs/skills/release-promotion/references/supply-chain.md @@ -30,6 +30,46 @@ permissions: Do **not** add `SIGNING_SECRET` to new workflows — keyless OIDC has replaced it. +## Enforcing signatures at pull time — containers policy.json + +Signing only matters if the pull path rejects unsigned images. The base image +pull is enforced by +`system_files/shared/etc/containers/policy.json`, consumed by the +`containers/image` library at `bootc switch` / `bootc install` time. + +- The `"default"` scope is `reject`, so any registry without an explicit entry + falls through to the `""` docker catch-all. +- `quay.io/toolbx-images` and `ghcr.io/ublue-os` are enforced with + `sigstoreSigned` (`keyPath`/`keyPaths` + `matchRepository`). +- `ghcr.io/projectbluefin` (the base image every consumer pulls) is enforced + with a keyless `sigstoreSigned` entry: Fulcio CA (`fulcio_v1.crt.pem`), + Rekor public key (`rekor.pub`), and `subjectRegExp` scoped to + `^https://github\.com/projectbluefin/[^/]+/\.github/workflows/` — the same + certificate identity the `sign-and-publish` action emits + (`.github/workflows/build.yml`). + +The `fulcio` block uses `oidcIssuer` + `subjectRegExp` (or `subjectEmail`), +**not** a top-level `fulcioIssuer`: `containers/image` policy parsing only +recognises those fields inside the `fulcio` object, so a `fulcioIssuer` +key is silently ignored and the scope falls back to the catch-all. + +> The `insecureAcceptAnything` catch-all on the `""` docker scope is left in +> place on purpose. Removing it would reject every registry without an explicit +> entry (Fedora base, rpm-ostree layers, third-party COPRs) and requires +> validating the entire consumed-registry surface before it is safe. Narrowing +> it is a follow-up, not this change. + +### Verifying the policy + +```bash +# The projectbluefin entry references these trust roots — they must exist: +ls -1 system_files/shared/usr/lib/pki/containers/fulcio_v1.crt.pem \ + system_files/shared/usr/lib/pki/containers/rekor.pub + +# The policy must be valid JSON: +python3 -c "import json;json.load(open('system_files/shared/etc/containers/policy.json'))" +``` + --- ## Verifying a published artifact diff --git a/system_files/shared/etc/containers/policy.json b/system_files/shared/etc/containers/policy.json index 20be49f56..a4a172b62 100644 --- a/system_files/shared/etc/containers/policy.json +++ b/system_files/shared/etc/containers/policy.json @@ -41,6 +41,20 @@ } } ], + "ghcr.io/projectbluefin": [ + { + "type": "sigstoreSigned", + "fulcio": { + "caPath": "/usr/lib/pki/containers/fulcio_v1.crt.pem", + "oidcIssuer": "https://token.actions.githubusercontent.com", + "subjectRegExp": "^https://github\\.com/projectbluefin/[^/]+/\\.github/workflows/" + }, + "rekorPublicKeyPath": "/usr/lib/pki/containers/rekor.pub", + "signedIdentity": { + "type": "matchRepository" + } + } + ], "": [ { "type": "insecureAcceptAnything"