Klaar met het copy-pasten van Cilium Network Policies? Probeer Clusterwide Policies
Stel je voor: je Kubernetes cluster bruist van activiteit. Tientallen, misschien wel honderden namespaces draaien onafhankelijk van elkaar, elk met hun eigen microservices. Het ene team heeft internettoegang nodig om AI-vectoren te bouwen en AI-modellen te downloaden. Een ander team valt onder strengere security-eisen vanwege gevoelige data. Hoe houd je dit overzichtelijk zonder te verdrinken in een spaghetti van Cilium Network Policies?
Vaak worstelen teams met het schrijven van een eindeloos aantal bijna identieke netwerk policies. Elke keer dat er een nieuwe namespace wordt aangemaakt, begint dezelfde routine opnieuw. Soms staat het zelfs in de Scrum Definition of Done! Dat moet toch eenvoudiger kunnen?
Gelukkig is er een veel simpelere manier. De oplossing: Cilium Cluster-Wide Network Policies (CCNP’s) gecombineerd met slimme namespace labeling. Dit elimineert redundantie en de inconsistenties die daarbij horen.
Policy Spaghetti
De valkuil van herhaling
- Zie je dezelfde internet access-regels steeds opnieuw terugkomen? Wat een tijdverspilling.
- Beheer en overzicht: Houd het simpel
Stel je voor dat je honderden van deze policies hebt. Een snelle wijziging doorvoeren is lastig. De eenvoudigste manier is om dit centraal te doen, bij voorkeur via GitOps met bijvoorbeeld Argo CD. - Foutgevoeligheid: Een typefout is zo gemaakt
Eén verkeerd cijfer in een IP-adres of een typefout in een poortnummer en de verbinding werkt niet meer – of erger nog: hij staat wagenwijd open.
Maak beheer eenvoudig: De kracht van CCNP’s en Namespace Labels
Cilium Cluster-wide Network Policies (CCNP’s) zijn krachtig omdat ze policies definiëren die gelden voor je hele cluster, niet alleen voor één enkele namespace. En het mooie is: je kunt deze CCNP’s laten reageren op labels die op namespaces zijn toegepast. Zo werkt het:
➜ ~ kubectl create namespace hello-world
namespace/hello-world created
➜ ~ kubectl run nginx -n hello-world --image docker.io/nginxdemos/hello --image-pull-policy=IfNotPresent --port 80
pod/nginx created
➜ ~ kubectl -n hello-world expose pod nginx --type LoadBalancer
service/nginx exposed
➜ ~ kubectl -n hello-world get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx LoadBalancer 10.43.67.208 192.168.4.51 80:30715/TCP 61s
➜ ~ curl http://192.168.4.51 | grep "<title>"
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 12108 0 12108 0 0 955k 0 --:--:-- --:--:-- --:--:-- 985k
<title>Hello World</title>
Copy code
Deny All Policy
Laten we beginnen met een veilige baseline. Blokkeer al het inkomende en uitgaande verkeer door een Cilium Network Policy toe te passen die al het verkeer matcht. Dit mechanisme kun je op verschillende manieren toepassen: per namespace, met een CCNP (Cilium Cluster-Wide Network Policy) of via Enforcement Mode always. (https://docs.cilium.io/en/latest/security/policy/intro/).
deny-all.yaml:
---
apiVersion: "cilium.io/v2"
kind: CiliumClusterwideNetworkPolicy
metadata:
name: "deny-all"
spec:
description: "Make sure namespace is locked"
endpointSelector:
matchExpressions:
- key: io.kubernetes.pod.namespace
operator: In
values:
- hello-world
ingress:
- {}
egress:
- {}
➜ ~ kubectl apply -f deny-all.yaml
ciliumclusterwidenetworkpolicy.cilium.io/deny-all created
Copy code
Endpoints listen en je app lokaliseren
Label de namespace met allow-ingress-port-80=true. Dit label heb je nodig in de Cilium Cluster-Wide Network Policy endpoint selector.
➜ ~ kubectl label namespace hello-world allow-ingress-port-80=true
namespace/hello-world labeled
➜ ~ kubectl -n hello-world describe ciliumendpoint nginx
Name: nginx
Namespace: hello-world
Labels: run=nginx
API Version: cilium.io/v2
Kind: CiliumEndpoint
...
Status:
Encryption:
External - Identifiers:
k8s-namespace: hello-world
k8s-pod-name: nginx
Pod - Name: hello-world/nginx
Id: 47
Identity:
Id: 34739
Labels:
k8s:io.cilium.k8s.namespace.labels.allow-ingress-port-80=true
k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=hello-world
k8s:io.cilium.k8s.policy.cluster=default
k8s:io.cilium.k8s.policy.serviceaccount=default
k8s:io.kubernetes.pod.namespace=hello-world
k8s:run=nginx
...
Copy code
De NGINX-pod is bekend als een Cilium Endpoint. De namespace labels, automatisch geprefixt met io.cilium.k8s.namespace.labels, worden aan het endpoint gekoppeld. Deze labels kun je gebruiken in de Network Policy endpointSelector.
Creëer een Cilium Cluster-wide Network Policy
Door de deny-all policy is de container nu niet bereikbaar:
➜ ~ curl --connect-timeout 5 -I http://192.168.4.51
curl: (28) Failed to connect to 192.168.4.51 port 80 after 5006 ms: Timeout was reached
➜ ~ kubectl -n kube-system exec ds/cilium -c cilium-agent -- cilium monitor --related-to 47
Press Ctrl-C to quit
time="2025-06-26T21:18:31Z" level=info msg="Initializing dissection cache..." subsys=monitor
Policy verdict log: flow 0x0 local EP ID 47, remote ID world, proto 6, ingress, action deny, auth: disabled, match none, 192.168.4.229:51956 -> 10.42.0.251:80 tcp SYN
xx drop (Policy denied) flow 0x0 to endpoint 47, ifindex 4, file bpf_lxc.c:2091, , identity world->34739: 192.168.4.229:51956 -> 10.42.0.251:80 tcp SYN
Policy verdict log: flow 0x0 local EP ID 47, remote ID world, proto 6, ingress, action deny, auth: disabled, match none, 192.168.4.229:51956 -> 10.42.0.251:80 tcp SYN
xx drop (Policy denied) flow 0x0 to endpoint 47, ifindex 4, file bpf_lxc.c:2091, , identity world->34739: 192.168.4.229:51956 -> 10.42.0.251:80 tcp SYN
Copy code
Maak nu een Cilium Cluster-Wide Network Policy die alleen actief wordt als een namespace een specifiek label heeft. In dit voorbeeld: allow-ingress-port-80: “true”.
---
apiVersion: "cilium.io/v2"
kind: CiliumClusterwideNetworkPolicy
metadata:
name: "allow-ingress-port-80"
spec:
description: "Clusterwide Network to allow ingress http traffic"
endpointSelector:
matchLabels:
io.cilium.k8s.namespace.labels.allow-ingress-port-80: "true"
ingress:
- fromEntities:
- world
toPorts:
- ports:
- port: "80"
protocol: TCP
➜ ~ kubectl apply -f allow-ingress-port-80.yaml
ciliumclusterwidenetworkpolicy.cilium.io/allow-ingress-port-80 created
Copy code
Het resultaat
De Cilium Cluster-Wide Network Policy geeft nu toegang tot de pod in de namespace. Tijd om dit te testen:
➜ ~ curl http://192.168.4.51 | grep "<title>"
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 12108 0 12108 0 0 2769k 0 --:--:-- --:--:-- --:--:-- 2956k
<title>Hello World</title>
Copy code
Referenties
En dat werkt dus: Cilium Cluster-Wide Network Policies (CCNP’s) gecombineerd met slimme namespace labeling. Stel je voor dat je een vergelijkbare aanpak gebruikt ter vervanging van complexe, namespace-gebonden network policies voor bijvoorbeeld Prometheus, Fluentd of andere tooling.
References
- Klaar met het copy-pasten van Cilium Network Policies? Probeer Clusterwide Policies
- Policy Spaghetti
- Maak beheer eenvoudig: De kracht van CCNP’s en Namespace Labels
- Deploy an Example Application
- Deny All Policy
- Endpoints listen en je app lokaliseren
- Creëer een Cilium Cluster-wide Network Policy
- Het resultaat
- Referenties
- Klaar met het copy-pasten van Cilium Network Policies? Probeer Clusterwide Policies
- Policy Spaghetti
- Maak beheer eenvoudig: De kracht van CCNP’s en Namespace Labels
- Deploy an Example Application
- Deny All Policy
- Endpoints listen en je app lokaliseren
- Creëer een Cilium Cluster-wide Network Policy
- Het resultaat
- Referenties