“Always set resource limits.” “Never pull latest in production.” “Every workload needs an owner label.” Every organisation has this list, and every organisation discovers it was optional the day something without limits evicts the thing that mattered.

Policy as code makes the cluster enforce the list. An admission controller inspects every object before it is persisted and rejects it, mutates it, or records a violation. The rules live in Git and are reviewed like everything else.

Kyverno, if you’re on Kubernetes

Kyverno writes policies as Kubernetes resources — YAML matching YAML, no new language. It graduated in the CNCF in 2026 and is the shortest path from “we should enforce this” to it being enforced.

  helm repo add kyverno https://kyverno.github.io/kyverno
helm install kyverno kyverno/kyverno -n kyverno --create-namespace
  
  apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-resource-limits
spec:
  validationFailureAction: Audit        # start here, switch to Enforce later
  rules:
    - name: check-limits
      match:
        any:
          - resources:
              kinds: [Pod]
      validate:
        message: "Every container needs CPU and memory limits."
        pattern:
          spec:
            containers:
              - resources:
                  limits:
                    memory: "?*"
                    cpu: "?*"
  

Kyverno also mutates — adding a default label, injecting a sidecar, setting imagePullPolicy — and generates, creating a NetworkPolicy or a ConfigMap whenever a namespace appears. That last one quietly removes a lot of onboarding toil.

OPA and Gatekeeper, if policy is bigger than the cluster

Open Policy Agent is a general policy engine with its own language, Rego, and Gatekeeper is its Kubernetes admission controller. Rego is harder than YAML, and it buys you one thing worth having: the same engine and the same policies across Kubernetes, Terraform plans, CI pipelines, and application authorisation.

Rough rule: Kyverno if the policies are about Kubernetes objects, OPA if you need one policy language across several systems, and if you’re unsure, Kyverno — you can add OPA later for the cases it doesn’t cover.

Audit first, always

The one deployment mistake that matters here is enforcing on day one. A deny policy on a live cluster breaks deployments that were fine yesterday, and the fastest fix anyone finds is deleting the policy.

  1. Run every new policy in Audit mode and read the report for a week.
  2. Fix the workloads it flags, or add explicit exclusions with a reason.
  3. Switch to Enforce, starting with the least critical namespace.
  4. Leave a documented exception path — kube-system and some operators legitimately need things your policy forbids.

What’s worth enforcing first

PolicyPrevents
Resource requests and limits requiredOne workload starving a node
No :latest tags“It worked yesterday” with no way to say what changed
Required labels (owner, team)Nobody knowing whose thing broke
No privileged containers, no hostPathThe obvious container escapes
Images from approved registries onlyAn unreviewed image reaching production

Pair this with Trivy in CI: scanning catches the vulnerable image before it ships, admission control catches whatever reaches the cluster anyway.

Next

To automate the deploy itself → GitHub Actions

Last updated 25 Aug 2026, 00:00 UTC. history