Kubernetes-namespaces automatisch opzetten met Kyverno

Beheer je een Kubernetes-cluster met meerdere applicaties of tenants, dan ken je waarschijnlijk het herhalende werk van het instellen van elke namespace met de juiste standaardconfiguraties. Denk aan netwerkisolatie, image pull-credentials en aangepaste certificaten—essentiële maar monotone taken. Kyverno is niet alleen een policy enforcement engine, maar ook een hulpmiddel om deze resources op een declaratieve en geautomatiseerde manier op te zetten.

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 of bootstrap=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.