mirror of
https://github.com/kerberos-io/helm-charts.git
synced 2026-11-10 21:10:24 +00:00
refactor(hub): one Kyverno policy per template in templates/kyverno
Move the image-verification policy to templates/kyverno/, one ClusterPolicy per file (hub-api-signed-images.yaml), with the shared parts (Kyverno check, names, labels, policy-wide settings and the UUG.AI signer) in templates/kyverno/_helpers.tpl. imageVerification.images becomes imageVerification.policies.<name>, each with its own enabled switch and optional validationFailureAction, failurePolicy and mutateDigest overrides. Schema and README updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
49d6226a5d
commit
dcfcf28050
+26
-10
@@ -339,10 +339,22 @@ only when a compatible image release is selected; no migration is required.
|
||||
|
||||
Starting with chart **`0.179.0`**, the chart verifies that UUG.AI images are
|
||||
signed by UUG.AI. When [Kyverno](https://kyverno.io) is installed in the cluster,
|
||||
it creates one `ClusterPolicy` per release, named
|
||||
`<namespace>-<release>-signed-images` and scoped to the release namespace.
|
||||
Without Kyverno (no `kyverno.io/v1` API), nothing is created and the chart
|
||||
behaves as before. Set `imageVerification.enabled: false` to opt out.
|
||||
it creates Kyverno `ClusterPolicies` scoped to the release namespace, named
|
||||
`<namespace>-<release>-<policy>`. Without Kyverno (no `kyverno.io/v1` API),
|
||||
nothing is created and the chart behaves as before. Set
|
||||
`imageVerification.enabled: false` to opt out.
|
||||
|
||||
Every policy is its own template in `templates/kyverno/`, with its own entry
|
||||
under `imageVerification.policies`:
|
||||
|
||||
| Template | Values | Checks |
|
||||
|---|---|---|
|
||||
| `hub-api-signed-images.yaml` | `imageVerification.policies.hubApi` | `ghcr.io/uug-ai/hub-api` signed for `uug-ai/hub-api` |
|
||||
|
||||
`templates/kyverno/_helpers.tpl` holds only the shared parts (the Kyverno
|
||||
check, names, labels, policy-wide settings and the UUG.AI signer). To change one
|
||||
policy, edit its file; to add an image, copy a policy file, change the image and
|
||||
repository, and add a `policies.<name>` entry in `values.yaml`.
|
||||
|
||||
Every image is released with a keyless [cosign](https://docs.sigstore.dev)
|
||||
signature recorded in the public Rekor transparency log. The policy accepts an
|
||||
@@ -355,21 +367,25 @@ image only when its signature was:
|
||||
The release workflow is shared by all UUG.AI repositories, so this repository
|
||||
claim is what stops an image of one repository passing as another.
|
||||
|
||||
Today only `hub-api` is listed in `imageVerification.images`; other images are
|
||||
added as their releases start signing. `hub-api` releases are signed from
|
||||
Today only `hub-api` has a policy; other images get one as their releases start
|
||||
signing. `hub-api` releases are signed from
|
||||
`v1.11.39` onwards (and `v1.11.37`); in `Enforce` mode an unsigned version such
|
||||
as `v1.11.38` is rejected.
|
||||
|
||||
The default is **`Audit`**: unsigned images are reported in Kyverno
|
||||
PolicyReports (for example in Policy Reporter) but still run, and
|
||||
`failurePolicy: Ignore` keeps pods starting if Kyverno is unavailable. To block
|
||||
unsigned images once the reports are clean:
|
||||
unsigned images once the reports are clean, for every policy or per policy:
|
||||
|
||||
```yaml
|
||||
imageVerification:
|
||||
validationFailureAction: Enforce
|
||||
failurePolicy: Fail # only with a highly available Kyverno
|
||||
mutateDigest: true # pin verified tags to their digest
|
||||
validationFailureAction: Enforce # default for every policy
|
||||
failurePolicy: Fail # only with a highly available Kyverno
|
||||
mutateDigest: true # pin verified tags to their digest
|
||||
policies:
|
||||
hubApi:
|
||||
enabled: true
|
||||
# validationFailureAction: Audit # per-policy override
|
||||
```
|
||||
|
||||
If you mirror the images to another registry, set `imageVerification.registry`
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
{{- /*
|
||||
Kyverno policy that verifies the keyless cosign signatures of UUG.AI images.
|
||||
Rendered only when imageVerification.enabled is true and the cluster serves the
|
||||
kyverno.io/v1 API (Kyverno installed), so clusters without Kyverno are unaffected.
|
||||
Each release gets its own ClusterPolicy, scoped to the release namespace.
|
||||
*/ -}}
|
||||
{{- $iv := .Values.imageVerification | default dict -}}
|
||||
{{- if and $iv.enabled (.Capabilities.APIVersions.Has "kyverno.io/v1") }}
|
||||
{{- if not $iv.images }}
|
||||
{{- fail "imageVerification.images must list at least one image when imageVerification.enabled is true" }}
|
||||
{{- end }}
|
||||
{{- if not (has $iv.validationFailureAction (list "Audit" "Enforce")) }}
|
||||
{{- fail "imageVerification.validationFailureAction must be Audit or Enforce" }}
|
||||
{{- end }}
|
||||
{{- if not (has $iv.failurePolicy (list "Ignore" "Fail")) }}
|
||||
{{- fail "imageVerification.failurePolicy must be Ignore or Fail" }}
|
||||
{{- end }}
|
||||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: {{ printf "%s-%s-signed-images" .Release.Namespace .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||
labels:
|
||||
app.kubernetes.io/name: hub
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: image-verification
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version }}
|
||||
annotations:
|
||||
policies.kyverno.io/title: Kerberos Hub images must be signed by UUG.AI
|
||||
policies.kyverno.io/category: Supply chain
|
||||
policies.kyverno.io/severity: high
|
||||
policies.kyverno.io/subject: Pod
|
||||
policies.kyverno.io/description: >-
|
||||
Verifies that UUG.AI images in namespace {{ .Release.Namespace }} carry a
|
||||
keyless cosign signature made by the UUG.AI release workflow for their own
|
||||
GitHub repository.
|
||||
spec:
|
||||
validationFailureAction: {{ $iv.validationFailureAction }}
|
||||
background: true
|
||||
failurePolicy: {{ $iv.failurePolicy }}
|
||||
webhookTimeoutSeconds: {{ $iv.webhookTimeoutSeconds | default 30 }}
|
||||
rules:
|
||||
{{- range $iv.images }}
|
||||
{{- $repository := .githubRepository | default .name }}
|
||||
- name: {{ printf "verify-%s" .name | trunc 63 | trimSuffix "-" }}
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- Pod
|
||||
namespaces:
|
||||
- {{ $.Release.Namespace | quote }}
|
||||
verifyImages:
|
||||
- imageReferences:
|
||||
- {{ printf "%s/%s:*" $iv.registry .name | quote }}
|
||||
- {{ printf "%s/%s@*" $iv.registry .name | quote }}
|
||||
required: true
|
||||
mutateDigest: {{ $iv.mutateDigest }}
|
||||
verifyDigest: {{ $iv.mutateDigest }}
|
||||
attestors:
|
||||
- entries:
|
||||
- keyless:
|
||||
issuer: {{ $iv.issuer | quote }}
|
||||
subjectRegExp: {{ $iv.subjectRegExp | squote }}
|
||||
additionalExtensions:
|
||||
# The signer identity is shared by every UUG.AI repository;
|
||||
# the repository claim binds the signature to this image's repo.
|
||||
githubWorkflowRepository: {{ printf "%s/%s" $iv.githubOrganization $repository | quote }}
|
||||
rekor:
|
||||
url: {{ $iv.rekorUrl | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,78 @@
|
||||
{{- /*
|
||||
Shared building blocks for the Kyverno policies in this folder.
|
||||
Each policy lives in its own file (one ClusterPolicy per file); these helpers
|
||||
hold only what every policy repeats.
|
||||
*/ -}}
|
||||
|
||||
{{- /*
|
||||
hub.kyverno.enabled: "true" when policy <name> should be rendered: image
|
||||
verification is enabled, the policy itself is enabled, and the cluster serves
|
||||
kyverno.io/v1 (Kyverno installed).
|
||||
Usage: {{- if eq (include "hub.kyverno.enabled" (dict "root" . "policy" "hubApi")) "true" }}
|
||||
*/ -}}
|
||||
{{- define "hub.kyverno.enabled" -}}
|
||||
{{- $iv := .root.Values.imageVerification | default dict -}}
|
||||
{{- $policy := index ($iv.policies | default dict) .policy | default dict -}}
|
||||
{{- if and $iv.enabled $policy.enabled (.root.Capabilities.APIVersions.Has "kyverno.io/v1") -}}
|
||||
true
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- /*
|
||||
hub.kyverno.name: ClusterPolicy name, unique per release: <namespace>-<release>-<suffix>.
|
||||
Usage: {{ include "hub.kyverno.name" (dict "root" . "suffix" "hub-api-signed-images") }}
|
||||
*/ -}}
|
||||
{{- define "hub.kyverno.name" -}}
|
||||
{{- printf "%s-%s-%s" .root.Release.Namespace .root.Release.Name .suffix | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- /*
|
||||
hub.kyverno.labels: common labels for every policy.
|
||||
*/ -}}
|
||||
{{- define "hub.kyverno.labels" -}}
|
||||
app.kubernetes.io/name: hub
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: kyverno-policy
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version }}
|
||||
{{- end -}}
|
||||
|
||||
{{- /*
|
||||
hub.kyverno.spec: policy-wide settings; a policy's own values override the
|
||||
imageVerification defaults (validationFailureAction, failurePolicy).
|
||||
*/ -}}
|
||||
{{- define "hub.kyverno.spec" -}}
|
||||
{{- $iv := .root.Values.imageVerification -}}
|
||||
{{- $policy := index $iv.policies .policy -}}
|
||||
{{- $action := $policy.validationFailureAction | default $iv.validationFailureAction -}}
|
||||
{{- $failure := $policy.failurePolicy | default $iv.failurePolicy -}}
|
||||
{{- if not (has $action (list "Audit" "Enforce")) -}}
|
||||
{{- fail (printf "imageVerification.policies.%s.validationFailureAction must be Audit or Enforce" .policy) -}}
|
||||
{{- end -}}
|
||||
{{- if not (has $failure (list "Ignore" "Fail")) -}}
|
||||
{{- fail (printf "imageVerification.policies.%s.failurePolicy must be Ignore or Fail" .policy) -}}
|
||||
{{- end -}}
|
||||
validationFailureAction: {{ $action }}
|
||||
background: true
|
||||
failurePolicy: {{ $failure }}
|
||||
webhookTimeoutSeconds: {{ $iv.webhookTimeoutSeconds | default 30 }}
|
||||
{{- end -}}
|
||||
|
||||
{{- /*
|
||||
hub.kyverno.signedBy: keyless cosign attestor for an image released by the
|
||||
UUG.AI release workflow for GitHub repository <githubOrganization>/<repository>.
|
||||
The signer identity is shared by every UUG.AI repository; the repository claim
|
||||
binds the signature to this image's repository.
|
||||
Usage: {{- include "hub.kyverno.signedBy" (dict "root" . "repository" "hub-api") | nindent 12 }}
|
||||
*/ -}}
|
||||
{{- define "hub.kyverno.signedBy" -}}
|
||||
{{- $iv := .root.Values.imageVerification -}}
|
||||
- entries:
|
||||
- keyless:
|
||||
issuer: {{ $iv.issuer | quote }}
|
||||
subjectRegExp: {{ $iv.subjectRegExp | squote }}
|
||||
additionalExtensions:
|
||||
githubWorkflowRepository: {{ printf "%s/%s" $iv.githubOrganization .repository | quote }}
|
||||
rekor:
|
||||
url: {{ $iv.rekorUrl | quote }}
|
||||
{{- end -}}
|
||||
@@ -0,0 +1,46 @@
|
||||
{{- /*
|
||||
hub-api images must be signed by the UUG.AI release workflow for uug-ai/hub-api.
|
||||
Values: imageVerification.policies.hubApi (defaults from imageVerification).
|
||||
To add another image, copy this file, change the image and repository, and add
|
||||
a policies.<name> entry in values.yaml.
|
||||
*/ -}}
|
||||
{{- if eq (include "hub.kyverno.enabled" (dict "root" . "policy" "hubApi")) "true" }}
|
||||
{{- $iv := .Values.imageVerification }}
|
||||
{{- $policy := $iv.policies.hubApi }}
|
||||
{{- $mutateDigest := ternary $policy.mutateDigest $iv.mutateDigest (hasKey $policy "mutateDigest") }}
|
||||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: {{ include "hub.kyverno.name" (dict "root" . "suffix" "hub-api-signed-images") }}
|
||||
labels:
|
||||
{{- include "hub.kyverno.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
policies.kyverno.io/title: hub-api images must be signed by UUG.AI
|
||||
policies.kyverno.io/category: Supply chain
|
||||
policies.kyverno.io/severity: high
|
||||
policies.kyverno.io/subject: Pod
|
||||
policies.kyverno.io/description: >-
|
||||
Verifies that hub-api images in namespace {{ .Release.Namespace }} carry a
|
||||
keyless cosign signature made by the UUG.AI release workflow for the
|
||||
uug-ai/hub-api repository.
|
||||
spec:
|
||||
{{- include "hub.kyverno.spec" (dict "root" . "policy" "hubApi") | nindent 2 }}
|
||||
rules:
|
||||
- name: verify-hub-api
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- Pod
|
||||
namespaces:
|
||||
- {{ .Release.Namespace | quote }}
|
||||
verifyImages:
|
||||
- imageReferences:
|
||||
- {{ printf "%s/hub-api:*" $iv.registry | quote }}
|
||||
- {{ printf "%s/hub-api@*" $iv.registry | quote }}
|
||||
required: true
|
||||
mutateDigest: {{ $mutateDigest }}
|
||||
verifyDigest: {{ $mutateDigest }}
|
||||
attestors:
|
||||
{{- include "hub.kyverno.signedBy" (dict "root" . "repository" "hub-api") | nindent 12 }}
|
||||
{{- end }}
|
||||
@@ -25,11 +25,11 @@
|
||||
"imageVerification": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Kyverno ClusterPolicy that verifies the keyless cosign signatures of UUG.AI images. Rendered only when the cluster serves kyverno.io/v1.",
|
||||
"description": "Kyverno ClusterPolicies (templates/kyverno/) that verify the keyless cosign signatures of UUG.AI images. Rendered only when the cluster serves kyverno.io/v1.",
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"description": "Create the policy when Kyverno is installed."
|
||||
"description": "Create the policies when Kyverno is installed."
|
||||
},
|
||||
"validationFailureAction": {
|
||||
"type": "string",
|
||||
@@ -37,7 +37,7 @@
|
||||
"Audit",
|
||||
"Enforce"
|
||||
],
|
||||
"description": "Audit reports violations; Enforce rejects pods with unsigned images."
|
||||
"description": "Default for every policy: Audit reports violations; Enforce rejects pods with unsigned images."
|
||||
},
|
||||
"failurePolicy": {
|
||||
"type": "string",
|
||||
@@ -45,7 +45,7 @@
|
||||
"Ignore",
|
||||
"Fail"
|
||||
],
|
||||
"description": "Webhook behaviour when Kyverno is unavailable."
|
||||
"description": "Default webhook behaviour when Kyverno is unavailable."
|
||||
},
|
||||
"webhookTimeoutSeconds": {
|
||||
"type": "integer",
|
||||
@@ -54,7 +54,7 @@
|
||||
},
|
||||
"mutateDigest": {
|
||||
"type": "boolean",
|
||||
"description": "Rewrite verified tags to digests and require digests."
|
||||
"description": "Default: rewrite verified tags to digests and require digests."
|
||||
},
|
||||
"registry": {
|
||||
"type": "string",
|
||||
@@ -78,23 +78,36 @@
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"images": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"policies": {
|
||||
"type": "object",
|
||||
"description": "One entry per policy template in templates/kyverno/.",
|
||||
"additionalProperties": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9][a-z0-9._-]*$"
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"description": "Render this policy (templates/kyverno/<file>)."
|
||||
},
|
||||
"githubRepository": {
|
||||
"validationFailureAction": {
|
||||
"type": "string",
|
||||
"pattern": "^[A-Za-z0-9._-]+$"
|
||||
"enum": [
|
||||
"Audit",
|
||||
"Enforce"
|
||||
],
|
||||
"description": "Overrides imageVerification.validationFailureAction for this policy."
|
||||
},
|
||||
"failurePolicy": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Ignore",
|
||||
"Fail"
|
||||
],
|
||||
"description": "Overrides imageVerification.failurePolicy for this policy."
|
||||
},
|
||||
"mutateDigest": {
|
||||
"type": "boolean",
|
||||
"description": "Overrides imageVerification.mutateDigest for this policy."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
-10
@@ -28,13 +28,16 @@ mode: "all"
|
||||
###########################################################################
|
||||
# Image signature verification (Kyverno)
|
||||
###########################################################################
|
||||
# Creates a Kyverno ClusterPolicy, scoped to the release namespace, that checks
|
||||
# the keyless cosign signatures of UUG.AI images: signed by GitHub Actions, by
|
||||
# the UUG.AI release workflow, for the image's own uug-ai GitHub repository.
|
||||
# Rendered only when Kyverno is installed (the cluster serves kyverno.io/v1);
|
||||
# without Kyverno nothing is created.
|
||||
# Kyverno ClusterPolicies, scoped to the release namespace, that check the
|
||||
# keyless cosign signatures of UUG.AI images: signed by GitHub Actions, by the
|
||||
# UUG.AI release workflow, for the image's own uug-ai GitHub repository.
|
||||
# Each policy is its own template in templates/kyverno/. They are rendered only
|
||||
# when Kyverno is installed (the cluster serves kyverno.io/v1); without Kyverno
|
||||
# nothing is created.
|
||||
imageVerification:
|
||||
enabled: true
|
||||
# Defaults for every policy; a policy under `policies` may override
|
||||
# validationFailureAction, failurePolicy and mutateDigest.
|
||||
# Audit reports unsigned images (PolicyReports) without blocking them;
|
||||
# Enforce rejects pods with an unsigned or wrongly signed image.
|
||||
validationFailureAction: Audit
|
||||
@@ -53,11 +56,16 @@ imageVerification:
|
||||
# Signer: the shared UUG.AI release workflow, at a branch/tag ref or a commit.
|
||||
subjectRegExp: '^https://github\.com/uug-ai/workflows/\.github/workflows/release-create\.yml@(refs/.+|[0-9a-f]{40})$'
|
||||
rekorUrl: https://rekor.sigstore.dev
|
||||
# Images to verify, by repository name under `registry`. githubRepository
|
||||
# defaults to the name. Only images whose releases are signed belong here;
|
||||
# more are added as their release pipelines start signing.
|
||||
images:
|
||||
- name: hub-api
|
||||
# One entry per policy template in templates/kyverno/. Only images whose
|
||||
# releases are signed have a policy; more are added as their release
|
||||
# pipelines start signing.
|
||||
policies:
|
||||
# templates/kyverno/hub-api-signed-images.yaml
|
||||
hubApi:
|
||||
enabled: true
|
||||
# validationFailureAction: Enforce
|
||||
# failurePolicy: Fail
|
||||
# mutateDigest: true
|
||||
###########################################################################
|
||||
# Global configuration
|
||||
###########################################################################
|
||||
|
||||
Reference in New Issue
Block a user