diff --git a/applicationsets/kyverno-policies.yaml b/applicationsets/kyverno-policies.yaml index f0bf77a..b928623 100644 --- a/applicationsets/kyverno-policies.yaml +++ b/applicationsets/kyverno-policies.yaml @@ -23,6 +23,9 @@ spec: - appName: kyverno-best-practices path: policies/kyverno/best-practices syncWave: "21" + - appName: kyverno-supply-chain + path: policies/kyverno/supply-chain + syncWave: "22" template: metadata: name: '{{ .appName }}' diff --git a/policies/kyverno/supply-chain/base/kustomization.yaml b/policies/kyverno/supply-chain/base/kustomization.yaml new file mode 100644 index 0000000..a92f076 --- /dev/null +++ b/policies/kyverno/supply-chain/base/kustomization.yaml @@ -0,0 +1,5 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - verify-images.yaml diff --git a/policies/kyverno/supply-chain/base/verify-images.yaml b/policies/kyverno/supply-chain/base/verify-images.yaml new file mode 100644 index 0000000..884870d --- /dev/null +++ b/policies/kyverno/supply-chain/base/verify-images.yaml @@ -0,0 +1,58 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: verify-images + annotations: + policies.kyverno.io/title: Verify Image Signatures + policies.kyverno.io/category: Supply Chain + policies.kyverno.io/severity: high + policies.kyverno.io/subject: Pod + policies.kyverno.io/description: >- + Factory-built images (ghcr.io/nanohype/*) must carry a valid keyless + Cosign signature produced by the org release workflow. The release + workflows sign with GitHub Actions OIDC (Fulcio + public Rekor), so the + attestor matches that workflow identity. An unsigned or foreign-signed + image — hand-pushed or tampered — fails verification. Images outside + ghcr.io/nanohype/* are not matched and pass unaffected. +spec: + # Audit during the signature rollout: report every unsigned nanohype image + # in PolicyReports without blocking admission. Overlays flip this to Enforce + # per environment once reports are clean (see overlays/). + validationFailureAction: Audit + # Image verification calls the registry + Rekor; the 10s default is tight. + webhookTimeoutSeconds: 30 + background: false + rules: + - name: verify-ghcr-nanohype + match: + any: + - resources: + kinds: + - Pod + exclude: + any: + - resources: + namespaces: + - kube-system + - kube-public + - kube-node-lease + - kyverno + verifyImages: + - imageReferences: + - "ghcr.io/nanohype/*" + # Pure signature verification for the rollout: report presence/validity + # without rewriting tags to digests or requiring digest references yet. + required: true + mutateDigest: false + verifyDigest: false + attestors: + - count: 1 + entries: + - keyless: + # GitHub Actions OIDC identity of the org release workflows. + # Operator signs from release.yaml, tenants from release.yml; + # both run on tag pushes (refs/tags/...). + issuer: "https://token.actions.githubusercontent.com" + subjectRegExp: '^https://github\.com/nanohype/[^/]+/\.github/workflows/release\.ya?ml@refs/tags/.+$' + rekor: + url: "https://rekor.sigstore.dev" diff --git a/policies/kyverno/supply-chain/overlays/dev/kustomization.yaml b/policies/kyverno/supply-chain/overlays/dev/kustomization.yaml new file mode 100644 index 0000000..9e633c7 --- /dev/null +++ b/policies/kyverno/supply-chain/overlays/dev/kustomization.yaml @@ -0,0 +1,14 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - ../../base + +# Dev: Audit mode (report unsigned images, don't block) +patches: + - patch: |- + - op: replace + path: /spec/validationFailureAction + value: Audit + target: + kind: ClusterPolicy diff --git a/policies/kyverno/supply-chain/overlays/production/kustomization.yaml b/policies/kyverno/supply-chain/overlays/production/kustomization.yaml new file mode 100644 index 0000000..81b2209 --- /dev/null +++ b/policies/kyverno/supply-chain/overlays/production/kustomization.yaml @@ -0,0 +1,16 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - ../../base + +# Production: Audit during the signature rollout. Flip value to Enforce once +# staging has run a clean audit week and every ghcr.io/nanohype/* image +# verifies — at which point an unsigned or tampered image is blocked at admission. +patches: + - patch: |- + - op: replace + path: /spec/validationFailureAction + value: Audit + target: + kind: ClusterPolicy diff --git a/policies/kyverno/supply-chain/overlays/staging/kustomization.yaml b/policies/kyverno/supply-chain/overlays/staging/kustomization.yaml new file mode 100644 index 0000000..bc77218 --- /dev/null +++ b/policies/kyverno/supply-chain/overlays/staging/kustomization.yaml @@ -0,0 +1,15 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - ../../base + +# Staging: Audit during the signature rollout. Flip value to Enforce once the +# PolicyReports here show every ghcr.io/nanohype/* image verifying clean. +patches: + - patch: |- + - op: replace + path: /spec/validationFailureAction + value: Audit + target: + kind: ClusterPolicy