Kyverno Reference: K8s Policy Engine — Validate, Mutate, Generate & Image Verification
Kyverno is a Kubernetes-native policy engine. Policies are written as K8s CRDs — no Rego required. It validates, mutates, and generates K8s resources, and integrates naturally with kubectl. Simpler to adopt than OPA/Gatekeeper for most K8s policy use cases.
1. Kyverno vs OPA Gatekeeper
When to choose Kyverno
| Feature | Kyverno | OPA Gatekeeper |
|---|---|---|
| Policy language | Kubernetes YAML (no new language) | Rego (new language to learn) |
| Mutation | Yes — first-class mutate rules | Needs separate Mutation webhook |
| Generation | Yes — generate resources on trigger | No |
| Test tools | kyverno test (built-in unit testing) | opa test (separate tool) |
| Image verification | Yes — verifyImages with Cosign | No |
| Learning curve | Low — already know YAML/JMESPath | High — Rego is a new paradigm |
| Best for | Teams wanting K8s-native policies without Rego | Complex policies, existing Rego expertise, multi-service mesh |
# Install Kyverno: helm repo add kyverno https://kyverno.github.io/kyverno/ helm install kyverno kyverno/kyverno -n kyverno --create-namespace # Verify: kubectl get pods -n kyverno kubectl get crds | grep kyverno.io # ClusterPolicy, Policy, PolicyReport, etc.
2. Validate Policies
Block non-compliant resources at admission time
# Require resource limits on all containers:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-resource-limits
spec:
validationFailureAction: Enforce # Enforce=block, Audit=allow+report
background: true # also check existing resources
rules:
- name: check-resource-limits
match:
any:
- resources:
kinds: [Pod]
validate:
message: "All containers must define CPU and memory limits."
pattern:
spec:
containers:
- resources:
limits:
cpu: "?*" # must be set to anything
memory: "?*"
# Disallow privileged containers:
- name: deny-privileged
match:
any:
- resources: {kinds: [Pod]}
validate:
message: "Privileged containers are not allowed."
pattern:
spec:
containers:
- =(securityContext):
=(privileged): "false"
initContainers:
- =(securityContext):
=(privileged): "false"
# Require specific labels on Deployments:
- name: require-labels
match:
any:
- resources: {kinds: [Deployment]}
validate:
message: "Deployment must have 'app' and 'version' labels."
pattern:
metadata:
labels:
app: "?*"
version: "?*"
3. Mutate Policies
Automatically patch resources on admission
# Add default resource limits if not set:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: add-default-limits
spec:
rules:
- name: add-cpu-memory-limits
match:
any:
- resources: {kinds: [Pod]}
mutate:
patchStrategicMerge:
spec:
containers:
- (name): "*"
resources:
limits:
+(cpu): "500m" # add only if missing (+ prefix)
+(memory): "256Mi"
requests:
+(cpu): "100m"
+(memory): "64Mi"
# Add namespace label to all Pods:
- name: add-namespace-label
match:
any:
- resources: {kinds: [Pod]}
mutate:
patchStrategicMerge:
metadata:
labels:
+(namespace): "{{ request.namespace }}" # JMESPath expression
# Force non-root user if runAsUser is 0:
- name: force-non-root
match:
any:
- resources: {kinds: [Pod]}
mutate:
patchStrategicMerge:
spec:
securityContext:
+(runAsNonRoot): true
+(runAsUser): 1000 # set only if missing
4. Generate Policies
Auto-create resources (NetworkPolicy, RoleBinding) when namespace is created
# Auto-create default NetworkPolicy in every new namespace:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: add-default-networkpolicy
spec:
rules:
- name: default-deny-ingress
match:
any:
- resources:
kinds: [Namespace]
generate:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
name: default-deny-ingress
namespace: "{{ request.object.metadata.name }}" # target namespace
synchronize: true # keep in sync (update if policy changes)
data:
spec:
podSelector: {}
policyTypes: [Ingress]
# Auto-copy a Secret to every new namespace (e.g. Docker registry credentials):
- name: copy-regcred
match:
any:
- resources: {kinds: [Namespace]}
generate:
apiVersion: v1
kind: Secret
name: regcred
namespace: "{{ request.object.metadata.name }}"
synchronize: true
clone:
namespace: default # clone from this source namespace
name: regcred
5. Testing & Operations
Unit test policies, check reports, verify images
# Test policies locally (no cluster needed):
# Create kyverno-test.yaml next to your policy:
policies:
- policy.yaml
resources:
- resources/good-pod.yaml
- resources/bad-pod.yaml
results:
- policy: require-resource-limits
rule: check-resource-limits
resource: good-pod
result: pass
- policy: require-resource-limits
rule: check-resource-limits
resource: bad-pod
result: fail
kyverno test . # runs all tests in directory
# Check policy reports (what's currently failing in cluster):
kubectl get policyreport -A # namespace-scoped results
kubectl get clusterpolicyreport # cluster-scoped
# PolicyReport shows: which resources fail which rules (for background audit mode)
# Image signature verification with Cosign:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: verify-image-signature
spec:
rules:
- name: check-signature
match:
any:
- resources: {kinds: [Pod]}
verifyImages:
- imageReferences: ["registry.example.com/my-app:*"]
attestors:
- entries:
- keys:
publicKeys: |
-----BEGIN PUBLIC KEY-----
MFkwEwYH...
-----END PUBLIC KEY-----
# Dry-run a resource against policies:
kubectl apply --dry-run=server -f my-pod.yaml
# Kyverno webhook will return validation errors without creating the resource
Track Kyverno, Kubernetes, and policy tooling releases.
ReleaseRun monitors Kubernetes, Docker, and 13+ DevOps technologies.
Related: OPA & Gatekeeper Reference | Kubernetes RBAC Reference | Cilium Reference | Kubernetes EOL Tracker
🔍 Free tool: K8s YAML Security Linter — check the manifests Kyverno policies enforce against for baseline security misconfigurations.
Founded
2023 in London, UK
Contact
hello@releaserun.com