Understanding Kyverno Policies: Export, Apply, and Enforce Kubernetes Security

Apr 13, 2026 posted by Ilman Iqbal

Kubernetes lets you deploy and manage containers at scale, but out of the box it won't stop you from doing risky things — like running containers with the latest tag or deploying into the default namespace. There are no built-in guardrails.

Kyverno fixes that. It's a policy engine built for Kubernetes that lets you write rules as plain YAML — no new language to learn — that automatically check, modify, or even create resources whenever someone runs kubectl apply.

In this guide, we'll take a real policy — one that blocks the latest image tag — and walk through every step: exporting it from a live cluster, cleaning it up, applying it to a fresh environment, and testing that it actually works.

What are Kyverno Policies?

A Kyverno policy is just a Kubernetes resource (a YAML file you kubectl apply) that describes a rule you want enforced. Policies can do three things:

There are two scopes:

Listing Existing Policies

To see policies in your cluster:

kubectl get cpol -n kyverno --context my-cluster-aks

Example output:

NAME                               READY   AGE
check-ingress-annotation           True    50d
deploy-cdc-sync-to-app-namespaces  True    49d
disallow-default-namespace         True    50d
disallow-latest-tag                True    50d

Some example policies:

Exporting Policies

Export all policies

kubectl get cpol -n kyverno --context my-cluster-aks -o yaml > kyverno-cluster-policies.yaml

Export a single policy

kubectl get cpol disallow-latest-tag -n kyverno --context my-cluster-aks -o yaml > disallow-latest-tag-policy.yaml

Cleaning the YAML

Exported YAML contains runtime metadata that must be removed before reapplying.

Remove fields like:

metadata:
  annotations:
  creationTimestamp:
  resourceVersion:
  uid:
  managedFields:
  generation:
status:

Note: The status section must always be removed. It contains runtime data and will cause apply errors.

Final Clean Policy

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: disallow-latest-tag
spec:
  validationFailureAction: Enforce
  rules:
    - name: require-image-tag
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        message: An image tag is required.
        pattern:
          spec:
            containers:
              - image: "*:*"

    - name: validate-image-tag
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        message: Using 'latest' is not allowed.
        pattern:
          spec:
            containers:
              - image: "!*:latest"

What This Policy Does

❌ Not allowed:

image: nginx:latest
image: nginx

✅ Allowed:

image: nginx:1.25.3

Applying the Policy

Apply this policy to your cluster:

kubectl apply -f disallow-latest-tag-policy.yaml --context k3d-user-management-local

No Kyverno? You'll Get an Error

If Kyverno is not installed in this cluster, the command above will fail with:

error: resource mapping not found for name: "disallow-latest-tag" namespace: ""
from "disallow-latest-tag-policy.yaml": no matches for kind "ClusterPolicy" in version "kyverno.io/v1"
ensure CRDs are installed first

This happens because Kyverno is not installed in this cluster. Kubernetes only understands built-in resources like Pod, Deployment, and Service. But ClusterPolicy is a Custom Resource (CRD) provided by Kyverno. No Kyverno = No CRD = error.

Installing Kyverno in k3d

First, add the Kyverno Helm repo:

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

Then switch your kubectl context. Helm does not support --context in helm install, so you need to switch first:

kubectl config use-context k3d-user-management-local

Now install Kyverno:

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

Wait Until Ready

kubectl get pods -n kyverno

Verify CRDs Exist

kubectl get crds | grep kyverno

You should see:

clusterpolicies.kyverno.io
policies.kyverno.io

Apply Your Policy Again

kubectl apply -f disallow-latest-tag-policy.yaml

Quick Sanity Check

kubectl get cpol

If this returns your policy, Kyverno is installed correctly and the policy is active.

Testing the Policy

1. Create a Bad Pod

Create a file called bad-pod.yaml with the following contents:

apiVersion: v1
kind: Pod
metadata:
  name: bad-pod
spec:
  containers:
    - name: nginx
      image: nginx:latest

Apply it:

kubectl apply -f bad-pod.yaml

Kyverno blocks it. You'll see an error like this:

Error from server: error when creating "bad-pod.yaml": admission webhook
"validate.kyverno.svc-fail" denied the request:

resource Pod/default/bad-pod was blocked due to the following policies

disallow-latest-tag:
  validate-image-tag: 'validation error: Using a mutable image tag e.g. latest
    is not allowed. rule validate-image-tag failed at path
    /spec/containers/0/image/'

2. Create a Good Pod

Create a file called good-pod.yaml with the following contents:

apiVersion: v1
kind: Pod
metadata:
  name: good-pod
spec:
  containers:
    - name: nginx
      image: nginx:1.25

Apply it:

kubectl apply -f good-pod.yaml

This time it works:

pod/good-pod created

What Happens When Kyverno Blocks a Request?

The flow looks like this:

kubectl apply → API Server → Kyverno webhook → ❌ BLOCK

Kyverno logs the reason inside the admission controller pod. When Kyverno blocks a request, the Pod is never created, so kubectl describe pod bad-pod won't work. But you can still see what happened in two ways:

Check Kyverno Logs

kubectl logs -n kyverno deploy/kyverno-admission-controller -f

Check Kubernetes Events

kubectl get events --sort-by=.metadata.creationTimestamp

You'll see something like:

LAST SEEN   TYPE      REASON            OBJECT                              MESSAGE
13m         Warning   PolicyViolation   clusterpolicy/disallow-latest-tag   Pod default/bad-pod:
  [validate-image-tag] fail (blocked); validation error: Using a mutable image tag
  e.g. 'latest' is not allowed. rule validate-image-tag failed at path
  /spec/containers/0/image/

Disabling or Bypassing Policies

1. Switch to Audit Mode

Edit your disallow-latest-tag-policy.yaml and change the validation action:

spec:
  validationFailureAction: Audit

Then re-apply:

kubectl apply -f disallow-latest-tag-policy.yaml
clusterpolicy.kyverno.io/disallow-latest-tag configured

Now the bad pod goes through:

kubectl apply -f bad-pod.yaml
pod/bad-pod created

The policy still runs, but it only logs violations instead of blocking them.

2. Temporarily Disable All Policies

Scale down the Kyverno admission controller to stop all policy enforcement:

kubectl scale deployment kyverno-admission-controller -n kyverno --replicas=0

The cluster becomes unprotected — no policies perform any validations or blockings.

To re-enable:

kubectl scale deployment kyverno-admission-controller -n kyverno --replicas=1

3. Skip Policy via Annotation

Add this annotation to your pod YAML to bypass Kyverno for a specific resource:

metadata:
  annotations:
    policies.kyverno.io/ignore: "true"

4. Remove the Policy Completely

kubectl delete cpol disallow-latest-tag

The policy is deleted and no longer enforced.

Final Thoughts

Kyverno brings policy-as-code into Kubernetes in a very natural way. Instead of relying on external tools, you define security rules as Kubernetes resources.

In production environments, policies like disallow-latest-tag are critical to ensure immutability, traceability, and safer deployments.