Network policies, not just firewall rules, are the key to securing your Kubernetes network with Cilium.
Let’s see Cilium network policies in action. Imagine a simple deployment with two applications: frontend and backend. The frontend needs to talk to the backend on port 80, but the backend should not initiate any connections outward.
apiVersion: cilium.io/v1alpha1
kind: CiliumNetworkPolicy
metadata:
name: frontend-backend-policy
spec:
endpointSelector:
matchLabels:
app: backend # This policy applies to the 'backend' pods
ingress:
- fromEndpoints:
- matchLabels:
app: frontend # Allow ingress from 'frontend' pods
toPorts:
- ports:
- port: "80"
protocol: TCP
This policy explicitly states that only pods labeled app: frontend can connect to pods labeled app: backend on TCP port 80. Any other traffic to backend is dropped by default.
Now, let’s consider encryption. Cilium can leverage WireGuard for pod-to-pod encryption, ensuring that all traffic between your pods traversing the network is confidential.
apiVersion: cilium.io/v1.12
kind: CiliumConfig
metadata:
name: cilium-config
spec:
enable-encryption: true
encryption:
type: wireguard
wireguard:
enabled: true
interface: eth0 # Or your primary network interface
When enable-encryption is set to true and type to wireguard, Cilium automatically generates WireGuard keys for each node. It then distributes these public keys to other nodes, establishing secure, encrypted tunnels for all pod traffic.
The core problem Cilium network policies solve is the lack of granular, identity-based network segmentation within Kubernetes. Traditional network security relies on IP addresses, which are ephemeral and change frequently in a dynamic container environment. Cilium, by leveraging Kubernetes labels and service identities, allows you to define policies based on what a workload is, not just where it is. This makes policies resilient to pod restarts and rescheduling.
Internally, Cilium uses eBPF (extended Berkeley Packet Filter) to program the Linux kernel’s networking stack. When a packet arrives or leaves a pod, eBPF programs attached to network interfaces intercept it. These programs, dictated by your CiliumNetworkPolicies, decide whether to allow, deny, or modify the packet. For encryption, eBPF programs handle the WireGuard encapsulation and decapsulation transparently, so your applications don’t need to be aware of the encryption.
The exact levers you control are primarily through CiliumNetworkPolicy and CiliumClusterwideNetworkPolicy resources. CiliumNetworkPolicy applies to pods within a specific namespace, while CiliumClusterwideNetworkPolicy can enforce policies across the entire cluster. You define these policies using selectors (matchLabels, matchExpressions) for endpoints (pods) and specifying ingress and egress rules with fromEndpoints, toEndpoints, fromCIDR, toCIDR, fromEntities, and toEntities. The fromEntities and toEntities are particularly powerful, allowing you to reference special Kubernetes entities like kube-apiserver, world (all external IPs), or cluster (all IPs within the cluster).
The most surprising, and often overlooked, aspect of Cilium’s encryption is its per-node key management and automatic rotation. While you enable it via CiliumConfig, Cilium handles the complex dance of generating public/private key pairs for each node, securely exchanging public keys with other nodes in the cluster, and establishing WireGuard tunnels. This process is entirely automated; you don’t manually configure tunnel endpoints or keys between nodes. If a node is added or removed, Cilium dynamically updates the encryption state for affected nodes.
For advanced hardening, explore the CiliumEnvoyConfig resource, which allows you to leverage Envoy’s advanced L7 features like TLS termination, request routing based on HTTP headers, and rate limiting, all managed and enforced by Cilium’s eBPF data plane.