Skip to content
Published on

Cilium Network Policy Engine: L3/L4/L7 Filtering Implementation

Authors

Cilium Network Policy Engine: L3/L4/L7 Filtering Implementation

Overview

Cilium's network policy engine extends Kubernetes NetworkPolicy to provide fine-grained traffic control at L3/L4/L7 levels. It combines eBPF with Envoy proxy in a hybrid architecture that achieves both high performance and flexibility.

1. Policy Repository and Rule Compilation

1.1 Policy Sources

Cilium collects network policies from multiple sources:

Policy sources:
1. Kubernetes NetworkPolicy
   - Standard L3/L4 policies
   - Automatically translated and applied by Cilium

2. CiliumNetworkPolicy (CNP)
   - Namespace-scoped Cilium extended policy
   - Advanced features: L7, FQDN, Identity-based

3. CiliumClusterwideNetworkPolicy (CCNP)
   - Cluster-wide policies
   - Default deny policies, common security rules

4. CiliumEnvoyConfig (CEC)
   - Envoy proxy L7 traffic management rules

1.2 Policy Repository

The policy repository within the Agent manages all policies in a unified manner:

Policy collection flow:

K8s API Server
    |
    v
[Watcher: NetworkPolicy]  ->  Policy Repository
[Watcher: CNP]             ->  Policy Repository
[Watcher: CCNP]            ->  Policy Repository
                                    |
                                    v
                               [Policy Computation Engine]
                                    |
                                    v
                               [Per-Endpoint Policy Set]
                                    |
                                    v
                               [BPF Program Compilation]

1.3 Translation from Policy to BPF Maps

CiliumNetworkPolicy YAML
    |
    v
Parse and normalize policy
    |
    v
Selector matching: determine affected endpoints
    |
    v
Generate Identity-based allow list
    |
    v
Update BPF policy maps:
  Add entries to cilium_policy_<endpoint_id> map
  Key: (Identity, port, protocol)
  Value: (allow/deny, proxy port)
    |
    v
Regenerate endpoint BPF programs (if needed)

2. Identity-Based vs IP-Based Enforcement

2.1 Identity-Based Enforcement

This is Cilium's default policy enforcement method, using numeric Identities instead of IP addresses:

Traditional IP-based firewall:
  Allow: 10.244.1.5 -> 10.244.2.10:8080
  Problem: IP changes when Pod restarts

Cilium Identity-based:
  Allow: Identity 48291 (app=frontend) -> Identity 52103 (app=backend):8080
  Advantage: Policy persists regardless of IP changes
# Check policy map contents (by endpoint ID)
cilium bpf policy get 1234

# Example output:
# POLICY   DIRECTION   IDENTITY   PORT/PROTO   PROXY PORT   ENTRY TYPE
# Allow    Ingress     48291      8080/TCP     0            allow
# Allow    Ingress     52103      443/TCP      0            allow
# Allow    Egress      0          53/UDP       0            allow (DNS)

2.2 Policy Map Structure

// Policy map key (conceptual)
struct policy_key {
    __u32 identity;      // Source/destination Identity
    __u16 dport;         // Destination port (0 = all ports)
    __u8  protocol;      // TCP, UDP, ICMP
    __u8  direction;     // ingress(1), egress(2)
};

// Policy map value
struct policy_entry {
    __u8  action;        // allow(1), deny(2), audit(3)
    __u16 proxy_port;    // L7 proxy port (0 = no proxy)
    __u8  auth_type;     // Auth type (mTLS, etc.)
    __u64 packets;       // Matched packet counter
    __u64 bytes;         // Matched byte counter
};

2.3 Policy Lookup Algorithm

Policy lookup on packet receive:

1. Look up Identity from source IP (ipcache)
2. Search in policy map for (Identity, Port, Protocol) combination
3. Exact match attempt:
   - Check (src_identity, dst_port, protocol)
4. Wildcard match:
   - Check (src_identity, ANY_PORT, protocol)
   - Check (ANY_IDENTITY, dst_port, protocol)
5. Check Deny rules first:
   - If Deny exists, unconditionally deny
6. Result: Allow / Deny / Audit

3. L3/L4 Enforcement: High-Speed Filtering in eBPF

3.1 L3 Policy (Network Layer)

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: l3-policy-example
spec:
  endpointSelector:
    matchLabels:
      app: backend
  ingress:
    - fromEndpoints:
        - matchLabels:
            app: frontend
    - fromCIDR:
        - 10.0.0.0/8
    - fromEntities:
        - world
  egress:
    - toEndpoints:
        - matchLabels:
            app: database
    - toCIDR:
        - 0.0.0.0/0
      toCIDRSet:
        - cidr: 0.0.0.0/0
          except:
            - 169.254.169.254/32

3.2 L4 Policy (Transport Layer)

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: l4-policy-example
spec:
  endpointSelector:
    matchLabels:
      app: backend
  ingress:
    - fromEndpoints:
        - matchLabels:
            app: frontend
      toPorts:
        - ports:
            - port: '8080'
              protocol: TCP
            - port: '8443'
              protocol: TCP
  egress:
    - toEndpoints:
        - matchLabels:
            app: database
      toPorts:
        - ports:
            - port: '5432'
              protocol: TCP

3.3 L3/L4 Enforcement Flow in eBPF

Packet: src=10.244.1.5:34567 dst=10.244.2.10:8080 TCP

1. [from-container or to-container BPF program]

2. Source Identity lookup:
   ipcache[10.244.1.5] -> Identity: 48291

3. Policy map lookup:
   Search in policy_map[endpoint_id]:
   key = (identity=48291, port=8080, proto=TCP, dir=ingress)

4. Result:
   - Allow: Continue packet delivery
   - Deny: Drop packet + monitor event
   - L7 Redirect: Redirect to Envoy proxy port

4. L7 Enforcement: Envoy Proxy Integration

4.1 L7 Policy Overview

L7 policies provide application protocol-level filtering:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: l7-http-policy
spec:
  endpointSelector:
    matchLabels:
      app: api-server
  ingress:
    - fromEndpoints:
        - matchLabels:
            app: frontend
      toPorts:
        - ports:
            - port: '8080'
              protocol: TCP
          rules:
            http:
              - method: GET
                path: '/api/v1/users'
              - method: GET
                path: '/api/v1/products'
              - method: POST
                path: '/api/v1/orders'
                headers:
                  - 'Content-Type: application/json'

4.2 L7 Redirect Mechanism

Traffic flow with L7 policy applied:

Pod A -> [from-container BPF]
    |
    v (policy map: L7 proxy redirect needed)
    |
    v
[tc redirect to Envoy proxy port]
    |
    v
[Envoy Proxy (1 per node)]
  - HTTP/gRPC/Kafka parsing
  - L7 rule matching
  - Allow/deny decision
    |
    v (if allowed)
    |
    v
[Forward to destination via BPF]
    |
    v
Pod B

4.3 Supported Protocols

ProtocolFilterable Fields
HTTPmethod, path, headers, host
gRPCservice, method
Kafkatopic, clientID, apiKey, apiVersion
DNSquery name pattern (matchName, matchPattern)

4.4 Kafka L7 Policy Example

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: kafka-policy
spec:
  endpointSelector:
    matchLabels:
      app: kafka-consumer
  egress:
    - toEndpoints:
        - matchLabels:
            app: kafka-broker
      toPorts:
        - ports:
            - port: '9092'
              protocol: TCP
          rules:
            kafka:
              - role: consume
                topic: 'orders'
              - role: consume
                topic: 'events'

5. FQDN Policies: DNS Proxy Integration

5.1 How FQDN Policies Work

FQDN policy flow:

1. Policy definition:
   toFQDNs:
     - matchName: "api.example.com"

2. Cilium DNS proxy activation:
   - Transparently intercept Pod DNS traffic
   - Learn IP addresses from DNS responses

3. IP cache update:
   DNS response: api.example.com -> 203.0.113.10, 203.0.113.11
   |
   v
   Add IP -> FQDN mapping to ipcache
   Add allow rules for those IPs to BPF policy map

4. Traffic allow/block:
   - Only allow traffic to learned IPs
   - Mapping expires and refreshes based on DNS TTL

5.2 FQDN Policy Example

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: fqdn-policy
spec:
  endpointSelector:
    matchLabels:
      app: backend
  egress:
    - toFQDNs:
        - matchName: 'api.external-service.com'
      toPorts:
        - ports:
            - port: '443'
              protocol: TCP
    - toFQDNs:
        - matchPattern: '*.storage.googleapis.com'
      toPorts:
        - ports:
            - port: '443'
              protocol: TCP
    - toEndpoints:
        - matchLabels:
            io.kubernetes.pod.namespace: kube-system
            k8s-app: kube-dns
      toPorts:
        - ports:
            - port: '53'
              protocol: UDP
          rules:
            dns:
              - matchPattern: '*'

6. CiliumNetworkPolicy vs CiliumClusterwideNetworkPolicy

6.1 Scope Differences

CiliumNetworkPolicy (CNP):
  - Namespace scope
  - endpointSelector selects Pods in the same namespace
  - Cross-namespace via namespaceSelector in fromEndpoints/toEndpoints

CiliumClusterwideNetworkPolicy (CCNP):
  - Cluster scope
  - Can select specific nodes with nodeSelector
  - Applies across all namespaces
  - Suitable for cluster-level default policies

6.2 CCNP Example

apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
  name: default-deny-ingress
spec:
  endpointSelector: {}
  ingress:
    - fromEntities:
        - cluster

6.3 Host Policy

apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
  name: host-firewall
spec:
  nodeSelector:
    matchLabels:
      node-role.kubernetes.io/worker: ''
  ingress:
    - fromEntities:
        - remote-node
        - health
      toPorts:
        - ports:
            - port: '10250'
              protocol: TCP
    - fromCIDR:
        - 10.0.0.0/8
      toPorts:
        - ports:
            - port: '22'
              protocol: TCP

7. Policy Audit Mode

7.1 Audit Mode Operation

In audit mode, policy-violating traffic is not blocked but only logged:

# Set endpoint to audit mode
cilium endpoint config 1234 PolicyAuditMode=Enabled

# Global audit mode
cilium config PolicyAuditMode=true

# Check audit logs
cilium monitor --type policy-verdict

# Example output:
# Policy verdict log: flow ... action audit
# -> Would be DROPPED by policy (ingress)
# Identity: 48291 -> 52103, port 8080/TCP

7.2 Transitioning from Audit to Enforcement

Audit mode workflow:

Step 1: Enable audit mode
  -> All traffic allowed, violations logged

Step 2: Analyze traffic patterns with Hubble
  -> Identify actual required communication paths

Step 3: Write policies and compare with audit results
  -> Verify no unintended blocks

Step 4: Disable audit mode
  -> Actual policy enforcement begins

8. Endpoint Regeneration and Policy Changes

8.1 Regeneration Process on Policy Change

Policy change detected:
    |
    v
Determine affected endpoints:
  - All endpoints matching the selector
  - Including indirect impact via Identity references
    |
    v
Recompute policy maps:
  - Generate new allow/deny rule set
  - Compare with existing policy map (apply diff only)
    |
    v
Update BPF maps:
  - Add/delete entries in cilium_policy map
  - Atomic updates to minimize packet loss
    |
    v
Recompile BPF programs (if needed):
  - When L7 redirect is added/removed
  - When program logic changes are required
    |
    v
Update endpoint state: Ready

8.2 Regeneration Performance Optimization

Optimization techniques:

1. Incremental updates:
   - Update only BPF maps instead of full recompilation
   - Most policy changes only need map updates

2. Batch regeneration:
   - Batch multiple policy changes in a short timeframe
   - Prevent unnecessary duplicate regenerations

3. Selective regeneration:
   - Only regenerate affected endpoints
   - Precisely calculate impact scope based on Identity

9. Deny Policies

9.1 Deny Rule Behavior

Cilium supports explicit Deny rules, which always take precedence over Allow:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: deny-specific-cidr
spec:
  endpointSelector:
    matchLabels:
      app: backend
  egressDeny:
    - toCIDR:
        - 169.254.169.254/32
      toPorts:
        - ports:
            - port: '80'
              protocol: TCP
  egress:
    - toCIDR:
        - 0.0.0.0/0
      toPorts:
        - ports:
            - port: '443'
              protocol: TCP

9.2 Policy Priority

Policy evaluation order:

1. Check Deny rules
   - If matching Deny rule exists, immediately deny
   - Ignore Allow rules

2. Check Allow rules
   - If matching Allow rule exists, allow

3. Default behavior
   - If policies exist for that direction (ingress/egress): default deny
   - If no policies at all: default allow

10. Policy Troubleshooting

10.1 Debugging Commands

# Check applied policies
cilium policy get

# Per-endpoint policy state
cilium endpoint get 1234

# Policy map contents
cilium bpf policy get 1234

# Look up labels from Identity
cilium identity get 48291

# Policy verdict monitoring
cilium monitor --type policy-verdict

# Check dropped packets
cilium monitor --type drop

10.2 Common Issues and Solutions

Issue: Pod-to-Pod communication blocked
Possible causes:
1. Identity not correctly assigned
   -> Verify with cilium identity list
2. Policy selector is incorrect
   -> Check applied policies with cilium policy get
3. DNS egress policy missing
   -> DNS allow is required when using FQDN policies

Issue: L7 policy not applied
Possible causes:
1. Envoy proxy not functioning properly
   -> Check Proxy status in cilium status
2. Syntax error in rules under toPorts
   -> Check parsed result with cilium policy get

Summary

Cilium's network policy engine provides robust traffic control through a multi-layered security model:

  • Identity-Based Enforcement: Applies policies based on labels, not IP addresses, ensuring stability in dynamic environments
  • eBPF High-Speed Filtering: L3/L4 policies applied directly in the kernel for minimal latency
  • Envoy L7 Integration: Application-level filtering for HTTP, gRPC, Kafka
  • FQDN Policies: Domain-based egress control through DNS proxy
  • Deny Precedence: Explicit deny rules always take priority for stronger security
  • Audit Mode: Assess impact before enforcing policies
  • Incremental Updates: Apply policy changes with minimal regeneration