Skip to content

Module 4.7: Kyverno

Toolkit Track | Complexity: [MEDIUM] | Time: 35-40 minutes

Kyverno is a Kubernetes-native policy engine. Unlike OPA/Gatekeeper which uses Rego, Kyverno policies are plain YAML — no new language to learn. It can validate, mutate, and generate resources, making it a Swiss Army knife for cluster governance.

What You’ll Learn:

  • Kyverno architecture and policy model
  • Writing validate, mutate, and generate policies
  • Policy reports and audit mode
  • Kyverno CLI for CI/CD integration
  • When to choose Kyverno vs OPA/Gatekeeper

Prerequisites:


After completing this module, you will be able to:

  • Deploy Kyverno and configure admission policies for validation, mutation, and resource generation
  • Implement Kyverno policies using familiar Kubernetes patterns without learning a new policy language
  • Configure Kyverno’s image verification policies to enforce signed containers and SBOM attestations
  • Evaluate Kyverno’s Kubernetes-native approach against OPA Gatekeeper for policy management simplicity

In 2023, a fintech company pushed a Friday deploy with a root container, no resource limits, and an image tagged latest from a public registry. By Monday, cryptominers had consumed 80% of cluster CPU. Cost: $340,000 in cloud spend, a week of incident response, and a mandatory regulator audit. A single Kyverno ClusterPolicy requiring non-root containers and pinned image tags would have stopped it at the gate.

Did You Know?

  • Kyverno means “govern” in Greek. It became a CNCF Incubating project in 2022 and is one of the most popular Kubernetes policy engines.
  • Kyverno policies are pure Kubernetes resources — manage them with Argo CD or Flux without special adapters.
  • Kyverno can generate new resources automatically (NetworkPolicies, ResourceQuotas) — something OPA/Gatekeeper cannot do natively.
  • The Kyverno policy library contains 200+ ready-to-use policies covering Pod Security Standards, best practices, and multi-tenancy.

KYVERNO ARCHITECTURE
════════════════════════════════════════════════════════════════════
kubectl apply ──▶ API Server
│ Admission Webhooks
┌────────────────────────────────────────────────────────────┐
│ KYVERNO │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Validate │ │ Mutate │ │ Generate │ │
│ │ Webhook │ │ Webhook │ │ Controller│ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ ClusterPolicy / Policy (YAML) ──▶ PolicyReport (audit) │
└────────────────────────────────────────────────────────────┘
Allow, Deny, Mutate, or Generate
ActionWhat It DoesExample
ValidateBlock or audit resources that violate rulesDeny pods without resource limits
MutateModify resources before they’re storedAuto-add labels, inject sidecars
GenerateCreate new resources when triggeredNetworkPolicy when a namespace is created

Terminal window
helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update
helm install kyverno kyverno/kyverno -n kyverno --create-namespace
# Verify
kubectl get pods -n kyverno
kubectl get validatingwebhookconfigurations | grep kyverno
kubectl get mutatingwebhookconfigurations | grep kyverno

ResourceScopeUse Case
ClusterPolicyCluster-wide, all namespacesOrg-wide security baselines
PolicyNamespaced, single namespace onlyTeam-specific rules
# ClusterPolicy - applies everywhere
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-labels
# Policy - applies only in "team-alpha" namespace
apiVersion: kyverno.io/v1
kind: Policy
metadata:
name: require-labels
namespace: team-alpha

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-labels
spec:
validationFailureAction: Enforce
background: true
rules:
- name: check-labels
match:
any:
- resources:
kinds:
- Pod
validate:
message: "Labels 'app' and 'team' are required."
pattern:
metadata:
labels:
app: "?*"
team: "?*"
Terminal window
# DENIED -- missing labels
kubectl run nginx --image=nginx:1.27
# ALLOWED -- labels present
kubectl run nginx --image=nginx:1.27 --labels="app=web,team=platform"
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-latest-tag
spec:
validationFailureAction: Enforce
rules:
- name: validate-image-tag
match:
any:
- resources:
kinds:
- Pod
validate:
message: "The 'latest' tag is not allowed. Pin images to a specific version."
pattern:
spec:
containers:
- image: "!*:latest"
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-resource-limits
spec:
validationFailureAction: Enforce
rules:
- name: check-limits
match:
any:
- resources:
kinds:
- Pod
validate:
message: "CPU and memory limits are required for all containers."
pattern:
spec:
containers:
- resources:
limits:
memory: "?*"
cpu: "?*"
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-non-root
spec:
validationFailureAction: Enforce
rules:
- name: check-non-root
match:
any:
- resources:
kinds:
- Pod
exclude:
any:
- resources:
namespaces:
- kube-system
validate:
message: "Containers must set securityContext.runAsNonRoot to true."
pattern:
spec:
containers:
- securityContext:
runAsNonRoot: true

Auto-Generate NetworkPolicy for New Namespaces

Section titled “Auto-Generate NetworkPolicy for New Namespaces”

Every time a namespace is created, Kyverno generates a default-deny NetworkPolicy inside it. This is a killer feature that Gatekeeper lacks.

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

With synchronize: true, if someone deletes the NetworkPolicy, Kyverno recreates it.


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

The +() notation means “add only if not already present” — it won’t overwrite labels developers set explicitly.

Match on an annotation to opt in specific pods:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: inject-logging-sidecar
spec:
rules:
- name: inject-sidecar
match:
any:
- resources:
kinds:
- Pod
annotations:
inject-logger: "true"
mutate:
patchStrategicMerge:
spec:
containers:
- name: logger
image: fluent/fluent-bit:3.0
resources:
limits:
memory: "64Mi"
cpu: "50m"

Set validationFailureAction: Audit to log violations without blocking. This is how you safely roll out new policies.

Terminal window
# View policy reports
kubectl get clusterpolicyreport
kubectl get policyreport -A
# Detailed results
kubectl get policyreport -n default -o yaml

Kyverno generates PolicyReport resources following the Kubernetes Policy WG standard — they work with dashboards like Policy Reporter UI.


Test policies against manifests before deploying. Shift-left your policy enforcement.

Terminal window
# Install
brew install kyverno
# Test locally
kyverno apply policy.yaml --resource deployment.yaml
kyverno apply policies/ --resource manifests/ --detailed-results
.github/workflows/kyverno-check.yaml
name: Kyverno Policy Check
on: [push, pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Kyverno CLI
run: |
curl -LO https://github.com/kyverno/kyverno/releases/latest/download/kyverno-cli_linux_amd64.tar.gz
tar -xzf kyverno-cli_linux_amd64.tar.gz
sudo mv kyverno /usr/local/bin/
- name: Validate manifests
run: kyverno apply policies/ --resource k8s-manifests/ --detailed-results

FeatureKyvernoOPA/Gatekeeper
Policy languageYAML (Kubernetes-native)Rego (custom DSL)
Learning curveLow — know YAML, you’re readySteep — Rego takes weeks
MutationFirst-class supportAdded later, less mature
GenerationYes — auto-create resourcesNo
Policy reportsBuilt-in (K8s Policy WG standard)Via constraint status
CLI for CI/CDkyverno applyopa test + gator verify
Policy library200+ policies50+ ConstraintTemplates
Complex logicLimited (YAML + JMESPath)Powerful (Rego handles anything)
Non-K8s useKubernetes onlyTerraform, Envoy, Kafka, etc.
CNCF statusIncubatingGraduated (OPA)

Bottom line: Kyverno wins on simplicity and breadth of actions (validate + mutate + generate). Gatekeeper wins on expressiveness and reach beyond Kubernetes. Many organizations use both.

See Module 4.2: OPA & Gatekeeper for Rego-based policies. For CKS exam prep, understand both — the exam covers admission controllers broadly.


MistakeProblemSolution
Enforcing before auditingBreaks existing workloads on day oneStart with Audit, review reports, then Enforce
No exclude for system namespacesKyverno blocks kube-systemAlways exclude kube-system, kube-public, kyverno
Confusing generate with validateExpecting generate to block resourcesGenerate creates resources; it doesn’t deny anything
Not setting background: trueExisting violations are invisibleEnable background scanning for running resources
Overly broad matchPolicies hit every resource typeBe specific with kinds and namespaces
Ignoring init containersSecurity holes in init phaseAdd rules for initContainers or use =(initContainers)

What are the three main policy actions Kyverno supports?

Show Answer

Validate, Mutate, and Generate. Kyverno also supports verifyImages for container image signature verification.

What is the difference between ClusterPolicy and Policy?

Show Answer

ClusterPolicy is cluster-scoped and applies to all namespaces. Policy is namespace-scoped and only affects resources in the namespace where it lives. Use ClusterPolicy for org-wide baselines, Policy for team-specific rules.

How do you safely roll out a new policy in production?

Show Answer
  1. Deploy with validationFailureAction: Audit (not Enforce).
  2. Set background: true to scan existing resources.
  3. Review PolicyReport resources for violations.
  4. Work with teams to fix violations.
  5. Switch to Enforce once violations are resolved.

What does synchronize: true do on a generate rule?

Show Answer

It makes Kyverno continuously reconcile the generated resource. If someone deletes or modifies it, Kyverno recreates or restores it. Without synchronize, the resource is generated once and never managed again. Use it for security-critical generated resources like default-deny NetworkPolicies.


Install Kyverno, deploy validation and generation policies, and verify enforcement.

Terminal window
kind create cluster --name kyverno-lab
helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update
helm install kyverno kyverno/kyverno -n kyverno --create-namespace
kubectl wait --for=condition=ready pod -l app.kubernetes.io/instance=kyverno -n kyverno --timeout=120s
  1. Deploy the “require labels” policy with validationFailureAction: Enforce.

  2. Verify unlabeled pods are blocked:

    Terminal window
    kubectl run test-nginx --image=nginx:1.27
    # Expected: DENIED
  3. Verify labeled pods succeed:

    Terminal window
    kubectl run test-nginx --image=nginx:1.27 --labels="app=web,team=platform"
    # Expected: pod/test-nginx created
  4. Deploy “block latest tag” policy and test:

    Terminal window
    kubectl run bad --image=nginx:latest --labels="app=web,team=platform"
    # Expected: DENIED
  5. Deploy “generate NetworkPolicy” policy, then:

    Terminal window
    kubectl create namespace test-generate
    kubectl get networkpolicy -n test-generate
    # Expected: default-deny-all exists
  6. Check policy reports: kubectl get policyreport -A

  • Kyverno pods running in kyverno namespace
  • Unlabeled pod blocked with clear error
  • Labeled pod created successfully
  • Pod with latest tag blocked
  • New namespace auto-gets default-deny NetworkPolicy
  • Policy reports show pass/fail results

Write a mutating policy that adds environment: dev to all pods in the development namespace only if not already set.



Continue to the Security Tools README to review all security toolkit modules and plan your learning path.


“The best policy engine is the one your team actually uses. If your developers can read the policies, they’ll follow them.”