Tag Archives: Cilium Network Policy

cilium header

Cilium Network Policies, from first principles to production

This post teaches the Cilium policy model with clear scenarios and annotated YAML. It matches the style of practical technical blogs, explanation first and code second, with links to the official docs where you will want deeper detail.

Why Cilium policy

Kubernetes’ built-in NetworkPolicy objects define which pods can communicate using label-based rules at the IP and port level. This provides basic isolation, but it stops short of deeper visibility or intent-based control.

Cilium builds on this foundation by introducing security identities derived from labels. These identities represent workloads consistently across nodes and are enforced directly in the kernel using eBPF. Because enforcement happens in the datapath, policies remain accurate and efficient even as workloads scale or IPs change.

Beyond IP and port filtering, Cilium understands application context such as DNS names and HTTP methods and paths. This makes it possible to express policies in human terms — for example, “allow only GET requests on /health from pods with role=frontend” or “allow egress only to api.partner.com.”

Together, these capabilities create a single, consistent model for enforcing and observing network behavior across all workloads. This post walks through that model step by step, with practical YAML examples you can apply to your own environment.

For further reading, see the official Cilium policy overview for the complete language reference and selector options.

Mental model

Every policy answers four things. Where to enforce, which direction to guard, who may talk, and whether to apply checks at the application layer.

These are the top things to keep in mind when defining a Cilium Network Policy.

  • Subject, choose pods with endpointSelector or nodes with nodeSelector
  • Direction, if a selected subject has an ingress list then ingress becomes default deny for that subject, the same idea applies for egress
  • Peers, choose with fromEndpoints, toEndpoints, toEntities, toCIDRSet, toFQDNs, toServices
  • Application layer, add optional rules: under toPorts for HTTP or DNS

Language details are in the Cilium policy language.

We typically refer to the security policies implemented in Cilium holistically as “Cilium Network Policy”. However when you dive into using them in your platform, you will find there is in fact two types of policy configuration to be aware of. Essentially most of the information in this post is true for both types. But just keep in mind the following;

  • CiliumNetworkPolicy (CNP) is the namespaced policy object you apply to control traffic for pods within a single namespace.
    CiliumClusterwideNetworkPolicy (CCNP) is the cluster-scoped version. It uses the same language and selectors but applies across all namespaces, which is useful for node policies, global DNS interception, or rules that span multiple teams.

What a Cilium endpoint is

Every pod (and any process that Cilium manages traffic for) is represented inside Cilium as an endpoint. An endpoint is essentially Cilium’s view of a workload: its labels, Security Identity, policies, and network state.

When you write a policy with an endpointSelector, you’re telling Cilium “apply this rule to the endpoints whose labels match this selector.” Cilium uses that to program the eBPF datapath on the node where each endpoint lives.

You can see endpoints on a node with:

kubectl -n kube-system exec -ti ds/cilium -- cilium endpoint list
Each row in the table is one Cilium endpoint. An endpoint represents a pod or other workload that Cilium is managing on that node. The columns tell you at a glance what Cilium knows about it and how policies apply.
  • ENDPOINT: This is Cilium’s internal endpoint ID on that node. In this case, 24. You’ll use this ID if you run cilium endpoint get 24 for detailed info.

  • POLICY (ingress / egress): Shows whether policy enforcement is active on this endpoint. “Disabled” means there are no Cilium policies selecting it yet for that direction, so all traffic is allowed. Once you create a CiliumNetworkPolicy with an ingress or egress section matching this endpoint, this field will flip to “Enabled”.

  • IDENTITY: The numeric Security Identity assigned to the set of identity-relevant labels for this endpoint (69014 here). Cilium uses this number in the datapath to represent the workload.

  • LABELS (source:key=value): The full list of labels that Cilium knows for this endpoint. The prefix shows where the label came from (k8s: means Kubernetes label). These are the labels you match on in your policies. In the example, it includes app=minio, the namespace, the service account, and some Helm-related labels.

  • IPv4 / IPv6: The IP addresses currently assigned to that pod. Notice you never use them directly in your policies; Cilium maps them to the Security Identity automatically. Note: there is the ability to specify CIDR-based filtering in a Cilium Network Policy as well, but this is recommended not to be used to for filtering when it comes to Pod traffic inside the cluster.

  • STATUS: Shows the endpoint’s state from Cilium’s perspective (“ready” means it’s healthy and being managed).

ENDPOINT   POLICY (ingress)   POLICY (egress)   IDENTITY   LABELS (source:key[=value])                                                                IPv6   IPv4         STATUS   
           ENFORCEMENT        ENFORCEMENT                                                                                                                                 
24         Disabled           Disabled          69014      k8s:app.kubernetes.io/managed-by=Helm                                                             10.0.0.247   ready   
                                                           k8s:app=minio                                                                                                          
                                                           k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=minio                                                   
                                                           k8s:io.cilium.k8s.policy.cluster=kind                                                                                  
                                                           k8s:io.cilium.k8s.policy.serviceaccount=quickstart-sa                                                                  
                                                           k8s:io.kubernetes.pod.namespace=minio                                                                                  
                                                           k8s:v1.min.io/console=quickstart-console                                                                               
                                                           k8s:v1.min.io/pool=ss-0

This view is invaluable when troubleshooting, and we’ll cover this towards the end of the blog post.

Labels and Security Identity

Continue reading Cilium Network Policies, from first principles to production