Wat is Kyverno?
Kyverno is een Kubernetes-native policy engine, ontworpen voor security en governance. Het wordt vaak vergeleken met Open Policy Agent (OPA), maar in tegenstelling tot OPA werkt Kyverno met YAML en begrijpt het Kubernetes-resources direct. Waar OPA een aparte taal (Rego) vereist, gebruikt Kyverno vertrouwde Kubernetes-manifests.
De meeste gebruikers zetten Kyverno in om clusterbrede of namespace-specifieke regels af te dwingen, zoals het blokkeren van geprivilegieerde containers of het afdwingen van labeling-conventies.
Waarom namespaces bootstrappen?
In de meeste clusters moet elke namespace voorzien worden van een aantal basisresources: netwerkbeleid voor isolatie, image pull secrets voor private registries, gedeelde configuratie zoals CA-certificaten en resourcequota's om overbelasting te voorkomen. Dit handmatig doen—of integreren in elke Helm-chart—is foutgevoelig en lastig consistent te houden.
Kyverno maakt deze standaarden automatisch, versieerbaar en zelfherstellend via declaratieve policies.
Kyverno als bootstrapper
Naast handhaving is Kyverno ook handig voor het automatisch opzetten van namespaces met logische standaardinstellingen. Het creëert niet alleen resources, maar houdt ze ook synchroon met een brontemplate. Kyverno kan dus updates toepassen op je standaard NetworkPolicy
, certificaatbundels of andere gedeelde configuraties.
De kern hiervan is de generate
-regel. Die maakt resources aan zodra een namespace wordt aangemaakt, of als een resource ontbreekt. Wordt de resource later aangepast, dan herstelt Kyverno deze automatisch. In combinatie met match
- en exclude
-regels kun je secrets, configmaps, policies en meer automatisch instellen.
⚠️ Wees voorzichtig met
synchronize: true
—Kyverno zorgt ervoor dat de gegenereerde resource blijft overeenkomen met de bron, wat handmatige aanpassingen in andere namespaces kan overschrijven.
Laten we vier praktijkvoorbeelden bekijken:
1. Netwerkisolatie afdwingen met een standaard NetworkPolicy
Elke namespace zou moeten starten met een NetworkPolicy
die verkeer isoleert en alleen DNS-verkeer naar kube-dns
toestaat. Hierdoor zijn applicaties standaard geïsoleerd, tenzij anders aangegeven.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: default-deny
spec:
rules:
- name: add-default-network-policy
match:
resources:
kinds:
- Namespace
generate:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
name: default-deny
namespace: ""
synchronize: true
generateExisting: true
data:
metadata:
name: default-deny
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
ingress:
- to:
- podSelector: {} # allow traffic to any pod in same namespace
egress:
- to:
- podSelector: {} # allow traffic to any pod in same namespace
- to:
- namespaceSelector: # allow traffic to kube-dns in kube-system
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
Deze regel beveiligt elke nieuwe namespace met strikte ingress- en egress-controles. Na het toepassen zie je een default-deny
policy per namespace die alleen DNS-verkeer naar kube-dns
in de kube-system
namespace toestaat:
$ kubectl create ns test-namespace
namespace/test-namespace created
$ kubectl get networkpolicy -n test-namespace
NAME POD-SELECTOR AGE
default-deny <none> 3s
2. Image pull secrets automatisch genereren
Gebruik je een private container registry, dan heeft elke applicatie-namespace waarschijnlijk toegang nodig via credentials. In plaats van handmatig kopiëren of inbouwen in Helm-charts, kun je deze via Kyverno injecteren.
Voor dit voorbeeld verwacht Kyverno dat er een image-pull-secret
bestaat in de kyverno
namespace. Je kan die maken met:
$ kubectl create secret docker-registry image-pull-secret -n kyverno --docker-username=foo --docker-password=password
Standaard mag Kyverno niet met secrets werken, dus je moet het juiste recht geven via deze ClusterRole
resources. Dit werkt met geaggregeerde rollen en vult bestaande Kyverno-rollen aan.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kyverno:admission:secrets
labels:
rbac.kyverno.io/aggregate-to-admission-controller: "true"
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- list
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kyverno:background:secrets
labels:
rbac.kyverno.io/aggregate-to-background-controller: "true"
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- list
- get
- create
- update
- delete
- patch
Gebruik vervolgens Kyverno om de secret te kopiëren naar elke nieuwe namespace:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: copy-image-pull-secret
spec:
rules:
- name: generate-image-pull-secret
match:
resources:
kinds:
- Namespace
generate:
generateExisting: true
kind: Secret
apiVersion: v1
name: image-pull-secret
namespace: ""
synchronize: true
clone:
namespace: kyverno
name: image-pull-secret
Dit voorbeeld kopieert de bestaande secret automatisch naar elke nieuwe namespace. Je kunt eventueel exclude
-regels toevoegen voor ontwikkelomgevingen of annotaties toevoegen.
3. Een custom CA-certificaat injecteren
Sommige applicaties moeten interne services vertrouwen via een eigen certificaatautoriteit (CA). Gebruik Kyverno om een CA-bundel als secret in elke namespace te injecteren zodat applicaties die kunnen gebruiken.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: add-ca-secret
spec:
rules:
- name: copy-ca-secret
match:
resources:
kinds:
- Namespace
generate:
generateExisting: true
kind: Secret
apiVersion: v1
name: custom-ca
namespace: ""
synchronize: true
clone:
namespace: kyverno
name: custom-ca
Deze policy kopieert het bestaande custom-ca
secret uit de kyverno
namespace naar elke nieuwe en bestaande namespace.
4. ResourceQuota-templates per namespace instellen
Om overmatig verbruik van CPU en geheugen te beperken in multi-tenant clusters, kun je per namespace een standaard ResourceQuota
instellen.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: default-resource-quota
spec:
rules:
- name: generate-default-quota
match:
resources:
kinds:
- Namespace
generate:
generateExisting: true
kind: ResourceQuota
apiVersion: v1
name: default-quota
namespace: ""
synchronize: true
data:
metadata:
name: default-quota
spec:
hard:
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi
Zo voorkom je dat nieuwe namespaces onbeperkte resources kunnen gebruiken.
Een kanttekening bij trade-offs
Het gebruik van Kyverno voor het automatisch opzetten van namespaces zorgt voor consistentie, maar je past hiermee ook clusterbrede standaarden toe—brede maatregelen die later flexibiliteit kunnen beperken. Zo staat de standaard NetworkPolicy
in dit artikel al het verkeer binnen een namespace toe. Dat is een logisch uitgangspunt, maar het belemmert fijnmazige segmentatie later, omdat Kyverno die bredere regel steeds blijft herstellen. Hetzelfde geldt voor ResourceQuota
: als je een applicatie moet opschalen buiten de limieten, leidt het verhogen van de quota mogelijk tot verruiming in álle namespaces.
Om dit te voorkomen kun je het volgende doen:
- Gebruik labels om policies te richten op specifieke namespaces. Bijvoorbeeld alleen toepassen bij
env=prod
ofbootstrap=default
, zodat je uitzonderingen kunt maken. - Splits policies per omgeving of team om de impact te beperken. Bijvoorbeeld aparte regels voor gedeelde namespaces versus team-specifieke omgevingen.
- Gebruik
exclude
-blokken om bepaalde namespaces uit te sluiten (bijv.namespace != critical-apps
).
Samenvatting
Kyverno inzetten voor namespace-bootstrap is een vorm van policy-as-code die zorgt voor consistentie in je cluster. Of het nu gaat om netwerkisolatie, toegangscredentials, TLS-configuratie of resourcebeheer—Kyverno maakt standaardinstellingen herhaalbaar, controleerbaar en zelfherstellend.
Bekijk de Kyverno repository voor nog meer kant-en-klare policies of inspiratie.