Kyverno
Kyverno is a security solution for Kubernetes that can validate, modify, and generate specifications using admission controllers. Kyverno uses rule definitions based on CRDs.
Prerequisites
We need a Kubernetes cluster, which can be created following these instructions. We also need the kubectl binary configured with the cluster’s kubeconfig, and the helm binary.
Installation
We install Kyverno using Helm.
# Add the repository
helm repo add kyverno https://kyverno.github.io/kyverno/
# Install *kyverno*
helm install kyverno kyverno/kyverno -n kyverno --create-namespace
We verify that the Kyverno Pod is running correctly.
$ kubectl get po -n kyverno
NAME READY STATUS RESTARTS AGE
kyverno-6ffff9dc94-rlwj4 1/1 Running 0 2m15s
The Kyverno installation created MutatingWebhookConfiguration and ValidatingWebhookConfiguration CRDs.
$ kubectl get mutatingwebhookconfigurations
NAME WEBHOOKS AGE
kyverno-policy-mutating-webhook-cfg 1 2m53s
kyverno-resource-mutating-webhook-cfg 2 2m52s
kyverno-verify-mutating-webhook-cfg 1 2m53s
$ kubectl get validatingwebhookconfigurations
NAME WEBHOOKS AGE
kyverno-policy-validating-webhook-cfg 1 66s
kyverno-resource-validating-webhook-cfg 2 66s
Usage
- Defining a Cluster-wide Policy
The following specification defines a ClusterPolicy at the cluster level, which ensures that no Pod is created if it doesn’t have a label named app.kubernetes.io/name.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-labels
spec:
validationFailureAction: enforce
rules:
- name: check-for-labels
match:
any:
- resources:
kinds:
- Pod
validate:
message: "label 'app.kubernetes.io/name' is required"
pattern:
metadata:
labels:
app.kubernetes.io/name: "?*"
We create the resource.
kubectl apply -f cluster-pod-label-policy.yaml
We test this ClusterPolicy by creating the following Deployment that doesn’t contain the label:
kubectl create deployment nginx --image=nginx
We should get an error message similar to the following.
error: failed to create deployment: admission webhook "validate.kyverno.svc-fail" denied the request:
resource Deployment/default/nginx was blocked due to the following policies
require-labels:
autogen-check-for-labels: 'validation error: label ''app.kubernetes.io/name'' is
required. Rule autogen-check-for-labels failed at path /spec/template/metadata/labels/app.kubernetes.io/name/'
We delete this ClusterPolicy.
kubectl delete -f cluster-pod-label-policy.yaml
- Defining a Namespace-scoped Policy
The following specification defines a Policy that automatically adds the app.kubernetes.io/name label property to Pods that don’t have it.
apiVersion: kyverno.io/v1
kind: Policy
metadata:
name: require-labels
spec:
validationFailureAction: enforce
rules:
- name: check-for-labels
match:
any:
- resources:
kinds:
- Pod
mutate:
patchStrategicMerge:
metadata:
labels:
+(app.kubernetes.io/name): "{{request.object.metadata.name}}"
We create the resource in a new test namespace:
kubectl create ns test
kubectl apply -f pod-add-label-policy.yaml -n test
Next, we create a simple Pod.
kubectl run mongo --image=mongo:5.0
Then, we verify the label app.kubernetes.io/name: mongo has been added to the Pod.
$ kubectl get po mongo -o jsonpath='{.metadata.labels}'
{"app.kubernetes.io/name":"mongo","run":"mongo"}
We delete the Policy:
kubectl delete -f pod-add-label-policy.yaml -n test
- Automatic Resource Generation
The following specification defines a ClusterPolicy that automatically creates a NetworkPolicy that prevents all traffic between Pods when a new namespace is created.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: default
spec:
rules:
- name: deny-all-traffic
match:
any:
- resources:
kinds:
- Namespace
exclude:
any:
- resources:
namespaces:
- kube-system
- default
- kube-public
- kyverno
generate:
kind: NetworkPolicy
name: deny-all-traffic
namespace: "{{request.object.metadata.name}}"
data:
spec:
# select all pods in the namespace
podSelector: {}
policyTypes:
- Ingress
- Egress
We create the resource:
kubectl apply -f create-network-policy.yaml
Let’s now create a new namespace and making sure a NetworkPolicy has been created inside it.
kubectl create ns test
kubectl -n test get netpol
We should get a result similar to the following.
NAME POD-SELECTOR AGE
deny-all-traffic <none> 4s
Summary
Kyverno is a solution that positions itself as an alternative to PodSecurityPolicy, which has been removed in Kubernetes 1.25. One of Kyverno’s strengths is using CRDs to define rules to be applied at the cluster level (ClusterPolicy) or namespace level (Policy).
Many examples of Policy and ClusterPolicy are available at https://kyverno.io/policies/