Skip to main content
This guide continues the hands-on exploration of Cilium network policies, focusing on Layer 4 (L4) controls and how they combine with Layer 3 (L3) and Layer 7 (L7) capabilities. Examples use egress rules for clarity, but the syntax and behavior are identical for ingress rules where noted.
A presentation slide with the word "Demo" on the left. On the right is a teal gradient shape reading "Cilium Network Policy Part 2" with a small © KodeKloud notice in the corner.

L4 egress: restrict by CIDR and port(s)

You can restrict egress by IP ranges (CIDRs) and/or by specific ports or port ranges. Use CIDR restrictions when you want to limit destinations by address space; use toPorts for port-based filtering regardless of destination. Example: allow egress to two specific CIDR ranges, and also allow a broad CIDR but exclude a few subnets/addresses.
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: l3-policy
  namespace: dev
spec:
  endpointSelector:
    matchLabels:
      app: app1
  egress:
    - toCIDR:
        - 172.16.1.0/24
        - 10.12.1.0/24
    - toCIDRSet:
        - cidr: 10.0.0.0/8
          except:
            - 10.100.0.0/24
            - 10.200.200.11/32
To restrict only by ports (L4) and allow those ports to any destination, use toPorts:
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: allow-app1-port80
  namespace: dev
spec:
  endpointSelector:
    matchLabels:
      app: app1
  egress:
    - toPorts:
        - ports:
            - port: "80"
              protocol: TCP
This policy permits pods with label app: app1 to make TCP connections only on port 80 to any IP. Terminal checks from inside an app1 pod (examples):
# Attempt to reach port 90 -> should fail (connection refused or timeout)
telnet 10.0.2.89 90

# Attempt to reach port 80 -> should succeed (if target accepts TCP)
telnet 10.0.2.89 80

Port ranges

Allow a contiguous port range using endPort (inclusive):
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: allow-app1-port-range
  namespace: dev
spec:
  endpointSelector:
    matchLabels:
      app: app1
  egress:
    - toPorts:
        - ports:
            - port: "80"
              endPort: 100
              protocol: TCP
This permits TCP ports 80–100; ports outside that range (e.g., 101) are denied.

Combine L3 (endpoints/CIDR) with L4 (ports)

For precise allowances, combine toEndpoints (L3 pod selectors) or toCIDR with toPorts. Example: allow app1 to talk to app2 only on TCP port 80.
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: app1-to-app2-port80
  namespace: dev
spec:
  endpointSelector:
    matchLabels:
      app: app1
  egress:
    - toEndpoints:
        - matchLabels:
            app: app2
      toPorts:
        - ports:
            - port: "80"
              protocol: TCP
Behavior summary:
  • app1 -> app2 on TCP/80: allowed
  • app1 -> app2 on other ports (e.g., 90): blocked
  • app1 -> any other pod: blocked (regardless of port)

L4 with CIDR destinations

You can combine L4 and L3-by-CIDR — for example, permit app1 to contact IPs in a subnet only on a specific port.
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: app1-to-subnet-port80
  namespace: dev
spec:
  endpointSelector:
    matchLabels:
      app: app1
  egress:
    - toCIDR:
        - 192.168.1.0/24
      toPorts:
        - ports:
            - port: "80"
              protocol: TCP
This allows TCP port 80 traffic from app1 to addresses in 192.168.1.0/24 only.
Egress policies are deny-by-default: when you add egress rules, Cilium blocks anything not explicitly allowed. Common control-plane traffic (for example DNS) will be blocked unless you permit it.

DNS gets blocked by default — add an explicit rule

Because egress is deny-by-default, restrictive egress policies often break DNS resolution inside pods. You must explicitly allow DNS to the cluster’s DNS service (typically CoreDNS) on port 53. Example symptom after applying a restrictive policy:
;; communications error to 10.96.0.10#53: timed out
Steps to allow DNS for app1:
  1. Find CoreDNS pod labels:
kubectl get pod -n kube-system --show-labels | grep -i coredns
  1. Create a namespaced policy that permits egress from app1 to the CoreDNS pods on port 53. DNS often uses UDP/TCP, so protocol: ANY is acceptable:
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: allow-dns-for-app1
  namespace: dev
spec:
  endpointSelector:
    matchLabels:
      app: app1
  egress:
    - toEndpoints:
        - matchLabels:
            k8s.io.kubernetes.pod.namespace: kube-system
            k8s-app: kube-dns
      toPorts:
        - ports:
            - port: "53"
              protocol: ANY
After applying the rule, DNS queries from app1 should succeed:
Server:  10.96.0.10
Address: 10.96.0.10#53

Non-authoritative answer:
Name:    google.com
Address: 142.250.176.206
If you forget to allow DNS, many higher-level application behaviors will fail (package downloads, image pulls inside pods, service discovery, etc.). Always include DNS allowances when applying restrictive egress policies.

L7: DNS filtering (match names / patterns)

Cilium’s L7 rules can match DNS queries by name or pattern. Use rules.dns to allow only specific domain names to be resolved. Example: allow only *.google.com and yahoo.com queries from app1 to CoreDNS:
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: dns-l7-restrict
  namespace: dev
spec:
  endpointSelector:
    matchLabels:
      app: app1
  egress:
    - toEndpoints:
        - matchLabels:
            k8s.io.kubernetes.pod.namespace: kube-system
            k8s-app: kube-dns
      toPorts:
        - ports:
            - port: "53"
              protocol: ANY
      rules:
        dns:
          - matchPattern: "*.google.com"
          - matchName: "yahoo.com"
Result:
  • Queries for *.google.com and yahoo.com: allowed
  • Queries for other domains (e.g., amazon.com): refused/blocked
Example from app1 after applying policy:
# Allowed
nslookup google.com

# Refused
nslookup amazon.com
;; communications error to 10.96.0.10#53: timed out

L7: HTTP filtering (method, path, headers, host)

Cilium can perform HTTP-aware L7 filtering. You can allow or deny requests based on HTTP method, path, headers, and host. The following policy lets only GET /auth requests from app1 to app2 on port 80.
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: app1-to-app2-http-get-auth
  namespace: dev
spec:
  endpointSelector:
    matchLabels:
      app: app2
  ingress:
    - fromEndpoints:
        - matchLabels:
            app: app1
      toPorts:
        - ports:
            - port: "80"
              protocol: TCP
          rules:
            http:
              - method: "GET"
                path: /auth
Test plan:
  • Start packet capture or application logs on app2 to observe incoming requests.
  • From app1:
    • curl http://<app2-ip>/auth => allowed
    • curl http://<app2-ip>/products => blocked by L7 policy
Note: If app2 has no HTTP server running, you may see connection refused. Policy enforcement can still be verified by checking whether requests are accepted or dropped at the network policy layer.

Ingress from other pods and external entities

Ingress policies follow the same selector patterns. Example: allow ingress to app1 only from pods labeled app: app2:
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: app1-ingress-from-app2
  namespace: dev
spec:
  endpointSelector:
    matchLabels:
      app: app1
  ingress:
    - fromEndpoints:
        - matchLabels:
            app: app2
If you expose a pod with a NodePort or similar, external traffic is treated as an entity outside the cluster. Use fromEntities to allow traffic from those external sources:
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: allow-nodeport-world
  namespace: dev
spec:
  endpointSelector:
    matchLabels:
      app: app1
  ingress:
    - fromEntities:
        - world
Example NodePort service exposing app1 on nodePort 30007:
apiVersion: v1
kind: Service
metadata:
  name: my-service
  namespace: dev
spec:
  type: NodePort
  selector:
    app: app1
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30007
If your cluster has a restrictive ingress policy, external curl to <nodeIP>:30007 will be blocked unless you permit fromEntities: ["world"] (or another appropriate ingress allowance).

Cilium Cluster-wide Network Policies (CCNP)

A CiliumClusterwideNetworkPolicy (CCNP) applies across all namespaces. Use a CCNP when you want the same policy to affect pods in every namespace — for example, to allow DNS cluster-wide. Example: allow all pods cluster-wide to query CoreDNS on port 53:
apiVersion: "cilium.io/v2"
kind: CiliumClusterwideNetworkPolicy
metadata:
  name: allow-dns-clusterwide
spec:
  endpointSelector: {}   # matches all pods in all namespaces
  egress:
    - toEndpoints:
        - matchLabels:
            k8s.io.kubernetes.pod.namespace: kube-system
            k8s-app: kube-dns
      toPorts:
        - ports:
            - port: "53"
              protocol: ANY
Notes:
  • A namespaced CiliumNetworkPolicy applies only to pods in that namespace. A CCNP applies cluster-wide.
  • To include or exclude specific namespaces in endpoint selectors, use the k8s.io.kubernetes.pod.namespace label in fromEndpoints/toEndpoints.

Quick reference: L3 vs L4 vs L7

LayerWhat it controlsCilium fieldsCommon use cases
L3 (Network)Destination IPs / podstoCIDR, toCIDRSet, toEndpointsRestrict to specific pods or subnets
L4 (Transport)Ports and protocolstoPorts, port, endPortAllow only specific TCP/UDP ports or ranges
L7 (Application)Protocol methods, paths, DNS namesrules: { http:, dns: }HTTP method/path filtering, DNS name filtering

Summary

  • Use toPorts for L4 port-based restrictions and toCIDR/toEndpoints for L3 (IP/pod) restrictions.
  • Combine L3 + L4 to express fine-grained policies (e.g., app1 → app2 on TCP/80).
  • Cilium policies are deny-by-default for egress; always explicitly allow control-plane traffic such as DNS.
  • Cilium supports L7 policies (DNS, HTTP, etc.) for application-aware controls.
  • Use CiliumClusterwideNetworkPolicy to apply consistent rules cluster-wide.
For advanced tactics like entities, additional L7 rules, HTTP header or host matching, consult the Cilium policy documentation above.

Watch Video

Practice Lab