Skip to content

Admission policies

Every Kyverno policy in the repository, wherever it lives: the kyverno component's own policies and the ones storage components ship to describe their classes. Deny blocks the apply; Warn records an audit warning and lets it through, so a warn-only rule is invisible until something goes wrong; Mutate changes the object on the way in; Delete runs on a schedule against objects that already exist.

Policy Applies to Effect Shipped by
cleanup-cnpg-backups backups Delete on schedule 17 3 * * * platform-storage
generate-flux-reconciler namespaces Generate platform-security
generate-group-rolebindings namespaces Generate platform-security
mutate-configmap-autoreload deployments, statefulsets Mutate platform-security
mutate-nfs-pvc-alert-exclusion persistentvolumeclaims Mutate platform-storage
require-resource-requests pods Warn platform-security
validate-flux-role-labels namespaces Deny platform-security
validate-group-labels namespaces Deny platform-security
validate-helm-chart-version helmreleases Deny platform-security
validate-ingress-contract ingresses Deny platform-security
validate-nfs-k8up-annotations persistentvolumeclaims, persistentvolumes Warn platform-storage
validate-pdb-drain-safety poddisruptionbudgets Warn platform-security
validate-reconciler-sa-usage pods Deny platform-security
validate-roaming-volume-size persistentvolumeclaims Deny platform-storage

cleanup-cnpg-backups

Kind DeletingPolicy
Applies to backups
Effect Delete on schedule 17 3 * * *
Shipped by platform-storage
Source k8s/platform/storage/cnpg-system/policies/cleanup-backups.yaml

Deletes only objects matching all of:

  • scheduled-backup
  • terminal-phase
  • older-than-retention-window

generate-flux-reconciler

Kind GeneratingPolicy
Applies to namespaces
On CREATE, UPDATE
Effect Generate
Only when object.metadata.?labels.orValue({}).exists(k, k == "flux.rbac.thaum.xyz/role")
Shipped by platform-security
Source k8s/platform/security/kyverno/policies/generate-flux-reconciler.yaml

generate-group-rolebindings

Kind GeneratingPolicy
Applies to namespaces
On CREATE, UPDATE
Effect Generate
Only when object.metadata.?labels.orValue({}).exists(k, k.startsWith("group.rbac.thaum.xyz/"))
Shipped by platform-security
Source k8s/platform/security/kyverno/policies/generate-group-rolebindings.yaml

mutate-configmap-autoreload

Kind MutatingPolicy
Applies to deployments, statefulsets
On CREATE, UPDATE
Effect Mutate
failurePolicy Ignore — a policy error skips the rule silently
Only when has(object.metadata.annotations) && object.metadata.annotations.exists(k, k == "autoreloader.thaum.xyz/configmap")
Shipped by platform-security
Source k8s/platform/security/kyverno/policies/mutate-configmap-autoreload.yaml

mutate-nfs-pvc-alert-exclusion

Kind MutatingPolicy
Applies to persistentvolumeclaims
On CREATE, UPDATE
Effect Mutate
failurePolicy Fail
Only when object.spec.?storageClassName.orValue("") == "unifi-nas"
Shipped by platform-storage
Source k8s/platform/storage/csi-nfs/mutatingpolicy.yaml

require-resource-requests

Kind ValidatingPolicy
Applies to pods
On CREATE
Effect Warn
failurePolicy Fail
Shipped by platform-security
Source k8s/platform/security/kyverno/policies/require-resource-requests.yaml

Rules enforced:

  • All regular and init containers should set CPU and memory requests.

validate-flux-role-labels

Kind ValidatingPolicy
Applies to namespaces
On CREATE, UPDATE
Effect Deny
failurePolicy Fail
Only when object.metadata.?labels.orValue({}).exists(k, k == "flux.rbac.thaum.xyz/role")
Shipped by platform-security
Source k8s/platform/security/kyverno/policies/validate-flux-role-labels.yaml

Rules enforced:

  • A flux.rbac.thaum.xyz/role label must name a ClusterRole the Kyverno background controller is allowed to bind -- currently only "cluster-admin". It grants that role to this namespace's flux-reconciler ServiceAccount through a RoleBinding, which confers only its namespaced rules and only here, so it can never reach outside this namespace. A namespace whose Flux objects install cluster-scoped resources cannot use this label at all; it belongs in k8s/namespaces// with a hand-written ClusterRoleBinding.

validate-group-labels

Kind ValidatingPolicy
Applies to namespaces
On CREATE, UPDATE
Effect Deny
failurePolicy Fail
Only when object.metadata.?labels.orValue({}).exists(k, k.startsWith("group.rbac.thaum.xyz/"))
Shipped by platform-security
Source k8s/platform/security/kyverno/policies/validate-group-labels.yaml

Rules enforced:

  • A group.rbac.thaum.xyz/ label must have the value "edit" or "view". It grants the pocket-id group oidc:k8s:group: that ClusterRole in this namespace; the group name comes from the label key, never from the value.

validate-helm-chart-version

Kind ValidatingPolicy
Applies to helmreleases
On CREATE, UPDATE
Effect Deny
failurePolicy Fail
Shipped by platform-security
Source k8s/platform/security/kyverno/policies/validate-helm-chart-version.yaml

Rules enforced:

  • HelmRelease chart versions must be pinned to an exact semantic version.

validate-ingress-contract

Kind ValidatingPolicy
Applies to ingresses
On CREATE, UPDATE
Effect Deny
failurePolicy Fail
Shipped by platform-security
Source k8s/platform/security/kyverno/policies/validate-ingress-contract.yaml

Rules enforced:

  • Ingress class must be public, private, or cloudflare.
  • The deprecated kubernetes.io/ingress.class annotation is not allowed; use spec.ingressClassName.
  • Public and private Ingresses must configure TLS.
  • Public and private Ingresses must use an approved cert-manager ClusterIssuer.
  • Every Ingress TLS entry must specify a Secret name.

validate-nfs-k8up-annotations

Kind ValidatingPolicy
Applies to persistentvolumeclaims, persistentvolumes
On CREATE, UPDATE
Effect Warn
failurePolicy Ignore — a policy error skips the rule silently
Only when object.spec.?storageClassName.orValue("") == "unifi-nas"
Shipped by platform-storage
Source k8s/platform/storage/csi-nfs/validatingpolicy.yaml

Rules enforced:

  • k8up.io/* annotations do not belong on unifi-nas. The class provisions each claim as a subdirectory of the NAS's own k8snfscsi share, which the UNAS already backs up offsite nightly, so a K8up backup here reads the NAS to write a restic repository back onto the same disk. Leave the claim unannotated, or move it to piraeus-r2 and back it up there.

validate-pdb-drain-safety

Kind ValidatingPolicy
Applies to poddisruptionbudgets
On CREATE, UPDATE
Effect Warn
failurePolicy Fail
Only when !object.metadata.?ownerReferences.orValue([]).exists( owner, owner.kind == "Cluster" && owner.apiVersion.startsWith("postgresql.cnpg.io/") )
Shipped by platform-security
Source k8s/platform/security/kyverno/policies/validate-pdb-drain-safety.yaml

Rules enforced:

  • PodDisruptionBudgets must use maxUnavailable so the disruption allowance follows changes to the workload replica count.
  • maxUnavailable must permit at least one voluntary disruption.
  • unhealthyPodEvictionPolicy must be AlwaysAllow so an unhealthy Pod does not indefinitely block a node drain.
  • PodDisruptionBudget selectors must not be empty because policy/v1 empty selectors match every Pod in the namespace.

validate-reconciler-sa-usage

Kind ValidatingPolicy
Applies to pods
On CREATE
Effect Deny
failurePolicy Fail
Shipped by platform-security
Source k8s/platform/security/kyverno/policies/validate-reconciler-sa-usage.yaml

Rules enforced:

  • The flux-reconciler ServiceAccount is the identity Flux impersonates to reconcile this namespace, not one a workload may run as; it is privileged by construction. Give the Pod its own ServiceAccount and grant that what it needs.

validate-roaming-volume-size

Kind ValidatingPolicy
Applies to persistentvolumeclaims
On CREATE, UPDATE
Effect Deny
failurePolicy Fail
Only when object.spec.?storageClassName.orValue("") == "piraeus-r2-roaming"
Shipped by platform-storage
Source k8s/platform/storage/piraeus-datastore/validatingpolicy.yaml

Rules enforced:

  • PersistentVolumeClaims on piraeus-r2-roaming are limited to 32Gi, because the volume is resynced across the node network every time its Pod moves to a node without a replica. Use piraeus-r2 for larger volumes; it pins the Pod to a replica instead.