feat(policies): verify-images Kyverno policy for factory-built images#47
Open
stxkxs wants to merge 1 commit into
Open
feat(policies): verify-images Kyverno policy for factory-built images#47stxkxs wants to merge 1 commit into
stxkxs wants to merge 1 commit into
Conversation
The factory signs every image it ships — the operator and all four tenant
release workflows run `cosign sign` (keyless OIDC) and `cosign attest` on
each pushed image. Nothing on the cluster side ever checked those signatures,
so a hand-pushed or tampered image was admitted identically to a signed,
gate-approved one. This adds the admission-time check that closes that gap.
─────────────────────────── What changed ───────────────────────────
policies/kyverno/supply-chain/ (new policy group, pure Kustomize like the
others) — a `verify-images` ClusterPolicy with a base + dev/staging/production
overlays:
- Scopes to imageReferences `ghcr.io/nanohype/*`. Images outside the org
registry (cert-manager, kyverno, etc.) are not matched and pass untouched,
so the blast radius is the factory's own images only.
- Keyless Cosign attestor matching the release-workflow identity: issuer
`https://token.actions.githubusercontent.com`, subject regex
`github.com/nanohype/<repo>/.github/workflows/release.ya?ml@refs/tags/*`
(operator signs from release.yaml, tenants from release.yml; both on tag
pushes), verified against public Rekor.
- required: true, mutateDigest/verifyDigest: false — pure signature
verification for the rollout, no tag-to-digest rewriting yet.
- webhookTimeoutSeconds: 30 (registry + Rekor lookups exceed the 10s default).
- Excludes kube-system/kube-public/kube-node-lease/kyverno from the match.
applicationsets/kyverno-policies.yaml — adds the `kyverno-supply-chain` entry
at sync-wave 22 (after best-practices at 21), same matrix generator and
per-environment overlay path as the existing policy groups.
─────────────────────────── Rollout ───────────────────────────
Ships in Audit mode across all three environments: every unsigned
ghcr.io/nanohype/* image is reported in PolicyReports without blocking
admission. This is deliberate — it is the cluster's first image-verification
policy, and going straight to Enforce before confirming the deployed image set
verifies clean would break admission for any pre-signing or mutable-tag image.
The overlays are structured so the flip to Enforce is a one-line value change
per environment: staging first after a clean audit week, production after
staging proves clean.
Validated with `task validate` (yamllint + kustomize build, all environments).
CI Results
All validations passed. |
This was referenced Jun 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The factory signs every image it ships — the operator and all four tenant release workflows run
cosign sign(keyless OIDC) +cosign attest. But there was zeroverifyImagesadmission policy anywhere, so a hand-pushed or tampered image was admitted exactly like a signed, gate-approved one. Kyverno is already installed with per-env overlays; this fills the missing half (sign → verify).What
New
policies/kyverno/supply-chain/group (pure Kustomize, mirroring best-practices / pod-security-standards):verify-imagesClusterPolicy scoped toghcr.io/nanohype/*— foreign images (cert-manager, kyverno, …) aren't matched and pass untouched, so blast radius is the factory's own images.https://token.actions.githubusercontent.com, subjectgithub.com/nanohype/<repo>/.github/workflows/release.ya?ml@refs/tags/*(operator →release.yaml, tenants →release.yml), verified against public Rekor.required: true,mutateDigest/verifyDigest: false— pure signature verification for the rollout.webhookTimeoutSeconds: 30.kyverno-supply-chainat sync-wave 22.Rollout (Audit first — deliberate)
Ships in Audit across all three envs: unsigned
ghcr.io/nanohype/*images are reported in PolicyReports without blocking. This is the cluster's first image-verification policy; straight-to-Enforce would break admission for any pre-signing or mutable-tag image still running. The overlays make the flip a one-lineAudit→Enforcechange — staging first after a clean audit week, production after staging proves clean.Verification
task validate(yamllint +kustomize buildall environments) — green. Each overlay resolvesvalidationFailureAction: Audit.A sibling PR mirrors this to
aks-gitops(same registry-scoped policy applies on AKS clusters).