Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Infrastructure as Code By James Joyner IV · · 8 min read

Kyverno: Policy-as-Code for Kubernetes Without Learning Rego

Kyverno writes Kubernetes admission policies in plain YAML — no new query language. Here's how to validate, mutate, and generate resources to keep clusters sane.

  • #iac
  • #kyverno
  • #kubernetes
  • #policy-as-code
  • #security
  • #governance

Policy-as-code for Kubernetes used to mean learning Rego, the query language behind OPA. Rego is powerful, but it’s a genuinely new mental model, and asking every platform engineer to learn a logic-programming language just to enforce “all pods need resource limits” is a hard sell. Kyverno’s bet is simpler: write policies in the same YAML you already use for everything else in Kubernetes.

I’ve rolled out both OPA/Gatekeeper and Kyverno on clusters, and for teams whose policies are mostly about Kubernetes resources themselves, Kyverno is usually the faster path to “we have guardrails now.” Here’s how it works.

How Kyverno fits in

Kyverno runs as a Kubernetes admission controller. Every time someone creates or updates a resource, the API server calls Kyverno, which checks the resource against your policies and can validate (allow/deny), mutate (modify it), or generate (create related resources). Because policies are CRDs, they live in git and deploy like any other manifest. No external language, no separate policy bundle format.

Validation: the bread and butter

Most policies start as validation rules — reject resources that don’t meet a standard. Here’s “every pod must set CPU and memory requests”:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-resource-requests
spec:
  validationFailureAction: Enforce
  rules:
    - name: check-requests
      match:
        any:
          - resources:
              kinds: ["Pod"]
      validate:
        message: "CPU and memory requests are required."
        pattern:
          spec:
            containers:
              - resources:
                  requests:
                    memory: "?*"
                    cpu: "?*"

The pattern block reads almost like the resource it’s checking — "?*" just means “any non-empty value.” Anyone who can read a pod spec can read this policy, which is the entire point. Set validationFailureAction: Audit first to log violations without blocking, then flip to Enforce once you’ve confirmed nothing legitimate breaks.

Mutation: fix it instead of rejecting it

Rejecting bad resources creates friction. Often you’d rather quietly correct them. Mutation policies patch resources on admission:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: add-default-securitycontext
spec:
  rules:
    - name: set-runasnonroot
      match:
        any:
          - resources:
              kinds: ["Pod"]
      mutate:
        patchStrategicMerge:
          spec:
            securityContext:
              runAsNonRoot: true

Now every pod gets runAsNonRoot: true injected automatically, whether the author remembered it or not. Mutation is fantastic for applying org-wide defaults — labels, security contexts, image pull policies — without nagging developers about boilerplate they shouldn’t have to think about.

Generation: create the resources teams always forget

The generate rule is Kyverno’s standout feature. When a resource appears, Kyverno can create other resources in response. Classic use: every new namespace automatically gets a default NetworkPolicy and a resource quota:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: default-network-policy
spec:
  rules:
    - name: deny-all-by-default
      match:
        any:
          - resources:
              kinds: ["Namespace"]
      generate:
        apiVersion: networking.k8s.io/v1
        kind: NetworkPolicy
        name: default-deny
        namespace: "{{request.object.metadata.name}}"
        synchronize: true
        data:
          spec:
            podSelector: {}
            policyTypes: ["Ingress", "Egress"]

With synchronize: true, Kyverno keeps the generated resource in sync — if someone deletes the NetworkPolicy, it comes back. This closes the gap where new namespaces silently ship without baseline security controls because someone forgot the boilerplate.

Test policies before they block production

The dangerous failure mode is a policy that blocks legitimate deployments at 3pm on a Friday. Kyverno has a CLI for testing policies against sample resources in CI:

kyverno apply require-resource-requests.yaml \
  --resource sample-deployment.yaml

You can also write declarative test cases asserting which resources should pass and fail, and run them in your pipeline. Always run policies in Audit mode in production first. Watch the policy reports for a week, confirm the only violations are genuinely bad resources, then switch to Enforce. Skipping this step is how you turn a governance win into an incident.

Policy reports: visibility without enforcement

Kyverno generates PolicyReport resources summarizing pass/fail across the cluster:

kubectl get policyreport -A

This is gold for compliance and for the rollout phase — you get a cluster-wide view of what would be blocked before you block anything. It also means an auditor can see your enforcement posture without you building a dashboard.

Kyverno vs OPA/Gatekeeper, briefly

Pick Kyverno when your policies are mostly about Kubernetes resources and you want low learning cost, mutation, and generation out of the box. Reach for OPA/Gatekeeper when you need Rego’s expressiveness for complex cross-resource logic, or you’re already running OPA elsewhere and want one policy language across CI, Terraform, and Kubernetes. They’re not mutually exclusive — plenty of clusters run both. We cover the OPA side separately in our IaC policy guides.

Where AI helps

Kyverno’s YAML is approachable, but the exact match/validate/mutate structure and JMESPath expressions in {{ }} blocks still take reference-checking. AI smooths that.

  • Drafting a policy from a sentence. “Write a Kyverno policy that denies images not from our private registry” gets you a solid starting point.
  • Converting a Gatekeeper/Rego constraint to Kyverno, when you’re migrating — the model maps the intent to Kyverno’s pattern syntax well.
  • Explaining a policy report failure. Paste the report entry and the offending resource, and the model pinpoints which rule tripped and why.

Verify everything with kyverno apply against real samples — the model can invent JMESPath functions or get a context variable slightly wrong. We maintain a set of IaC prompts for policy authoring.

The bottom line

Kyverno makes Kubernetes guardrails accessible to anyone who can read YAML. Validate to enforce standards, mutate to apply defaults painlessly, generate to stop new namespaces from shipping insecure, and roll everything out in Audit mode first. For most teams, that’s the fastest route from “the cluster is the Wild West” to “we have real, version-controlled policy” — without anyone having to learn a new language to get there.

AI-generated Kyverno policies are assistive, not authoritative. Always run them in Audit mode and test against real resources before enforcing in production.

Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.