✦ For everyone, free.

Practical knowledge for real and everyday life

Home

Kubernetes Network Address Translation

Kubernetes Network Address Translation enables efficient communication between containers by translating IP addresses and ports within a cluster's network infrastructure.

Kubernetes Network Address Translation is the set of packet address rewriting mechanisms that Kubernetes and its supporting components (kube-proxy, the CNI plugin, cloud load balancers) apply so that Pods with ephemeral, cluster-internal IP addresses can be reached through stable Service IPs, and so that Pods can reach destinations outside the cluster network without every node needing externally routable Pod subnets. It covers destination NAT (DNAT) for Service-to-Pod translation, source NAT (SNAT) for outbound Pod traffic, and the specific rules that determine when NAT is skipped for performance or correctness reasons.


Destination NAT: Service to Pod

The ClusterIP Rewrite

When a client sends a packet to a Service's ClusterIP, that address is a virtual IP with no corresponding network interface. kube-proxy programs DNAT rules (via iptables, IPVS, or an eBPF dataplane) that rewrite the packet's destination address and port from the ClusterIP:port pair to the address of a selected backend Pod drawn from the Service's EndpointSlice, before the packet is routed onward.

# Inspect iptables DNAT rules kube-proxy generates for a Service
iptables -t nat -L KUBE-SERVICES -n | grep <service-cluster-ip>

iptables Mode Mechanics

In iptables mode, kube-proxy creates a chain per Service (KUBE-SVC-*) that probabilistically jumps to one of several per-endpoint chains (KUBE-SEP-*), each containing a DNAT target rewriting the destination to a specific Pod IP and port. The random selection across endpoint chains approximates load balancing without a userspace proxy in the data path.

IPVS Mode Mechanics

In IPVS mode, kube-proxy instead creates a virtual server for each Service ClusterIP and registers backend Pods as real servers, letting the Linux kernel's IPVS subsystem perform DNAT using one of several selectable scheduling algorithms (round robin, least connection, etc.), which scales better than iptables for clusters with very large numbers of Services.


Source NAT for Outbound and Return Traffic

SNAT on Egress to External Destinations

Pod IP addresses are usually only routable within the cluster's private Pod network. When a Pod sends traffic to a destination outside the cluster, the node's CNI plugin typically applies SNAT, rewriting the packet's source address to the node's own IP so that return traffic can find its way back through the node's normal routing table.

Masquerade Rules and Non-Masquerade CIDRs

Kubernetes nodes commonly run an ip-masq-agent or equivalent iptables MASQUERADE rule that SNATs traffic destined outside a configured non-masquerade CIDR range (typically the cluster's own Pod and Service CIDRs plus RFC 1918 private ranges). Traffic between Pods, and traffic to other cluster nodes, is excluded from masquerading so that Pod-to-Pod communication preserves original Pod source IPs.

nonMasqueradeCIDRs:
  - 10.0.0.0/8
  - 172.16.0.0/12
  - 192.168.0.0/16
masqLinkLocal: false

SNAT and externalTrafficPolicy Interaction

When a Service uses externalTrafficPolicy: Cluster, kube-proxy applies SNAT to inbound external traffic that gets forwarded to a Pod on a different node, replacing the original client IP with the receiving node's IP so that the destination Pod's return traffic routes back through the same node. Setting externalTrafficPolicy: Local avoids this hop and this SNAT, preserving the original client source IP for Pods on the node that first received the packet.


Hairpin NAT and Loopback Traffic

The Hairpin Problem

A Pod that calls back to its own Service IP and happens to be load-balanced to itself faces a routing quirk: without special handling, the return packet may not traverse the same DNAT/SNAT path and gets dropped by the kernel's reverse path filtering. This is commonly called the hairpin NAT problem.

hairpin-mode and Masquerade-All Fixes

CNI bridge plugins expose a hairpinMode setting on the bridge interface, and kube-proxy applies a masquerade rule specifically for hairpin traffic (rewriting the source address to the node/bridge address for self-directed Service calls), ensuring the return packet is recognized as belonging to an existing connection rather than being treated as a new, invalid one.


NAT-Free Paths and Their Advantages

Direct Server Return

Some load balancer integrations support Direct Server Return, where inbound traffic is DNAT'd to reach a Pod, but the Pod's response is sent directly back to the client, bypassing the load balancer for the return path and avoiding an extra NAT/routing hop, at the cost of requiring the backend to be L2-adjacent or otherwise specially routed to the client-facing network.

CNI Plugins with Routed Pod Networks

CNIs such as Calico in BGP mode assign Pod IPs from routable subnets advertised throughout the underlying network fabric, which eliminates the need for SNAT on Pod-to-Pod traffic across nodes since every node already knows how to route directly to any Pod subnet without translation.

eBPF Dataplanes and NAT Offload

eBPF-based dataplanes (such as Cilium's kube-proxy replacement) perform the equivalent of DNAT/SNAT translation at the socket layer or in earlier hook points (tc, XDP) rather than through iptables/netfilter conntrack, reducing the per-packet overhead of connection tracking lookups while producing functionally equivalent address translation results.


Observability and Debugging NAT Behavior

Inspecting Connection Tracking

The kernel's conntrack table records every NAT translation Kubernetes networking components create, and inspecting it directly reveals what a packet's original and translated address/port pairs were.

conntrack -L -n | grep <pod-ip>

Common Symptoms of NAT Misconfiguration

Source IP visibility loss at the application layer (seeing node IPs instead of real client IPs) typically points to externalTrafficPolicy: Cluster or a mesh sidecar rewriting addresses; dropped hairpin connections manifest as a Pod being unable to reach its own Service IP; and asymmetric routing after a NAT rule change often surfaces as connections that establish but never receive a response, since return traffic takes a path the conntrack table does not recognize as belonging to the original connection.