ADR-022: Kyverno guard rails, checked before merge and enforced in the cluster
Status: Accepted Date: 2026-10-07 Builds on: ADR-017 (the GitOps repo generates every manifest), ADR-020/021 (addons)
Context
Section titled “Context”render.py produces hardened manifests (non-root numeric user, read-only filesystem, dropped capabilities, resource limits), but nothing stops a hand-edited manifest, a third-party chart or a mistaken services.yaml from deploying something weaker, and nothing says so before merge. We want the platform’s own conventions to be policy.
Decision
Section titled “Decision”- Opt-in per application. A
policies:section inapp.yamlrenders one Kyverno policy per environment (policies: {}= defaults). It is opt-in because it makes Kyverno a cluster prerequisite; existing repos that update their template are unaffected. - CEL-based
NamespacedValidatingPolicy(policies.kyverno.io/v1), not the classicPolicy: Kyverno 1.19 markskyverno.io/v1 Policydeprecated and recommends the CEL types (verified on a live cluster). The policy lives in the environment’s namespace (<app>-<env>), so several products can share a cluster, and targets Deployments only (the manifests we render; operator-managed pods such as the database are out of scope). - Rules (the platform’s conventions): numeric non-root user,
readOnlyRootFilesystem, no privilege escalation and all capabilities dropped, no privileged containers / host namespaces /hostPath, CPU and memory requests plus a memory limit, theapp.kubernetes.io/part-oflabel, images only from allowed registries, and no:latestor untagged image outside dev. Allowed registries are derived from the services’ ownimagefields, plus the addon images (otel/for the collector) andpolicies.registries. - Mode per environment:
Audit(report),Enforce(deny) orOff; defaults Audit in dev and staging, Enforce in prod. Synced by<app>-policies-<env>ApplicationSets (pruned). - Shift-left:
devbox run validate(and CI) runsscripts/check-policies.sh: every service overlay and addon of an environment is built with kustomize and evaluated offline with the Kyverno CLI (kyverno@1.19.0in devbox). A violation fails the pull request in every mode, so Audit environments do not accumulate violations. Because the check evaluates the kustomize output, an environment that still runs:latestaftercomposefails until/gitops:promotepins a tag. - Operator:
cluster-upinstalls Kyverno (chart 3.9.1) whenpolicies:is present; real clusters install it themselves.doctorchecks for the CRDs.
Not included
Section titled “Not included”Policies for pods created by operators (CloudNativePG), image signature verification (revisit with signing, ADR-019), mutating/generating policies, exceptions management and a PolicyReport summary in cplat status.