Policy Management with Kyverno
What Is Kyverno?
Kyverno is a Kubernetes-native policy engine that lets you manage policies as Kubernetes resources — no new language to learn, just YAML.
With Kyverno, you can:
- Validate — reject resources that don't meet requirements
- Mutate — automatically modify resources to add defaults or fix configurations
- Generate — create additional resources when certain conditions are met
- Verify images — ensure only signed container images are deployed
How Kyverno Works
Kyverno runs as a dynamic admission controller in your Kubernetes cluster:
- When a resource is created or updated, the Kubernetes API server sends an admission webhook to Kyverno
- Kyverno evaluates the resource against all matching policies
- Based on the policy rules, Kyverno can allow, reject, or modify the request
- Results are captured as Kubernetes events and Policy Reports
This all happens transparently — developers don't need to install anything or change their workflow.
Enabling Kyverno in Kuberise.io
In your enabler file, enable both Kyverno (the operator) and the policy chart:
# app-of-apps/values-{name}.yaml (e.g. values-webshop.yaml)
ArgocdApplications:
kyverno:
enabled: true
policy:
enabled: true
Then add your policy YAML files in the appropriate directory:
- All clusters:
values/defaults/platform/policy/— policies applied everywhere - Specific cluster:
values/{cluster}/platform/policy/— cluster-specific policies
Workshop: Validating Resources
Let's create a policy that requires all pods in the default namespace to have a team label.
Step 1: Create the Validation Policy
# values/{cluster}/platform/policy/required-labels.yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-labels
spec:
rules:
- name: check-team
match:
any:
- resources:
kinds:
- Pod
namespaces:
- default
skipBackgroundRequests: true
validate:
allowExistingViolations: true
failureAction: Enforce
message: "The label 'team' is required on all pods"
pattern:
metadata:
labels:
team: "?*"
Step 2: Test It
# This should FAIL — no team label
kubectl run nginx --image nginx
# This should SUCCEED — team label is present
kubectl run nginx --image nginx --labels='team=alpha'
Step 3: Check Policy Reports
kubectl get policyreport -o wide
Policy Reports give you visibility into which resources comply with your policies and which don't — even for resources that existed before the policy was created.
Workshop: Mutating Resources
Mutation policies automatically modify resources. Let's create a policy that adds a default project label to any pod that doesn't already have one.
Step 1: Create the Mutation Policy
# values/{cluster}/platform/policy/add-labels.yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: add-labels
spec:
rules:
- name: add-project
skipBackgroundRequests: true
match:
any:
- resources:
kinds:
- Pod
namespaces:
- default
mutate:
patchStrategicMerge:
metadata:
labels:
+(project): bravo
The +() syntax means "add this label only if it doesn't already exist."
Step 2: Test It
# Create a pod — it should automatically get 'project=bravo' label
kubectl run nginx --image nginx --labels='team=alpha'
# Verify the labels
kubectl get pod nginx --show-labels
Step 3: Verify
kubectl get policyreport -o wide
Workshop: Generating Resources
Generate policies automatically create new resources when a trigger condition is met. A common use case is syncing image pull secrets to new namespaces.
Step 1: Grant Kyverno Access to Secrets
Kyverno needs RBAC permissions to manage secrets:
# values/{cluster}/platform/policy/kyverno-clusterroles.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kyverno:secrets:view
labels:
rbac.kyverno.io/aggregate-to-admission-controller: "true"
rbac.kyverno.io/aggregate-to-reports-controller: "true"
rbac.kyverno.io/aggregate-to-background-controller: "true"
rules:
- apiGroups: ['']
resources: [secrets]
verbs: [get, list, watch]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kyverno:secrets:manage
labels:
rbac.kyverno.io/aggregate-to-background-controller: "true"
rules:
- apiGroups: ['']
resources: [secrets]
verbs: [create, update, delete]
Step 2: Create a Source Secret
kubectl -n default create secret docker-registry regcred \
--docker-server=myinternalreg.corp.com \
--docker-username=john.doe \
--docker-password=Passw0rd123! \
[email protected]
Step 3: Create the Generate Policy
# values/{cluster}/platform/policy/generate-secret.yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: sync-secrets
spec:
rules:
- name: sync-image-pull-secret
match:
any:
- resources:
kinds:
- Namespace
generate:
apiVersion: v1
kind: Secret
name: regcred
namespace: "{{request.object.metadata.name}}"
synchronize: true
clone:
namespace: default
name: regcred
This policy clones the regcred secret into every new namespace automatically. The synchronize: true flag keeps the cloned secrets in sync — if you update the source secret, all copies update too.
Step 4: Test It
# Create a new namespace — the secret should be automatically created
kubectl create ns test
# Verify the secret was generated
kubectl get secrets -n test
Key Takeaways
- Kyverno policies are Kubernetes-native — they're just YAML, stored in Git alongside your other configurations
- Validation policies enforce standards (required labels, resource limits, allowed registries)
- Mutation policies add sensible defaults automatically, reducing developer burden
- Generate policies propagate shared resources (secrets, configmaps, network policies) across namespaces
- Policy Reports provide audit visibility into compliance across your cluster
Traffic Management in Kubernetes
Learn how Kubernetes Services, Ingress Controllers, and DNS management work together to route traffic efficiently and reduce cloud costs.
Host LLM in Kubernetes
Learn how to host large language models in Kubernetes using Ollama, chat with them via Open-WebUI, and use K8sGPT to debug your cluster with AI.