Mastering Kyverno: From Installation to Advanced Policy Management in Kubernetes
This guide walks you through Kyverno, the CNCF‑graduated Kubernetes policy engine, covering its architecture, high‑availability installation, creation of validation, mutation, generation, and cleanup policies, as well as advanced features like variables, JMESPath expressions, and integration with Helm and the Kyverno Playground.
Kyverno is an open‑source policy engine originally from Nirmata and now part of the CNCF. It provides validation, mutation, generation, and cleanup capabilities for Kubernetes resources without requiring a dedicated language.
Kyverno runs as a dynamic admission controller, receiving AdmissionReview callbacks from the kube‑apiserver and applying matching policies to either accept or reject requests. Policies can match resources by kind, name, and label selectors, and support wildcard names.
Policy execution is captured via Kubernetes events, and the overall architecture is illustrated in the diagram below.
High‑availability installations run multiple Kyverno replicas, each hosting several controllers that handle AdmissionReview requests (
AdmissionReview), monitor policies (
PolicyController), and manage generated resources (
GenerateController).
Installation
Kyverno requires a Kubernetes cluster version ≥ v1.14. For a v1.28.x cluster, install the latest 1.11.4 release.
<code>kubectl create -f https://github.com/kyverno/kyverno/releases/download/v1.11.3/install.yaml</code>Alternatively, use Helm:
<code>helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update
helm upgrade --install kyverno kyverno/kyverno -n kube-kyverno --create-namespace</code>Installation creates the
kube-kyvernonamespace and installs the required CRDs, admission controller, reports controller, cleanup controller, and background controller.
Policies and Rules
A Kyverno policy is a collection of rules. Each rule contains a
matchclause, an optional
excludeclause, and one of the action clauses:
validate,
mutate,
generate, or
verifyImages. Only one action can be defined per rule.
Policies can be cluster‑wide (
ClusterPolicy) or namespace‑scoped (
Policy).
Policy applies only to resources within its own namespace.
ClusterPolicy applies to resources across all namespaces.
Policy Definition Example – Validation
The following policy enforces that every Pod carries a
kyvernolabel. It uses
validationFailureActionset to
Enforce, which blocks non‑compliant resources.
<code># kyverno-require-label.yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-label-policy
spec:
validationFailureAction: Enforce
rules:
- name: check-for-labels
match:
resources:
kinds:
- Pod
validate:
message: "label 'kyverno' is required"
pattern:
metadata:
labels:
kyverno: "?*"
</code>Applying the policy:
<code>kubectl apply -f kyverno-require-label.yaml
kubectl get clusterpolicy
</code>Creating a Pod without the label results in an admission error, while adding the label allows successful creation.
Policy Definition Example – Mutation
This policy adds the label
kyverno=nginxto any Pod that uses an image containing
nginx.
<code># kyverno-mutate-label.yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: nginx-label-policy
spec:
rules:
- name: nginx-label
match:
resources:
kinds:
- Pod
mutate:
patchStrategicMerge:
metadata:
labels:
kyverno: nginx
spec:
(containers):
- (image): "*nginx*"
</code>After applying the policy, a newly created
nginxPod automatically receives the label.
Policy Definition Example – Generation
Generation rules can create auxiliary resources. The example synchronizes a
regcredSecret from the
defaultnamespace to any newly created namespace.
<code># kyverno-generate-secret.yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: sync-secrets-policy
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
</code>Creating a new namespace automatically creates a copy of the
regcredSecret inside it.
Policy Definition Example – Cleanup
Cleanup policies declaratively delete resources. The example removes Deployments labeled
canremove:truewhen they have fewer than two replicas, running every five minutes.
<code>apiVersion: kyverno.io/v2beta1
kind: ClusterCleanupPolicy
metadata:
name: cleandeploy
spec:
match:
any:
- resources:
kinds:
- Deployment
selector:
matchLabels:
canremove: "true"
conditions:
any:
- key: "{{ target.spec.replicas }}"
operator: LessThan
value: 2
schedule: "*/5 * * * *"
</code>Cleanup can also be driven by a TTL label such as
cleanup.kyverno.io/ttl: 2mon any resource.
Policy Variables
Variables let policies reference dynamic data from the admission request, ConfigMaps, the API server, OCI registries, or external services. Kyverno stores data as JSON and uses JMESPath expressions to extract values, referenced with
{{key.path}}syntax.
Predefined variables include
serviceAccountName,
serviceAccountNamespace,
request.roles,
request.clusterRoles, and
images.
Variables can be escaped with a leading backslash (
\{{...}}) when the literal string is needed.
Advanced Example – Injecting OTEL Environment Variables
The policy below mutates Pods to add several environment variables, including
OTEL_RESOURCE_ATTRIBUTESthat references other variables using the
$(...)syntax.
<code>apiVersion: kyverno.io/v1
kind: Policy
metadata:
name: add-otel-resource-env
namespace: foobar
spec:
background: false
rules:
- name: imbue-pod-spec
match:
any:
- resources:
kinds:
- v1/Pod
mutate:
patchStrategicMerge:
spec:
containers:
- (name): "?*"
env:
- name: NODE_NAME
value: "mutated_name"
- name: POD_IP_ADDRESS
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_SERVICE_ACCOUNT
valueFrom:
fieldRef:
fieldPath: spec.serviceAccountName
- name: OTEL_RESOURCE_ATTRIBUTES
value: >-
k8s.namespace.name=\$(POD_NAMESPACE),
k8s.node.name=\$(NODE_NAME),
k8s.pod.name=\$(POD_NAME),
k8s.pod.primary_ip_address=\$(POD_IP_ADDRESS),
k8s.pod.service_account.name=\$(POD_SERVICE_ACCOUNT),
rule_applied=$(./../../../../../../../../name)
</code>When the mutated Pod runs, it prints the composed
OTEL_RESOURCE_ATTRIBUTESvalue, demonstrating variable substitution.
For more Kyverno policies and examples, visit the official website https://kyverno.io/policies or use the Kyverno Playground to test your policies.
Ops Development Stories
Maintained by a like‑minded team, covering both operations and development. Topics span Linux ops, DevOps toolchain, Kubernetes containerization, monitoring, log collection, network security, and Python or Go development. Team members: Qiao Ke, wanger, Dong Ge, Su Xin, Hua Zai, Zheng Ge, Teacher Xia.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.