Kyverno
Kyverno is a policy engine designed specifically for Kubernetes. Policies are defined as Kubernetes resources — no new language to learn. Kyverno can validate, mutate, generate, and verify images for workloads in your cluster.
Installation
Install via Helm
# Add Helm repository
helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update
# Install Kyverno (standalone mode — 1 replica)
helm install kyverno kyverno/kyverno \
--namespace kyverno \
--create-namespace
# Install in HA mode (production — 3 replicas)
helm install kyverno kyverno/kyverno \
--namespace kyverno \
--create-namespace \
--set replicaCount=3 \
--set admissionController.replicas=3 \
--set backgroundController.replicas=2 \
--set cleanupController.replicas=2 \
--set reportsController.replicas=2
# Install Kyverno CLI
brew install kyverno
# Or download from GitHub releases
Install via Manifest
kubectl create -f \
https://github.com/kyverno/kyverno/releases/latest/download/install.yaml
# Verify
kubectl get pods -n kyverno
kubectl get crds | grep kyverno
Install Kyverno CLI
# macOS
brew install kyverno
# Linux
curl -LO https://github.com/kyverno/kyverno/releases/latest/download/kyverno-cli_linux_x86_64.tar.gz
tar -xzf kyverno-cli_linux_x86_64.tar.gz
sudo mv kyverno /usr/local/bin/
# Verify
kyverno version
Configuration
ClusterPolicy vs Policy
# ClusterPolicy — cluster-scoped, applies across all namespaces
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: my-cluster-policy
spec:
# ...
# Policy — namespace-scoped
apiVersion: kyverno.io/v1
kind: Policy
metadata:
name: my-namespace-policy
namespace: production
spec:
# ...
Policy Spec Structure
spec:
validationFailureAction: Enforce # Enforce | Audit
background: true # Apply to existing resources
rules:
- name: rule-name
match:
any:
- resources:
kinds:
- Pod
namespaces:
- production
exclude:
any:
- resources:
namespaceSelector:
matchLabels:
kyverno.io/exclude: "true"
validate:
message: "Validation failed message"
pattern:
# ...
Core Commands
| Command | Description |
|---|---|
kubectl get clusterpolicy | List all ClusterPolicies |
kubectl get policy -A | List all namespace-scoped Policies |
kubectl get policyreport -A | List PolicyReports per namespace |
kubectl get clusterpolicyreport | List cluster-level PolicyReports |
kubectl describe clusterpolicy <name> | Show policy details and status |
kyverno apply <policy> -r <resource> | Test policy against a resource file |
kyverno test . | Run all test cases in current directory |
kyverno test --detailed-results . | Show per-rule test results |
kyverno jp query -i <json> '<expr>' | Test JMESPath expressions |
kyverno jp parse '<pattern>' | Parse and validate a Kyverno pattern |
kubectl get admissionreports -A | List admission-time reports |
kubectl get backgroundscanreports -A | List background scan reports |
kubectl logs -n kyverno -l app=kyverno | View Kyverno controller logs |
Advanced Usage
Validation Policy — Require Labels
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-labels
spec:
validationFailureAction: Audit
background: true
rules:
- name: check-team-label
match:
any:
- resources:
kinds:
- Deployment
- StatefulSet
- DaemonSet
validate:
message: "Deployment must have a 'team' label"
pattern:
metadata:
labels:
team: "?*"
Mutation Policy — Add Default Labels
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: add-default-labels
spec:
rules:
- name: add-managed-by
match:
any:
- resources:
kinds:
- Deployment
mutate:
patchStrategicMerge:
metadata:
labels:
managed-by: kyverno
spec:
template:
metadata:
labels:
managed-by: kyverno
Generation Policy — Create NetworkPolicy
# Auto-generate a default-deny NetworkPolicy in every new namespace
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: generate-default-networkpolicy
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
Image Verification with Cosign
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: verify-image-signature
spec:
validationFailureAction: Enforce
background: false
rules:
- name: check-image
match:
any:
- resources:
kinds:
- Pod
verifyImages:
- imageReferences:
- "ghcr.io/my-org/*"
attestors:
- count: 1
entries:
- keys:
publicKeys: |-
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...
-----END PUBLIC KEY-----
signatureAlgorithm: sha256
Enforce Resource Limits
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-resource-limits
spec:
validationFailureAction: Enforce
background: true
rules:
- name: validate-limits
match:
any:
- resources:
kinds:
- Pod
validate:
message: "All containers must have resource limits"
foreach:
- list: "request.object.spec.containers"
deny:
conditions:
any:
- key: "{{ element.resources.limits.cpu }}"
operator: Equals
value: ""
- key: "{{ element.resources.limits.memory }}"
operator: Equals
value: ""
Policy Exception
# Allow a specific workload to bypass a policy
apiVersion: kyverno.io/v2
kind: PolicyException
metadata:
name: delta-exception
namespace: delta
spec:
exceptions:
- policyName: require-labels
ruleNames:
- check-team-label
match:
any:
- resources:
kinds:
- Deployment
names:
- legacy-app
namespaces:
- delta
Common Workflows
Test Policies Before Enforcing
# Create a test directory structure:
# tests/
# kyverno-test.yaml — test manifest
# policy.yaml — the policy
# resource-pass.yaml — resource that should pass
# resource-fail.yaml — resource that should fail
# kyverno-test.yaml example:
cat <<EOF > tests/kyverno-test.yaml
name: require-labels-test
policies:
- policy.yaml
resources:
- resource-pass.yaml
- resource-fail.yaml
results:
- policy: require-labels
rule: check-team-label
resource: passing-deployment
result: pass
- policy: require-labels
rule: check-team-label
resource: failing-deployment
result: fail
EOF
# Run tests
kyverno test tests/
Audit Existing Resources
# Switch policy to Audit mode (doesn't block, just reports)
kubectl patch clusterpolicy require-labels \
--type=json \
-p='[{"op":"replace","path":"/spec/validationFailureAction","value":"Audit"}]'
# Check audit results
kubectl get clusterpolicyreport -o wide
# View detailed failures
kubectl get clusterpolicyreport -o json | \
jq '.items[].results[] | select(.result == "fail")'
Generate Policy Reports in CI
# Apply policy against resource manifests (no cluster needed)
kyverno apply ./policies/ \
--resource ./manifests/ \
--detailed-results
# Exit code 0 = all pass, non-zero = failures found
# Use in CI pipelines to gate PRs
Monitor Policy Violations
# Watch for new violations
kubectl get policyreport -A --watch
# Count violations per policy
kubectl get policyreport -A -o json | \
jq '[.items[].results[] | select(.result == "fail")] |
group_by(.policy) |
map({policy: .[0].policy, count: length})'
Tips and Best Practices
- Start with
Auditmode before switching toEnforce— audit mode reports violations without blocking deployments, letting you fix resources first. - Use
background: trueto scan existing resources — without this, Kyverno only evaluates new/updated resources, leaving existing violations undetected. - Set
synchronize: trueon generation rules — Kyverno will keep generated resources in sync if the source policy changes. - Write tests before policies — use
kyverno testin CI to validate that policies match the correct resources and allow intended exceptions. - Scope policies with
exclude— always exclude thekyvernonamespace and any system namespaces to prevent the policy engine from blocking itself. - Use PolicyExceptions instead of disabling policies — exceptions are tracked in Git and auditable; disabling policies leaves no trace.
- Pin image verification keys in policies — rotating signing keys requires updating policies; use key references or OCI keyless with OIDC for easier rotation.
- Enable
podSecurityStandards— Kyverno’s built-in Pod Security Standard policies are a quick win for baseline security posture. - Monitor the
kyvernonamespace — check controller logs for admission webhook timeouts; a failing webhook can block all admissions iffailurePolicy: Fail. - Use
kyverno jp queryto test JMESPath expressions interactively before embedding them in policies.