Kyverno is an open-source project that manages and enforces policies within a Kubernetes cluster. The policy definitions are defined as yaml and deployed as Kubernetes objects.
Kyverno has become popular for its Kubernetes-specific policy engine and declarative rule definitions (as opposed to a general policy engine like OPA/Gatekeeper that use a domain specific language). It also has rich support for CLI tools that allow evaluation of policies from within pipelines.
Deploy Kyverno into Kubernetes cluster
Per the official docs, use Helm to deploy a standalone instance into your Kubernetes cluster (non-HA).
helm repo add kyverno https://kyverno.github.io/kyverno/ helm repo update # view latest chart versions available helm search repo kyverno/kyverno --versions | head -n10 # fresh install helm install kyverno kyverno/kyverno -n kyverno --create-namespace # show all objects created kubectl get all -n kyverno # show webhooks created kubectl get validatingwebhookconfiguration,mutatingwebhookconfiguration -A | grep kyverno kubectl get Mutatingwebhookconfigurations -A | grep kyverno # show webhook excluded namespaces (kube-system,kyverno) kubectl get cm -n kyverno kyverno -o=jsonpath="{.data.webhooks}" | jq . # ensure all deployments are ready before moving forward kubectl rollout status deployment -n kyverno
kyverno CLI tool installation on Debian/Ubuntu
Below are the steps for manual installation of the CLI tool, although krew could be used as well.
latest_version=$(curl -sL https://api.github.com/repos/kyverno/kyverno/releases/latest | jq -r ".tag_name") wget https://github.com/kyverno/kyverno/releases/download/$latest_version/kyverno-cli_${latest_version}_linux_x86_64.tar.gz # extract and place on PATH tar xvfz kyverno-cli_${latest_version}_linux_x86_64.tar.gz sudo cp kyverno /usr/local/bin/. # validate kyverno version
Kyverno policy writing
There are 50+ policy examples on the official site, and this is the best place to understand the scope of what is possible with Kyverno policies.
Although security may be the first word that comes to mind when hearing “policy”, the Kyverno mutation engine can enrich deployment manifest in ways that simplify the life of developers (or Helm chart authors).
The “Writing Policies” page of the official documentation is where you can get into the details of the declarative rules, but for right now, let’s just look at two simple examples in the following sections.
Kyverno policy test #1: namespace policy
We will start with a policy on namespaces that requires a label named “owner” and a label named “env” that can be one of dev|staging|prod (rule originally authored by Glen Yu).
# get policy and apply wget https://raw.githubusercontent.com/fabianlee/blogcode/refs/heads/master/k8s/kyverno/kyv-require-ns-label.yaml kyverno apply kyv-require-ns-label.yaml --cluster --v=5 # EXPECTED kyverno policy control will stop this creation kubectl create ns this-ns-test-will-fail # logs will show policy name that blocked kubectl logs deployment/kyverno-admission-controller -n kyverno | grep "blocking " # kyverno policy allows because 'env' and 'owner' labels assigned kubectl apply -f - << EOF apiVersion: v1 kind: Namespace metadata: name: kyvtest labels: env: dev owner: me EOF # logs will show policy allowed kubectl logs deployment/kyverno-admission-controller -n kyverno | grep " passed"
Kyverno policy test #2: pod resource mutation
The second policy is a slight variation on the official “Add Default Resources“, that adds memory/cpu resource limits to pods that do not define them.
In our case, we have added an exclusion for the “default” namespace, which means it will NOT act upon pods in the default namespace. But it should still mutate pods created in other namespaces, such as the “kyvtest” namespace just created in the section above.
# get policy and apply wget https://raw.githubusercontent.com/fabianlee/blogcode/refs/heads/master/k8s/kyverno/add-default-resources.yaml kubectl apply -f add-default-resources.yaml # get simple deployment manifest that does NOT define any resource limits wget https://raw.githubusercontent.com/fabianlee/blogcode/refs/heads/master/k8s/tiny-tools.yaml # deploy to 'default' namespace and newly created 'kyvtest' namespace kubectl apply -f tiny-tools.yaml -n default kubectl apply -f tiny-tools.yaml -n kyvtest # wait for deployment kubectl rollout status deployment tiny-tools -n kyvtest kubectl rollout status deployment tiny-tools -n default # check resource values: will be empty for 'default' ns, and set to cpu=100m/memory=100Mi for kyvtest kubectl get pods -l app=tiny-tools -A -o=jsonpath="{range .items[*]}{.metadata.namespace},{.metadata.name},{.spec.containers[*].resources}{'\n'}{end}"
REFERENCES
Kyverno policy that adds explicit resource defaults to pods
Kyverno helm chart values.yaml
nirmata.com, 5 reasons Kyverno is better than OPA
nirmata.com, deeper analysis of Kyverno versus OPA
Amine Raje, Kyverno versus OPA
Glen Yu, why I prefer Kyverno over OPA
atlassian, upgrading a helm chart
NOTES
remove kyverno from cluster
helm uninstall kyverno -n kyverno
Exclude namespaces from evaluation at global level using resourceFilters
# show current namespaces excluded from kyverno policy enforcement kubectl get cm -n kyverno kyverno -o=jsonpath="{.data.resourceFilters}" | sed 's/ /\n/g' | grep '^\[\*/\*,' # append additional filters that makes 'default' namespace ignored helm upgrade --install kyverno kyverno/kyverno -n kyverno --create-namespace --set "config.resourceFiltersIncludeNamespaces={default,istio-system}" helm get values kyverno -n kyverno -n kyverno # resource filters will now include 'default' namespace filter kubectl get cm -n kyverno kyverno -o=jsonpath="{.data.resourceFilters}" | sed 's/ /\n/g' | grep '^\[\*/\*,'
kyverno upgrade using helm
# view latest chart versions available helm search repo kyverno/kyverno --versions | head -n10 # upgrade to newer chart helm upgrade --install kyverno kyverno/kyverno -n kyverno --create-namespace --version=3.3.3