Cilium Network Policies are a declarative way to define network connectivity between pods, offering a more powerful and granular alternative to Kubernetes Network Policies.

Let’s see how this works in practice with a simple scenario. Imagine we have two deployments: frontend and backend. By default, pods in these deployments can talk to each other. We want to restrict this so only the frontend pods can initiate connections to the backend pods.

First, here’s some basic setup to get our deployments running:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
spec:
  replicas: 2
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: backend
  template:
    metadata:
      labels:
        app: backend
    spec:
      containers:
      - name: httpd
        image: httpd:latest
        ports:
        - containerPort: 80

If you apply this, pods from frontend can already reach backend on port 80.

Now, let’s introduce a Cilium Network Policy to enforce our desired state. This policy will explicitly allow frontend to connect to backend on port 80, and implicitly deny all other traffic.

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "frontend-to-backend"
spec:
  endpointSelector:
    matchLabels:
      app: backend # This policy applies to pods labeled 'app: backend'
  ingress:
    - fromEndpoints:
        - matchLabels:
            app: frontend # Allow traffic originating from pods labeled 'app: frontend'
      toPorts:
        - ports:
            - port: "80"
              protocol: TCP

When you apply this policy, the frontend pods can still connect to the backend pods on port 80. However, if you try to initiate a connection from a different pod (e.g., if you had a database deployment) to the backend pod on port 80, that connection would be dropped. The frontend pods also cannot initiate connections to any other pods that might exist, unless explicitly allowed by another policy.

The power here comes from Cilium’s ability to leverage eBPF for highly efficient packet filtering at the kernel level. Unlike traditional iptables-based solutions, Cilium can make decisions directly in the kernel without needing to traverse userspace or complex rule chains for every packet. This means policies are evaluated and enforced very quickly, and the policies themselves are more expressive.

The endpointSelector in the policy defines which pods the policy applies to. In this case, it’s any pod with the label app: backend. The ingress section defines what traffic is allowed in to those selected pods. The fromEndpoints field specifies the source of the allowed traffic, and toPorts specifies the destination port and protocol on the backend pods.

Cilium Network Policies can also define egress rules, controlling what traffic originates from a set of pods. For example, to ensure frontend pods can only talk to backend pods and nothing else, you could add an egress section to a policy applied to frontend:

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "frontend-egress-control"
spec:
  endpointSelector:
    matchLabels:
      app: frontend
  egress:
    - toEndpoints:
        - matchLabels:
            app: backend
      toPorts:
        - ports:
            - port: "80"
              protocol: TCP

This policy, when applied to frontend pods, would block any outgoing connections from frontend unless they are destined for backend pods on port 80.

One of the most powerful aspects of Cilium is its ability to use identity-based security. Instead of relying solely on Kubernetes labels, Cilium assigns a unique identity to each pod. This identity can be used in policies, providing a more robust and less error-prone way to define network access, especially in dynamic environments where labels might change or be less precise. These identities are managed by the Cilium agent running on each node and are propagated cluster-wide.

When you create a Cilium Network Policy, Cilium translates these Kubernetes-style rules into eBPF programs that are attached to the network interfaces of the relevant pods. These programs inspect network packets and decide whether to allow or deny them based on the policy rules, all without leaving the kernel. This fundamentally changes how network security is managed, moving from host-based firewalls to a distributed, kernel-native enforcement model.

After implementing these policies, you might next encounter situations where you need to allow traffic from external sources into your cluster, or manage more complex inter-service communication patterns like mutual TLS encryption.

Want structured learning?

Take the full Cilium course →