Skip to content

Test 4: ChunkHound Response

NetworkPolicy to iptables: Complete Code Path Analysis

Section titled “NetworkPolicy to iptables: Complete Code Path Analysis”

This document traces the complete transformation path of Kubernetes NetworkPolicy objects into actual iptables rules on nodes. The analysis reveals that Kubernetes core provides zero NetworkPolicy enforcement - the entire transformation from policy objects to network rules happens in external CNI plugins through a sophisticated watch-and-enforce architecture.

┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ API Server │ │ CNI Plugin │ │ Linux Kernel │
│ │ │ (DaemonSet) │ │ │
│ ┌─────────────┐ │ │ ┌──────────────┐ │ │ ┌─────────────┐ │
│ │NetworkPolicy│ │───▶│ │Policy Engine │ │───▶│ │ iptables/ │ │
│ │ (etcd) │ │ │ │ (Watch) │ │ │ │ eBPF │ │
│ └─────────────┘ │ │ └──────────────┘ │ │ └─────────────┘ │
└─────────────────┘ └──────────────────┘ └─────────────────┘
^ ^ ^
│ │ │
Store Only Watch & Translate Enforce Rules

1. Kubernetes NetworkPolicy API (Storage Only)

Section titled “1. Kubernetes NetworkPolicy API (Storage Only)”

Location: pkg/apis/networking/types.go:27-209

Key Finding: Kubernetes core only provides the API contract and validation - no enforcement logic exists.

type NetworkPolicy struct {
metav1.TypeMeta
metav1.ObjectMeta
Spec NetworkPolicySpec
}
type NetworkPolicySpec struct {
PodSelector metav1.LabelSelector
Ingress []NetworkPolicyIngressRule
Egress []NetworkPolicyEgressRule
PolicyTypes []PolicyType // ["Ingress"], ["Egress"], or both
}
  • No Controller: No NetworkPolicy controller in Kubernetes core
  • No Enforcement: API server only stores and validates policies
  • CNI Dependency: Requires CNI plugin for any actual network enforcement

2. CNI Plugin Architecture (The Real Implementation)

Section titled “2. CNI Plugin Architecture (The Real Implementation)”

Evidence: cluster/addons/calico-policy-controller/calico-node-daemonset.yaml:76-94

All NetworkPolicy enforcement happens through CNI plugins running as DaemonSets:

containers:
- name: calico-node
image: gcr.io/projectcalico-org/node:v3.19.1
env:
- name: CALICO_MANAGE_CNI
value: "true"
- name: DATASTORE_TYPE
value: "kubernetes"
  1. API Watching: Monitor NetworkPolicy, Pod, Namespace, and Service resources
  2. Label Resolution: Convert selectors to actual Pod IPs and ports
  3. Rule Translation: Transform high-level policies to low-level network rules
  4. Kernel Programming: Apply iptables/eBPF/OVS rules to enforce policies

3. Kube-proxy’s Explicit Non-Involvement

Section titled “3. Kube-proxy’s Explicit Non-Involvement”

Evidence: cmd/kube-proxy/app/server.go:104-110

// "The Kubernetes network proxy runs on each node. This reflects services
// as defined in the Kubernetes API on each node and can do simple TCP, UDP,
// and SCTP stream forwarding"

Key Findings:

  • Zero NetworkPolicy Code: Exhaustive search reveals no NetworkPolicy handling in kube-proxy
  • Architectural Separation: Services (load balancing) vs NetworkPolicy (security filtering)
  • Coordination Mechanism: CNI plugins coordinate with kube-proxy via priority-based rule ordering

Separation Table:

AspectServices (Kube-proxy)NetworkPolicy (CNI)
PurposeLoad balancing & routingSecurity filtering
Enforcementiptables/IPVS/nftablesCNI-specific implementation
Traffic FlowDNAT service IPs to endpointsFilter based on selectors
IntegrationDirect kernel programmingPlugin-based architecture

1. Iptables-Based Implementations (Calico, Flannel)

Section titled “1. Iptables-Based Implementations (Calico, Flannel)”

Evidence: cluster/addons/calico-policy-controller/felixconfigurations-crd.yaml

  • Chain Organization: Uses cali-* prefixed chains
    • cali-tw-<endpoint> (to-workload)
    • cali-fw-<endpoint> (from-workload)
    • cali-pi-<policy> (policy ingress)
    • cali-po-<policy> (policy egress)
Terminal window
# Example NetworkPolicy translation:
# podSelector: app=web
# ingress.from.podSelector: app=frontend
# Becomes iptables rules:
-A cali-tw-web-pod -m set --match-set cali-frontend-pods src -j ACCEPT
-A cali-tw-web-pod -j DROP

Location: cluster/addons/calico-policy-controller/networkpolicies-crd.yaml:1-1163

Calico extends basic NetworkPolicy with:

  • HTTP Matching: L7 policy enforcement
  • Service Account Selectors: Identity-based rules
  • Negation Operators: notPorts, notNets, notSelector
  • Global Policies: Cluster-wide rules

Evidence: cluster/addons/calico-policy-controller/felixconfigurations-crd.yaml:63-81

bpfEnabled: true
bpfDataIfacePattern: "^(en.*|eth.*|tunl0$)"
bpfDisableUnprivileged: true
  • Kernel Integration: eBPF programs attached to network interfaces
  • Map-based Storage: Policy lookups via eBPF maps instead of rule chains
  • Dynamic Compilation: Policies compiled to eBPF bytecode at runtime
  • Performance: Bypasses netfilter overhead for better performance

Cilium’s eBPF architecture enables:

  • HTTP/gRPC Filtering: Application-layer policy enforcement
  • DNS-based Rules: Policy based on DNS names
  • Service Mesh Integration: Envoy proxy integration for advanced L7 features

Many CNI plugins support multiple enforcement mechanisms:

# iptables mode (default)
bpfEnabled: false
# eBPF mode (performance)
bpfEnabled: true
bpfExternalServiceMode: "DSR" # Direct Server Return

Evidence: vendor/sigs.k8s.io/knftables/types.go:104-144

NetworkPolicy enforcement leverages multiple netfilter hooks:

PreroutingHook BaseChainHook = "prerouting" // Initial packet processing
InputHook BaseChainHook = "input" // Local delivery
ForwardHook BaseChainHook = "forward" // Packet forwarding
OutputHook BaseChainHook = "output" // Local origination
PostroutingHook BaseChainHook = "postrouting" // Final processing

Evidence: pkg/proxy/nftables/proxier.go:401-414

Careful coordination between kube-proxy and CNI plugins:

// Service DNAT (kube-proxy) - Priority: DNAT
{natPreroutingChain, knftables.NATType, knftables.PreroutingHook, knftables.DNATPriority}
// NetworkPolicy filtering (CNI) - Priority: Filter (after DNAT)
// CNI plugins see post-DNAT traffic (endpoint IPs, not service IPs)

Evidence: pkg/util/iptables/testing/parse_test.go:300-336

Real iptables rules generated by kube-proxy (for context):

Terminal window
# Service load balancing
-A KUBE-SERVICES -m comment --comment "ns1/svc1:p80 cluster IP" \
-m tcp -p tcp -d 10.20.30.41 --dport 80 -j KUBE-SVC-XPGD46QRK7WJZT7O
# DNAT to endpoint
-A KUBE-SEP-SXIVWICOYRO3J4NJ -m comment --comment ns1/svc1:p80 \
-m tcp -p tcp -j DNAT --to-destination 10.180.0.1:80

CNI plugins would add NetworkPolicy rules that see this post-DNAT traffic.

Evidence: pkg/proxy/iptables/proxier.go:84-87

// Switch to "large cluster mode" at 1000+ endpoints
largeClusterEndpointsThreshold = 1000

CNI plugins implement similar optimizations:

  • Incremental Updates: Only modify changed rules
  • Rule Caching: Avoid regenerating identical rules
  • Batch Operations: Group multiple changes

Evidence: pkg/proxy/iptables/proxier.go:735-759

func (proxier *Proxier) syncProxyRules() (retryError error) {
doFullSync := proxier.needFullSync ||
(time.Since(proxier.lastFullSync) > proxyutil.FullSyncPeriod)
// Performance metrics tracking
metrics.SyncProxyRulesLatency.WithLabelValues(string(proxier.ipFamily)).Observe(
metrics.SinceInSeconds(start))
}
kubectl apply -f networkpolicy.yaml
API Server validation & storage in etcd
NetworkPolicy object available via watch API
CNI Plugin (DaemonSet) watches NetworkPolicy changes
Query Pods matching spec.podSelector
Query Namespaces matching ingress/egress rules
Resolve labels to actual Pod IPs and ports
Generate CNI-specific rules (iptables/eBPF/OVS)
CNI Plugin programs kernel networking
iptables/eBPF/OVS rules active
Network packets filtered according to policy
  • Kubernetes: Policy specification and storage
  • CNI Plugins: Policy implementation and enforcement
  • Linux Kernel: Actual packet filtering
  • Technology Choice: iptables vs eBPF vs OVS based on requirements
  • Feature Extensions: L7 policies, identity-based rules, global policies
  • Performance Optimization: Each plugin optimizes for their use cases
  • Label Resolution: Converting selectors to IPs requires watching multiple resources
  • Dynamic Updates: Handling pod/namespace changes that affect existing policies
  • Coordination: Ensuring CNI rules don’t conflict with kube-proxy rules
  • Kubernetes logs won’t show enforcement problems
  • Must check CNI plugin logs and configuration
  • Different CNI plugins have different debugging approaches
Terminal window
# iptables-based CNIs
iptables -L -n | grep cali-
# eBPF-based CNIs (Cilium)
cilium bpf policy get
# OVS-based CNIs
ovs-ofctl dump-flows br0
  1. Verify CNI plugin supports NetworkPolicy
  2. Check CNI plugin DaemonSet status
  3. Examine CNI plugin logs for policy translation errors
  4. Inspect actual kernel rules (iptables/eBPF/OVS)
  5. Test connectivity with policy temporarily disabled

The transformation from NetworkPolicy objects to iptables rules represents one of Kubernetes’ most sophisticated delegation patterns. Rather than implementing network enforcement directly, Kubernetes provides a clean API contract and delegates all implementation to specialized CNI plugins. This approach enables innovation in network enforcement technologies while maintaining a consistent policy interface for users.

The complete absence of enforcement logic in Kubernetes core, combined with the architectural separation from kube-proxy, demonstrates a careful separation of concerns that enables the diverse ecosystem of CNI implementations we see today - from traditional iptables-based approaches to cutting-edge eBPF implementations.


Analysis Sources: Kubernetes v1.29+ codebase, focusing on pkg/apis/networking/, pkg/proxy/, CNI addon configurations, and netfilter integration points.