Install
helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update
helm install kyverno kyverno/kyverno \
--namespace kyverno --create-namespace \
--version 3.3.x
Kyverno runs as a deployment in the kyverno namespace. Within a minute, the admission webhooks are registered and policies start enforcing.
The four policy actions
- validate — allow / deny incoming requests based on rules
- mutate — modify incoming requests (add labels, inject sidecars, set defaults)
- generate — create companion resources (e.g. on Namespace creation, auto-create a NetworkPolicy + ResourceQuota)
- verifyImages — check cosign / sigstore signatures on container images at admission time
Example 1: validate — deny privileged pods
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-privileged
spec:
validationFailureAction: Enforce # or Audit (warn but allow)
background: true # also scan existing resources, not just new
rules:
- name: privileged-containers
match:
any:
- resources:
kinds: [Pod]
validate:
message: "Privileged containers are not allowed."
pattern:
spec:
=(initContainers):
- =(securityContext):
=(privileged): "false"
containers:
- =(securityContext):
=(privileged): "false"
Apply with kubectl; the next time anyone tries to create a privileged Pod, kubectl returns a clear error message instead of letting it through.
Example 2: mutate — auto-inject a default label
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: add-cost-center-label
spec:
rules:
- name: add-label
match:
any:
- resources:
kinds: [Deployment, StatefulSet, DaemonSet]
mutate:
patchStrategicMerge:
metadata:
labels:
+(cost-center): "engineering"
+(...) in Kyverno's strategic-merge syntax means "add this field if it's missing." So every workload that doesn't already have a cost-center label gets engineering at admission time. Useful for tagging, network-policy selectors, billing-attribution patterns.
Example 3: generate — default NetworkPolicy per namespace
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: default-deny-netpol
spec:
rules:
- name: generate-default-deny
match:
any:
- resources:
kinds: [Namespace]
names: ["app-*"] # only namespaces matching this glob
generate:
kind: NetworkPolicy
name: default-deny
namespace: "{{ request.object.metadata.name }}"
synchronize: true # keep generated NetPol in sync if Kyverno-managed
data:
spec:
podSelector: {}
policyTypes: [Ingress, Egress]
# empty ingress + egress rules = default deny all
Now when anyone creates an app-* namespace, Kyverno auto-creates a default-deny NetworkPolicy in it. Teams then explicitly allow the traffic they need; everything else is blocked by default.
Example 4: verifyImages — require signed images
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-signed-images
spec:
validationFailureAction: Enforce
rules:
- name: signed-by-ci
match:
any:
- resources:
kinds: [Pod]
verifyImages:
- imageReferences:
- "ghcr.io/myorg/*"
attestors:
- entries:
- keyless:
issuer: "https://token.actions.githubusercontent.com"
subject: "https://github.com/myorg/*/.github/workflows/*"
rekor:
url: "https://rekor.sigstore.dev"
Containers from ghcr.io/myorg/* must be signed by a GitHub Actions workflow under the myorg account, with the signature visible in the public Rekor transparency log. Any image lacking a valid signature is rejected.
Policy reports
Kyverno generates PolicyReport resources per namespace and a ClusterPolicyReport for cluster-scoped resources. They list every policy result against every resource:
kubectl get polr -A # PolicyReports
kubectl get cpolr # ClusterPolicyReports
# Or via the dedicated CLI
kyverno report -A
Useful for "show me everything in this cluster that violates these policies." Pair with the Policy Reporter UI (separate Helm chart) for a web dashboard.
Test policies offline
# CLI test against sample manifests
kyverno apply ./policy.yaml --resource ./sample-pod.yaml
# Or run a full policy test suite (kyverno-test.yaml in a directory)
kyverno test ./policies/
Catch policy bugs in CI before they break the cluster's admission webhook.
Audit mode for safe rollout
Set validationFailureAction: Audit on new policies first. Kubernetes allows the resources through but Kyverno records the violations in PolicyReports. Watch for false positives, fix the rules, then flip to Enforce.
Background scans
With background: true, Kyverno also scans existing resources, not just incoming admission requests. Finds pre-existing violations from before the policy was installed; surfaces them in PolicyReports without retroactively breaking them.
The CNCF policy catalog
Kyverno's policy library contains 200+ pre-written policies for common needs: Pod Security Standards, naming conventions, image registry restrictions, mandatory probes / resource limits, label requirements. Copy them as a starting point; customize per cluster.
Kyverno vs OPA Gatekeeper
- Gatekeeper — policies written in Rego (OPA's purpose-built language). More expressive for complex logic; steeper learning curve.
- Kyverno — policies in YAML; can mutate and generate in addition to validate (Gatekeeper does mutation in 3.x, but Kyverno's been there longer). The simpler starting point.
For most teams, the choice is on Day 1: writing Rego is a real investment. If the team is up for it, Gatekeeper's expressive power matters; if not, Kyverno's YAML-only approach gets policy-as-code into production faster.
What Kyverno doesn't do
- Runtime enforcement (it's admission-time only) — pair with Tetragon (sister of Cilium; see that tutorial) or Falco for runtime threat detection.
- Network policy (use NetworkPolicy or Cilium NP).
- RBAC (use Kubernetes RBAC directly).
For "I want consistent guard-rails on what gets deployed into my cluster," Kyverno is the smallest tool that gets you there in 2026.