Skip to content

The Edge of the Cyber World See the latest

Apps

Kyverno Kubernetes Policy Engine Setup: 13 Steps [2026]

A static scan can tell you a Terraform plan or a Dockerfile looks wrong before it ships. It cannot stop someone from running kubectl apply on a privileged pod straight into production an hour later. That gap, between “we checked it once” and “we enforce it every single time,” is what admission control exists to close, and in the Kubernetes world, the policy engine most teams reach for to close it in 2026 is Kyverno. This tutorial covers installing Kyverno, writing validate, mutate, generate, and image-verification policies, testing them in CI before they ever touch a cluster, and the errors that trip up almost every team on their first rollout.

This guide is written for platform engineers and DevOps teams who already run a Kubernetes cluster in some form, whether that’s a managed service or a self-hosted control plane, and who are past the point of trusting tribal knowledge to keep pods from running privileged or unpatched. You don’t need prior experience with Rego, OPA, or any other policy language. Kyverno’s entire design goal is that if you can already write a Kubernetes Deployment manifest, you already know most of the syntax you need to write a Kyverno policy.

Kyverno reached CNCF Graduated status on March 16, 2026, the foundation’s highest maturity tier, putting it in the same category as Kubernetes itself, Prometheus, and Envoy. The project’s GitHub repository sits at roughly 8,200 stars as of October 13, 2026. The current stable release is Kyverno v1.19.1, published September 10, 2026, which brought the newer CEL-based policy types to feature parity with Kyverno’s original YAML rule syntax. If you’ve only used static scanners up to this point, the mental model shift in this guide is the important part: Kyverno doesn’t just report problems, it sits inside the Kubernetes API request path and decides whether a resource is allowed to exist at all.

What Kyverno Actually Does, and Why It’s Different From a Scanner

Kyverno is a Kubernetes-native policy engine that runs as a dynamic admission controller. When any resource is created or updated in a cluster, the Kubernetes API server forwards that request to Kyverno’s webhook before it’s persisted. Kyverno then allows, rejects, or modifies the resource based on policies you define, all written as native Kubernetes YAML rather than a separate policy language.

Jim Bugwadia, Kyverno’s maintainer and co-founder at Nirmata, has described the project’s core premise directly: “Today we’re gonna be taking a look at Kyverno, a CNCF sandbox project that aims to bring policy management to Kubernetes clusters in a Kubernetes way,” a framing that still captures why teams pick Kyverno over a general-purpose policy language. As Bugwadia put it when explaining the design choice, “So first off, Kyverno, as you mentioned as a policy engine, it’s designed specifically for Kubernetes,” according to an interview published by Rawkode Academy.

Kyverno supports five distinct policy types, and understanding the difference matters before you write your first rule:

  • Validate: reject or report resources that fail a rule, such as a pod requesting privileged mode or missing resource limits.
  • Mutate: automatically modify incoming resources, for example injecting default labels, tolerations, or security context fields.
  • Generate: create companion resources automatically, such as a default-deny NetworkPolicy whenever a new namespace is created, or a registry pull secret.
  • Verify images (verifyImages): check image signatures and attestations before a workload using that image is allowed to run.
  • Cleanup policies: delete existing resources on a schedule according to a rule, useful for expiring stale ConfigMaps, completed Jobs, or temporary namespaces.

That breadth is the real distinction from a static scanner. A tool that checks a Terraform file or a Dockerfile for misconfigurations is auditing intent before deployment. Kyverno is enforcing reality at the moment a resource tries to exist, and it can also actively generate or repair resources rather than just flag them.

It’s worth being specific about where each layer sits in a real deployment pipeline, because teams new to admission control often assume one tool makes the others redundant. A static IaC scan runs against a Terraform plan or Helm chart before anything is applied. A container image scanner runs against the built artifact before or after it’s pushed to a registry. Kyverno runs at the moment the Kubernetes API server receives a request to create or update a resource, which is the last point before that resource actually exists in the cluster. None of the three can fully substitute for the other two, because each one is looking at a different artifact at a different point in time, and a gap in any single layer is still a gap even if the other two are airtight.

Kyverno vs OPA Gatekeeper: Picking the Right Engine

Kyverno isn’t the only Kubernetes policy engine, and the comparison with OPA Gatekeeper is the first decision most platform teams have to make. Both are CNCF projects built around the same admission-webhook model, but they differ sharply in how policies are written.

Area Kyverno OPA Gatekeeper
Policy language Kubernetes-style YAML; newer policy types also support CEL Rego, evaluated by the Open Policy Agent engine
Mutation support Native mutate rules Mutation exists but validation is the traditional focus
Resource generation Native generate rules Not the typical primary workflow
Image verification Native verifyImages policies Usually requires additional integrations
Learning curve Lower for teams already fluent in Kubernetes YAML Steeper; requires learning Rego and ConstraintTemplates
CNCF maturity Graduated (March 2026) CNCF project; verify current maturity tier directly with CNCF

Neither tool is strictly “better.” Teams already invested in Rego across other OPA-based systems, or who want one policy language spanning Kubernetes and non-Kubernetes systems, often stick with Gatekeeper. Teams who want policies to look and read like ordinary Kubernetes manifests, with native mutation and generation built in rather than bolted on, tend to land on Kyverno. This tutorial focuses on Kyverno specifically because its YAML-first syntax is usually the faster on-ramp for teams who already run Checkov or similar YAML-based IaC checks earlier in their pipeline, a workflow covered in a Checkov IaC security scanning setup.

There’s also a migration question worth raising if your cluster already runs Gatekeeper: you don’t necessarily have to choose one exclusively. Some platform teams run both during a transition period, with new policies written in Kyverno and legacy Rego constraints left in place until they’re individually ported over. Running two admission webhooks adds operational overhead and isn’t a long-term architecture most teams want, but it’s a reasonable bridge if a full cutover isn’t realistic in one release cycle. What you should avoid is writing the same logical rule in both engines simultaneously as a permanent state, since that doubles the maintenance burden every time the underlying requirement changes.

Prerequisites: Versions, Access, and What You’ll Need

Before starting the Kyverno setup, confirm the following. Missing the RBAC or cluster-access items below is the most common reason an install silently half-works.

Requirement Minimum / Recommended Why It Matters
Kubernetes cluster A supported recent release; check the v1.19.1 compatibility matrix Policy API versions and CEL support are tied to specific Kubernetes releases
Kyverno version v1.19.1 (released September 10, 2026) or later Older releases lack CEL-based policy parity introduced in this release
kubectl Matching your cluster’s minor version Needed to apply policies and inspect admission results
Helm Helm 3.x Helm is the documented, recommended production install method
Cluster admin RBAC Permission to create namespaces, CRDs, and webhook configurations Kyverno installs its own namespace, CRDs, and admission webhooks
Admission controller capacity At least 2-3 replicas for production A single replica becomes a single point of failure for every admission request
Kyverno CLI (optional) Latest release matching your cluster version Required for testing policies against manifests before deployment

Step 1: Install Kyverno With Helm

Kyverno’s own documentation identifies Helm as the recommended, flexible production installation method, and it should run in its own dedicated namespace rather than alongside unrelated workloads or inside kube-system. Add the Helm repository first:

helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update

Then install Kyverno into its own namespace:

helm install kyverno kyverno/kyverno 
  --namespace kyverno 
  --create-namespace

Jim Bugwadia confirmed this is the project’s own recommended on-ramp, noting in the same Rawkode Academy interview, “Yes, so there is a Helm chart too in our quick start.” For a production cluster, run multiple admission-controller replicas from the start rather than retrofitting high availability later:

helm upgrade --install kyverno kyverno/kyverno 
  --namespace kyverno 
  --create-namespace 
  --set admissionController.replicas=3

Kyverno’s own documentation is explicit that only YAML from tagged Kyverno releases is supported, so avoid applying manifests pulled from a development branch or an unofficial mirror.

Step 2: Verify the Install and Check Component Health

Confirm every Kyverno component is running before writing a single policy:

kubectl get pods -n kyverno

Expected output shows the admission controller, background controller, cleanup controller, and reports controller all in a Running state:

NAME                                             READY   STATUS    RESTARTS   AGE
kyverno-admission-controller-6d8f9c7b4d-2xk9p    1/1     Running   0          45s
kyverno-admission-controller-6d8f9c7b4d-7mqwt    1/1     Running   0          45s
kyverno-admission-controller-6d8f9c7b4d-9rzzv    1/1     Running   0          45s
kyverno-background-controller-5b7d8f9c6-k2jhx    1/1     Running   0          45s
kyverno-cleanup-controller-7c9d6b8f5-l4mqp       1/1     Running   0          45s
kyverno-reports-controller-9f8d7c6b5-n3kwz       1/1     Running   0          45s

A healthy install should show the admission controller, background controller, cleanup controller, and reports controller each as separate deployments rather than one monolithic pod, which is intentional: Kyverno splits responsibilities so that a slow background scan or a cleanup job can’t block live admission decisions on new resources. Also confirm the admission webhooks registered correctly, since this is the piece that actually intercepts API requests:

kubectl get validatingwebhookconfigurations,mutatingwebhookconfigurations | grep kyverno

Step 3: Write Your First Validate Policy

Kyverno policies are written as native Kubernetes resources, using the ClusterPolicy kind for cluster-wide rules. Start with a baseline validate policy that rejects privileged containers, a configuration behind a meaningful share of Kubernetes container-escape and lateral-movement findings reported across 2026:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: disallow-privileged-containers
spec:
  validationFailureAction: Audit
  background: true
  rules:
    - name: disallow-privileged
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        message: "Privileged containers are not allowed."
        pattern:
          spec:
            containers:
              - securityContext:
                  =(privileged): "false"

Apply it the same way you’d apply any Kubernetes resource:

kubectl apply -f disallow-privileged-containers.yaml

Notice validationFailureAction is set to Audit, not Enforce, on purpose. The next step explains why that distinction is the single most important setting in this entire tutorial.

Step 4: Understand Audit vs Enforce Before You Go Further

validationFailureAction: Audit reports policy violations without blocking them. Resources that fail the rule are still admitted, but the violation is recorded in a PolicyReport you can inspect. validationFailureAction: Enforce blocks non-compliant resources outright, returning an admission error to whoever or whatever tried to create them.

Rolling a new policy straight to Enforce on a live cluster is one of the fastest ways to break a deployment pipeline you didn’t know depended on a now-forbidden pattern. Run every new policy in Audit mode first, review the resulting PolicyReports for a representative period, confirm nothing legitimate gets flagged, and only then flip it to Enforce:

kubectl get policyreport -A
sed -i 's/validationFailureAction: Audit/validationFailureAction: Enforce/' disallow-privileged-containers.yaml
kubectl apply -f disallow-privileged-containers.yaml

Step 5: Require Resource Limits With a Second Validate Rule

Pods with no CPU or memory limits are a recurring cause of noisy-neighbor incidents and node-level resource exhaustion. Add a second rule inside the same policy, or a separate one, requiring both:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-resource-limits
spec:
  validationFailureAction: Audit
  background: true
  rules:
    - name: require-resource-limits
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        message: "Every container must define CPU and memory limits."
        pattern:
          spec:
            containers:
              - resources:
                  limits:
                    cpu: "?*"
                    memory: "?*"

The ?* pattern matches any non-empty value, meaning the rule only confirms the field exists and isn’t blank, not that the value is reasonable for your workload. Pair this with your own organization’s sizing guidance rather than treating “a limit exists” as equivalent to “the limit is correct.”

Step 6: Require Non-Root Execution

Requiring containers to run as a non-root user is one of the highest-value, lowest-friction policies most clusters adopt early, because it meaningfully narrows what an attacker can do after compromising a single container:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-non-root
spec:
  validationFailureAction: Audit
  background: true
  rules:
    - name: require-non-root
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        message: "Containers must run as non-root."
        pattern:
          spec:
            securityContext:
              runAsNonRoot: true
            containers:
              - securityContext:
                  runAsNonRoot: true

You can combine all three rules above, privileged containers, resource limits, and non-root execution, into a single baseline ClusterPolicy once each has been validated independently in Audit mode. Writing them separately first, as shown here, makes it much easier to tell which specific rule caused a rejection if a workload gets flagged during testing, rather than debugging one large policy with three rules bundled together from the start.

Kyverno also ships an optional Pod Security Standards policy chart that implements the Kubernetes-defined Baseline and Restricted profiles without hand-writing every rule yourself, which is worth adopting once you’ve seen how your own hand-written rules behave in Audit mode, since it saves you from reinventing dozens of equivalent checks the Kubernetes community has already standardized:

helm install kyverno-policies kyverno/kyverno-policies 
  --namespace kyverno

Step 7: Write a Mutate Policy to Set Safe Defaults Automatically

Validation rejects noncompliant resources; mutation fixes them automatically before they’re admitted, which is often friendlier for developer teams who’d rather have a sane default applied than a build rejected outright. This policy adds a default toleration label to every pod missing one:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: add-default-labels
spec:
  rules:
    - name: add-team-label
      match:
        any:
          - resources:
              kinds:
                - Pod
      mutate:
        patchStrategicMerge:
          metadata:
            labels:
              +(managed-by): kyverno

The +(managed-by) syntax adds the label only if it doesn’t already exist, leaving a pod’s existing labels untouched rather than overwriting them.

Step 8: Write a Generate Policy for Default-Deny Network Policies

Namespaces with no NetworkPolicy at all default to allowing all traffic between every pod in the cluster, a gap that’s come up repeatedly in Kubernetes lateral-movement writeups. A generate policy can automatically create a default-deny NetworkPolicy the moment a new namespace is created, so teams never have to remember to add one manually:

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

With synchronize: true, Kyverno keeps the generated NetworkPolicy in sync if the source policy changes later, rather than leaving orphaned resources behind from an outdated rule.

Step 9: Verify Image Signatures With verifyImages

Supply-chain compromise, a tampered or unsigned image making it into production, is the risk category verifyImages policies exist for. This rule requires every image from a given registry to carry a valid signature before Kyverno admits a workload using it:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-signed-images
spec:
  validationFailureAction: Audit
  background: false
  rules:
    - name: verify-signature
      match:
        any:
          - resources:
              kinds:
                - Pod
      verifyImages:
        - imageReferences:
            - "registry.example.com/*"
          attestors:
            - entries:
                - keys:
                    publicKeys: |-
                      -----BEGIN PUBLIC KEY-----
                      
                      -----END PUBLIC KEY-----

This is the policy type most directly comparable to what container scanning covers from a different angle. A tool like Trivy tells you what known vulnerabilities exist inside an image before you deploy it; a Kyverno verifyImages rule tells you whether that image is actually the one your organization signed and trusts, enforced at the moment it tries to run. The two solve different problems and are worth running together rather than as alternatives.

Step 10: Test Policies in CI Before They Touch a Cluster

The Kyverno CLI applies and tests policies against manifests without needing a live cluster at all, which means you can catch a policy violation in a pull request instead of at admission time in production. Jim Bugwadia described seeing this hands-on in a Kyverno walkthrough: “15:53 Let’s see, so the first thing we need to do is just because this is all Kubernetes, it’s just apply some YAML,” a comment that applies just as well to testing a policy against a manifest as it does to applying one live.

kyverno apply disallow-privileged-containers.yaml 
  --resource deployment.yaml

For a GitOps pipeline rendering Helm charts or Kustomize overlays, render the manifests first, then run every policy against the rendered output before anything is committed:

helm template my-app ./chart > rendered.yaml
kyverno apply ./policies --resource rendered.yaml

A reasonable GitOps flow looks like this: render manifests, run kyverno apply against the output, fail the pipeline on any violation, commit only compliant manifests, let the GitOps controller sync them to the cluster, and keep live Kyverno admission enabled as the final backstop in case something slips past CI. If you’re already gating builds this way for container images or IaC, this slots directly into the same discipline covered in securing a CI/CD supply chain.

Step 11: Use Background Scanning for Resources That Already Exist

Admission control only governs new or updated requests. Every pod already running when you installed Kyverno was never evaluated by your new policies. Background scanning closes that gap by periodically evaluating existing resources and reporting violations, without retroactively blocking anything already admitted:

kubectl get policyreport -A -o wide

Treat background scan results as a remediation backlog, not an enforcement mechanism. If an existing deployment shows up as violating a new policy, you still have to update or restart it yourself; Kyverno’s background scan reports the problem, it does not fix a resource that already exists.

This is also the point where most teams discover the real size of their compliance gap for the first time. A cluster that’s been running for a year or more, with workloads deployed by different teams at different times, almost always turns up more violations in its first background scan than anyone expects, simply because nobody had a consistent way to check until now. Resist the urge to flip every flagged policy straight to Enforce the moment you see the report. Work through the backlog by priority, starting with the policies that address the most severe exposure, such as privileged containers, and treat the rest as an ongoing cleanup project rather than something to resolve in a single afternoon.

Step 12: Scope Policies by Namespace and Operation to Control Performance

A policy matching every kind, every namespace, and every operation adds admission latency to every single API request in the cluster, whether or not that request has anything to do with the rule’s intent. Scope rules narrowly:

spec:
  rules:
    - name: require-non-root
      match:
        any:
          - resources:
              kinds:
                - Pod
              namespaces:
                - production
                - staging
              operations:
                - CREATE
                - UPDATE

Restricting by namespace, kind, and operation keeps webhook evaluation fast and makes it far easier to reason about which policies actually apply to a given resource when something unexpected gets rejected. Frank Jogeleit, a Kyverno maintainer, has summarized the underlying mechanism directly: Kyverno registers inside a cluster as both a validating and a mutating admission webhook, which means every unscoped rule runs on every matching request across the entire cluster, not just the namespace you had in mind when you wrote it.

Step 13: Use Policy Exceptions Without Creating Silent Bypasses

Some workloads legitimately need to break a baseline rule, a monitoring agent that genuinely requires privileged access, for instance. Kyverno supports PolicyException resources for exactly this, but a broadly scoped exception quietly defeats the policy it’s attached to:

apiVersion: kyverno.io/v2
kind: PolicyException
metadata:
  name: allow-privileged-monitoring-agent
  namespace: monitoring
spec:
  exceptions:
    - policyName: disallow-privileged-containers
      ruleNames:
        - disallow-privileged
  match:
    any:
      - resources:
          names:
            - node-exporter-*
          namespaces:
            - monitoring

Scope every exception to a specific resource name pattern and namespace, never to an entire policy cluster-wide, and review the list of active exceptions on a recurring schedule. An exceptions list nobody revisits is how a strict baseline policy quietly becomes an optional one.

A practical habit worth adopting from day one: require every PolicyException to carry an owner annotation and a review-by date, even if Kyverno itself doesn’t enforce that convention natively. A quarterly audit that simply lists every active exception, who requested it, and whether it’s still needed catches the slow accumulation of bypasses long before it becomes a real incident. Teams that skip this step tend to discover years later that half their exceptions were for workloads that were decommissioned long ago, with nobody left who remembers why the exception existed in the first place.

5 Common Pitfalls When Rolling Out Kyverno

  • Jumping straight to Enforce. Deploying a new policy in Enforce mode before reviewing Audit-mode reports first is the single most common way teams accidentally break a working deployment pipeline.
  • Confusing background scanning with admission enforcement. A background scan reporting a violation does not mean the offending resource was blocked; it was already running before the policy existed.
  • Writing unscoped policies. A rule with no namespace, kind, or operation filter evaluates against every matching admission request cluster-wide, adding latency everywhere rather than just where you intended.
  • Treating a policy exception as a permanent fix. Exceptions accumulate quietly if nobody reviews them, and a broad exception can silently neutralize the policy it’s attached to.
  • Skipping CI-side testing entirely. Relying solely on live admission control means every policy violation is discovered at deploy time instead of in a pull request, which is slower for developers and noisier for whoever’s on call.

Troubleshooting: 8 Kyverno Errors and How to Fix Them

  • Admission webhook timeout errors on every deployment. Usually means the admission controller pods are under-resourced, overloaded, or unreachable due to a network policy blocking traffic to the Kyverno namespace. Increase replicas, CPU/memory requests, and confirm network policies allow traffic to the Kyverno service.
  • Policy applied but nothing happens. Check that match actually targets the resource kind and namespace you expect. A typo in a kind name or an overly narrow namespace list silently excludes the resources you meant to cover.
  • Resources rejected unexpectedly after enabling Enforce. This is almost always a policy that was never run in Audit mode first. Roll it back to Audit, review PolicyReports for a representative window, and only re-enable Enforce once the backlog of flagged resources is addressed.
  • Cluster-wide latency increase after adding several policies. Audit each policy’s match scope. Broad, unscoped rules running against every admission request are the most common cause of noticeable slowdown at scale.
  • Generate policy creates resources that don’t update when the source changes. Set synchronize: true on the generate rule so Kyverno keeps generated resources in sync with the source policy rather than leaving stale copies behind.
  • verifyImages policy blocks every image, including trusted ones. Confirm the attestor’s public key matches the actual signing key used, and that the imageReferences pattern matches your registry’s real image paths exactly, including any path prefixes.
  • Kyverno CLI results don’t match live admission behavior. The CLI evaluates policies statically against manifests and may not account for cluster-side context like existing resources or live mutation ordering. Treat CLI testing as a pre-flight check, not a guarantee of identical live behavior.
  • Installed in the wrong namespace or alongside unrelated workloads. Reinstall into a dedicated kyverno namespace as documented, rather than kube-system or a shared application namespace, to avoid RBAC and resource-contention issues.

Advanced Tips for Running Kyverno in Production

Once the baseline policies are stable, a few adjustments make Kyverno hold up as a cluster and policy count both grow. First, pin both Kyverno’s version and your policy manifests together, and test upgrades deliberately. Kyverno v1.19.1 introduced CEL-based policy types reaching parity with the original YAML rule syntax, and policies written against newer API types may not behave identically on an older Kyverno release.

Second, separate your baseline policies, the ones every workload must meet, from team- or application-specific policies that only apply to a subset of namespaces. Bundling everything into one sprawling ClusterPolicy makes it much harder to reason about why a specific resource was rejected.

Third, pair Kyverno’s admission-time enforcement with runtime behavioral monitoring rather than treating policy enforcement as the end of the story. A policy can stop a privileged pod from ever starting, but it can’t tell you what a process inside an already-compliant container does after it’s running, which is the gap covered by a Falco runtime security setup. The two layers, admission control and runtime detection, cover different points in a workload’s lifecycle.

Fourth, if your cluster already enforces broader hardening practices the way a Kubernetes security hardening baseline describes, treat Kyverno as the mechanism that makes those practices continuously enforced rather than a one-time setup checklist. The same logic applies to secrets: a policy requiring workloads to reference secrets through a proper mechanism complements, rather than replaces, the practices in a Kubernetes secrets management setup.

Fifth, build a dashboard or recurring report off PolicyReport data rather than relying on anyone remembering to run kubectl get policyreport -A by hand. Most teams running Kyverno at scale pipe PolicyReport results into whatever observability stack they already use for everything else, so a spike in violations shows up as an alert rather than something someone stumbles across weeks later during an unrelated investigation. The report data is already structured as Kubernetes custom resources, which makes it straightforward to query with standard Kubernetes tooling rather than needing a separate agent or exporter built specifically for Kyverno.

Complete Working Project: Baseline Security Policies for a Production Namespace

Here’s a complete, minimal policy set that exercises validate, mutate, and generate rules together, a reasonable starting baseline for a production namespace. Save each as a separate file and apply them as a set:

# 01-disallow-privileged.yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: disallow-privileged-containers
spec:
  validationFailureAction: Audit
  background: true
  rules:
    - name: disallow-privileged
      match:
        any:
          - resources:
              kinds: [Pod]
              namespaces: [production]
      validate:
        message: "Privileged containers are not allowed in production."
        pattern:
          spec:
            containers:
              - securityContext:
                  =(privileged): "false"
# 02-require-non-root.yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-non-root
spec:
  validationFailureAction: Audit
  background: true
  rules:
    - name: require-non-root
      match:
        any:
          - resources:
              kinds: [Pod]
              namespaces: [production]
      validate:
        message: "Containers must run as non-root in production."
        pattern:
          spec:
            securityContext:
              runAsNonRoot: true
# 03-generate-default-deny.yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: generate-default-deny-netpol
spec:
  rules:
    - name: default-deny
      match:
        any:
          - resources:
              kinds: [Namespace]
              names: ["production"]
      generate:
        apiVersion: networking.k8s.io/v1
        kind: NetworkPolicy
        name: default-deny-all
        namespace: production
        synchronize: true
        data:
          spec:
            podSelector: {}
            policyTypes: [Ingress, Egress]

Test the whole set against your existing manifests before applying anything live:

kyverno apply 01-disallow-privileged.yaml 02-require-non-root.yaml 03-generate-default-deny.yaml 
  --resource ./manifests/

Apply them in Audit mode, review PolicyReports for a week, fix any legitimate workload the rules flag, then flip the validate policies to Enforce one at a time rather than all at once, so you can isolate exactly which rule caused a problem if something breaks.

Once this baseline set is stable in production, the natural next step is extending it rather than leaving it static. A common second wave of policies adds image-registry allowlisting, so only images pulled from an organization’s approved registries can run at all, combined with the verifyImages signature check covered earlier. A third wave typically covers resource quotas at the namespace level, paired with the per-container resource-limit rule already in place, so a single misbehaving deployment can’t exhaust a shared cluster’s capacity. None of these need to ship on day one, but each one is a direct extension of the validate, generate, and verifyImages patterns already demonstrated in this project, which is the point of starting with a small, well-understood baseline rather than trying to write a comprehensive policy library before you’ve seen how your first three rules behave against real traffic.

Frequently Asked Questions

Is Kyverno free to use?
Yes. Kyverno is fully open source and is a CNCF Graduated project as of March 16, 2026, with no paid tier required for any policy type covered in this tutorial.

What’s the latest version of Kyverno as of October 2026?
Kyverno v1.19.1, released September 10, 2026. Always check the project’s GitHub releases page for a newer version before standardizing a cluster rollout on a pinned release.

Should I use Kyverno or OPA Gatekeeper?
Both are CNCF projects solving the same admission-control problem differently. Kyverno uses Kubernetes-native YAML (with newer CEL-based options) and has native mutation, generation, and image-verification support. Gatekeeper uses Rego and the broader OPA ecosystem. Teams already fluent in Kubernetes YAML generally find Kyverno faster to adopt; teams invested in Rego across multiple systems often prefer Gatekeeper.

Does Kyverno replace a vulnerability scanner like Trivy?
No. Kyverno enforces policy at admission time, deciding whether a resource is allowed to exist based on its configuration or image signature. It does not scan for known CVEs inside a container image’s packages, which is what a dedicated image scanner handles.

What’s the difference between Audit and Enforce mode?
Audit mode reports policy violations without blocking them, recording results in a PolicyReport. Enforce mode actively rejects noncompliant resources at admission time. Always test a new policy in Audit mode first.

Can Kyverno fix resources that already violate a new policy?
Not automatically for existing resources. Background scanning reports violations in already-running resources, but admission control only governs new or updated requests. You still need to manually update or restart any existing workload flagged by a background scan.

How do I test a Kyverno policy without applying it to a live cluster?
Use the Kyverno CLI’s apply command against a manifest file or a directory of rendered Kubernetes YAML. This lets you validate policy behavior in a CI pipeline before anything reaches a real cluster.

Why did my policy slow down the whole cluster after I added it?
Most likely the policy’s match block has no namespace, kind, or operation scoping, so it evaluates against every matching admission request cluster-wide. Narrow the match criteria to only the resources the policy is actually meant to cover.

Do I need to write every policy from scratch?
No. The Kyverno project maintains a public repository of community-contributed policies covering common security and best-practice scenarios, which is a reasonable starting point to adapt rather than writing every rule from a blank file. Review each one in Audit mode against your own workloads before adopting it, since a policy written for a different cluster’s conventions won’t always match yours exactly.

What happens if the Kyverno admission controller itself goes down?
By default, if Kyverno’s webhook becomes unreachable, Kubernetes fails open for most configurations, meaning new resources can still be admitted without policy checks, though this depends on your webhook failure-policy setting. Running multiple admission-controller replicas across different nodes is the main mitigation, since it makes a full outage far less likely than relying on a single pod.

Related Coverage

Source: Tech Insider