Cilium doesn’t just enforce network policies; it leverages DNS to make those policies dynamically aware of service identities, allowing you to write rules based on what a service is, not just where it is.

Let’s see this in action. Imagine you have a frontend service that needs to talk to an api service, but you want to restrict the api service to only respond to requests originating from the frontend.

Here’s a simplified Kubernetes Service definition for our frontend:

apiVersion: v1
kind: Service
metadata:
  name: frontend
  namespace: default
spec:
  selector:
    app: frontend
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080

And for our api service:

apiVersion: v1
kind: Service
metadata:
  name: api
  namespace: default
spec:
  selector:
    app: api
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 8080

Now, with Cilium installed, we can define a CiliumNetworkPolicy to enforce this relationship. Notice how we’re using service: api and service: frontend – this is the key. Cilium’s DNS-aware policy engine translates these service names into the actual IP addresses that the services resolve to.

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: frontend-to-api
  namespace: default
spec:
  endpointSelector:
    matchLabels:
      app: api # This policy applies to pods with the 'app: api' label
  ingress:
    - fromEndpoints:
        - matchLabels:
            app: frontend # Allow ingress only from pods with the 'app: frontend' label
      toPorts:
        - ports:
            - protocol: TCP
              port: "8080" # The target port on the API service
          service: api # This is where DNS awareness comes in: Cilium knows 'api' resolves to a specific IP/set of IPs
    - fromEntities: # Allow ingress from the Kubernetes API server for health checks, etc.
        - cluster
        - kube-apiserver

The power here is that if the IP address of the api service changes (e.g., due to a deployment scaling up or down, or even a DNS record update), Cilium automatically detects this change and updates its internal policy enforcement without requiring a policy redeploy. It watches DNS resolutions and service IP updates.

Let’s dive a bit deeper into the mental model. Cilium uses eBPF to intercept network packets at the kernel level. When a pod tries to communicate with another service, Cilium intercepts the outgoing packet. It then consults its policy database to determine if that communication is allowed.

For DNS-based policies, Cilium has a built-in DNS proxy and parser. When a pod makes a DNS query for a service name (like api.default.svc.cluster.local), Cilium intercepts this query. It resolves the DNS name itself and caches the IP address(es). This cached IP information is then used to match against the service fields in CiliumNetworkPolicy definitions. If the policy specifies service: api, Cilium looks up the current IP(s) associated with the api service and allows traffic only to those IPs.

The endpointSelector defines which pods the policy applies to. In our example, matchLabels: app: api means this policy will only govern traffic destined for pods running the API. The ingress section defines what traffic is allowed into those pods.

Crucially, fromEndpoints and toPorts.service work together. fromEndpoints specifies the source of the traffic, and toPorts.service specifies the destination service by name. Cilium’s DNS resolver ensures that service: api dynamically maps to the correct IP(s) of the api service.

The fromEntities section is a shortcut for common, essential network entities. cluster and kube-apiserver are pre-defined entities that represent traffic originating from within the Kubernetes cluster control plane or other cluster components. This is often necessary for services to function correctly (e.g., for kube-proxy or other internal cluster services).

One subtle but powerful aspect of Cilium’s DNS-aware policies is how it handles wildcard DNS entries and service discovery. If your application relies on discovering new services dynamically or uses DNS for more than just direct IP resolution, Cilium’s DNS proxy can still intercept and process these queries. It doesn’t just resolve service-name.namespace.svc.cluster.local; it can handle more complex DNS lookups and use that information to inform policy decisions, making it incredibly flexible for microservice architectures where service IPs are ephemeral.

The next logical step after mastering DNS-based network policies is exploring how Cilium integrates with service meshes like Istio, where it can provide the underlying network enforcement for service mesh policies.

Want structured learning?

Take the full Cilium course →