Cilium replaces the default AWS VPC CNI on EKS, giving you advanced networking and security features that the default CNI simply doesn’t offer.
Let’s see Cilium in action. Imagine we have a simple Deployment for a web application:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-webapp
spec:
replicas: 2
selector:
matchLabels:
app: my-webapp
template:
metadata:
labels:
app: my-webapp
spec:
containers:
- name: web
image: nginxdemos/hello:plain-text
ports:
- containerPort: 80
And another Deployment for a backend service:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-backend
spec:
replicas: 1
selector:
matchLabels:
app: my-backend
template:
metadata:
labels:
app: my-backend
spec:
containers:
- name: backend
image: httpd:alpine
ports:
- containerPort: 80
With the default CNI, these pods can talk to each other based on their IP addresses. If you wanted to restrict this, you’d be looking at Network Policies that operate at the IP layer, which can be cumbersome to manage and lack granular control.
Now, let’s install Cilium. We’ll use Helm for this:
helm repo add cilium https://helm.cilium.io/
helm repo update
helm install cilium cilium/cilium \
--version 1.14.2 \
--namespace kube-system \
--set eks.enabled=true \
--set ipam.mode=kubernetes \
--set kubeProxyReplacement=strict \
--set k8sServiceHost=$(kubectl -n kube-system get service cilium -o jsonpath='{.spec.clusterIP}') \
--set k8sServicePort=$(kubectl -n kube-system get service cilium -o jsonpath='{.spec.ports[0].port}')
The eks.enabled=true flag is crucial for EKS integration. ipam.mode=kubernetes tells Cilium to manage IP addresses using Kubernetes’ own IP Address Management. kubeProxyReplacement=strict means Cilium will take over all kube-proxy functionality, which is key for performance and advanced features. The k8sServiceHost and k8sServicePort settings ensure Cilium can correctly communicate with the Kubernetes API server.
Once Cilium is installed and running, you can start enforcing policies. Let’s say we want to ensure that my-webapp can only talk to my-backend on port 80.
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-webapp-to-backend
namespace: default # Assuming both deployments are in the 'default' namespace
spec:
endpointSelector:
matchLabels:
app: my-webapp # This policy applies to the 'my-webapp' pods
ingress:
- fromEndpoints:
- matchLabels:
app: my-backend # Allow traffic originating from 'my-backend' pods
toPorts:
- ports:
- port: "80" # Only allow traffic on port 80
protocol: TCP
This policy, when applied, means that even if my-webapp tried to access another pod’s IP directly on a different port, it would be blocked by Cilium. This level of control is based on pod identity, not just IP addresses, and is enforced at the kernel level using eBPF.
The mental model for Cilium revolves around eBPF. Instead of relying on traditional kernel modules or userspace daemons for networking and policy enforcement, Cilium injects eBPF programs directly into the kernel. These programs intercept network packets at various stages and can make intelligent decisions based on rich context, including Kubernetes labels, service identity, and L7 protocol information. This bypasses much of the overhead associated with kube-proxy and iptables, leading to significantly improved performance and lower latency. Cilium doesn’t just do network policy; it also handles service load balancing, ingress, and even DNS-aware policies.
A common misconception is that Cilium is just another CNI plugin. While it is a CNI plugin, its power comes from its eBPF datapath. Cilium leverages eBPF to implement not only basic pod networking but also advanced features like NetworkPolicy enforcement, transparent encryption, and service load balancing directly within the Linux kernel. This means that many networking tasks that would traditionally involve iptables rules or kube-proxy are now handled more efficiently and with greater visibility by eBPF programs.
The next step after mastering basic NetworkPolicy is exploring L7 visibility and policy enforcement.