Designing an IPv6-First Kubernetes Cluster
What it actually takes to run Pods on globally routable IPv6 addresses — the network layout, the bootstrap dependencies, and why IPv6-first…
Designing an IPv6-First Kubernetes Cluster
What it actually takes to run Pods on globally routable IPv6 addresses — the network layout, the bootstrap dependencies, and why IPv6-first is architecturally cleaner than the NAT model most clusters still use.
Most Kubernetes clusters use private IPv4 addresses for Pods and rely on NAT for outbound internet connectivity. It works — but it consumes limited private IPv4 address space, adds another stateful component to the network path, and introduces additional data-processing costs as traffic passes through the NAT gateway. AWS charges NAT gateways both hourly and per gigabyte of data processed.
IPv6-first changes the model fundamentally.
With Amazon EKS in IPv6 mode, Pods and Kubernetes Services receive IPv6 addresses while the underlying VPC and nodes retain IPv4 for compatibility. EKS does not support dual-stacked Pods or Services, so the VPC is dual-stack, but the Kubernetes cluster itself uses IPv6 as its Pod and Service address family.
For IPv6-to-IPv6 traffic, Pods can communicate using their own globally routable IPv6 addresses without source NAT. The destination sees the Pod’s IPv6 address rather than a shared NAT address.
This post walks through the design I used to implement it — four layers, each with one clear job.
With IPv6-first networking, Pods can have globally routable identities. Security comes from routing and policy, not from hiding workloads behind NAT.

The Network: Dual-Stack, Three Availability Zones
The virtual network is dual-stack — it carries both an IPv4 block and an IPv6 block. IPv4 stays because the underlying AWS infrastructure and external services still require IPv4 compatibility. IPv6 is what Kubernetes uses for Pod and Service addressing.
Subnets are spread across three availability zones. Each zone gets two subnet tiers: a public one for load balancers and edge-facing components, and a private one where workloads run. Every subnet has both IPv4 and IPv6 addressing, with each subnet receiving an IPv6 /64 from the VPC's IPv6 range.
Worker nodes are placed in the private subnets, and the Amazon VPC CNI provides Pod networking and IPv6 address allocation. In IPv6 EKS clusters, the CNI uses IPv6 prefix delegation to allocate Pod addresses efficiently. In IPv6 EKS clusters, the CNI uses IPv6 prefix delegation to allocate Pod addresses efficiently.
The word “private” also has a slightly different meaning in an IPv6 architecture.
An IPv6 address is globally routable by default, but that does not mean the workload accepts unsolicited inbound traffic. The private subnet remains outbound-only because its default IPv6 route points to an egress-only internet gateway rather than directly to an internet gateway.
This gives the architecture the same outbound-only intent that many IPv4 deployments achieve with NAT, but without requiring address translation for IPv6 traffic.
The Egress-Only Gateway
Outbound IPv6 traffic from private subnets flows through an egress-only gateway rather than a standard internet gateway.
The distinction matters: the egress-only internet gateway allows Pods to initiate outbound IPv6 connections, but prevents the internet from initiating new IPv6 connections to those Pods. AWS describes the egress-only gateway as a stateful VPC component specifically designed for outbound IPv6 communication.
The private subnet route table contains a route like:
Destination Target
VPC IPv6 CIDR local
::/0 Egress-Only Internet Gateway
AWS explicitly documents this ::/0 route for sending internet-bound IPv6 traffic from a private subnet through an egress-only internet gateway.
What makes this different from a NAT gateway is what doesn’t happen.
There is no source address translation.
The Pod’s own IPv6 address is preserved as the packet leaves the VPC.
The egress-only gateway provides the directional security — outbound connections are allowed and unsolicited inbound connections are blocked — without changing the source address.
There is no hourly or per-GB processing charge for the egress-only internet gateway itself, although normal AWS data-transfer charges can still apply.
How a Packet Actually Travels: Pod to Internet
When a Pod initiates an outbound IPv6 connection, the traffic is handled by the Pod’s networking stack and the node’s VPC CNI networking, then follows the private subnet’s IPv6 route to the egress-only internet gateway and finally to the internet.
Conceptually, the path looks like this:
┌──────────┐
│ Pod │
│ IPv6 │
└────┬─────┘
│
▼
┌──────────┐
│ Node │
│ VPC CNI │
└────┬─────┘
│
▼
┌──────────────────┐
│ Private Subnet │
│ Route Table │
│ ::/0 → EIGW │
└────┬─────────────┘
│
▼
┌──────────────────┐
│ Egress-Only IGW │
└────┬─────────────┘
│
▼
Internet
What makes this different from IPv4 is what doesn’t happen.
There is no SNAT rule applied to the Pod’s IPv6 address. There is no NAT gateway rewriting the source address into a shared public IPv4 address.
The destination on the internet receives a packet whose source address is the Pod’s own IPv6 address. AWS explicitly documents that the original IPv6 address is preserved when a Pod communicates outside the VPC.
Return traffic for established connections is allowed back through the egress-only gateway. Unsolicited inbound connections — anything the Pod did not initiate — are blocked at the gateway.
This is the important distinction: IPv6 removes address translation from the IPv6 traffic path, while the egress-only gateway still provides an outbound-only connectivity model.
The Bootstrap Dependency Nobody Documents
This is the part that can break silently if you get the order wrong on first deployment.
The dependency chain looks like this:
First, the VPC and subnets need to be configured for IPv6, including IPv6 CIDRs and appropriate routing. Second, the node and VPC CNI need the permissions required to configure IPv6 Pod networking. Third, once the CNI is working, Pods can receive their IPv6 addresses. Fourth, system workloads such as CoreDNS can start normally on top of that networking. Finally, with the networking and system services available, applications can start and discover each other through Kubernetes DNS.
The important dependency is therefore not really “CNI → CoreDNS → DNS” by itself.
AWS requires an IPv6 IAM policy for the VPC CNI, and recommends attaching that policy to a dedicated CNI IAM role.
The chain breaks early if those permissions aren’t ready when the CNI needs them. The CNI can be running, but without the required permissions it cannot complete the EC2 API operations necessary for IPv6 networking.
CoreDNS can then appear to be the problem because system Pods depend on working Pod networking underneath them.
On a first deployment, the required IAM permissions need to be available before the networking add-on can successfully perform the AWS API operations required for Pod networking.
This is primarily a bootstrap ordering concern — once the permissions and networking components are established, subsequent deployments can operate normally.
IPv4 vs IPv6: What Actually Changes
The comparison comes down to one fundamental difference: whether address translation happens in the path or not.
In the NAT model, a Pod with a private IPv4 address sends traffic to a NAT gateway. The gateway rewrites the source address to a shared public IP, forwards the packet, and maintains the state needed to route the return traffic back to the correct connection.
The destination never sees the Pod’s original private address.
Every gigabyte processed by the NAT gateway incurs a data-processing charge, in addition to the gateway’s hourly cost.
The NAT layer also becomes another stateful component in the network path.
And because many Pods can share the same public IPv4 address, the external identity of individual workloads is lost.
In the IPv6-first model, none of that exists for IPv6-to-IPv6 traffic.
The Pod’s address is globally routable.
The egress-only gateway lets traffic pass without rewriting the source address.
The destination sees the real Pod IPv6 address.
There is no NAT gateway processing the IPv6 traffic.
There is no shared IPv4 identity problem.
The security model is also different.
The egress-only gateway blocks unsolicited inbound IPv6 connections, while security groups, network ACLs and Kubernetes network policies determine what traffic is actually allowed.
There is, however, one important exception.
IPv6 Pods still need to communicate with IPv4-only destinations. EKS provides an IPv4 compatibility path for this traffic through the node’s IPv4 networking. This means IPv6-first does not mean that IPv4 connectivity disappears — IPv4 remains available for communication with IPv4-only endpoints. So the accurate statement is not “IPv6 eliminates NAT.”
It is:
IPv6 eliminates NAT from the IPv6-to-IPv6 traffic path.
That distinction matters in real-world Kubernetes environments where not every external service is IPv6-enabled.
Running IPv6-first on a managed Kubernetes platform requires deliberate choices at four layers: the network topology, the cluster’s IP family declaration, the node and CNI permissions, and the add-on configuration.
Each layer has one clear job.
The VPC provides dual-stack connectivity.
The EKS cluster declares IPv6 as its Pod and Service address family.
The Amazon VPC CNI provides IPv6 Pod networking using prefix delegation.
The routing layer sends outbound IPv6 traffic from private subnets through an egress-only internet gateway.
The IAM layer gives the CNI the permissions required to configure Pod networking.
The layers depend on each other in a specific order on first deployment, and then operate independently once the cluster is established.
The result is a cluster where Pods have globally routable IPv6 addresses, IPv6 egress does not require NAT, address translation is removed from the IPv6 traffic path, and Pod identity is preserved all the way to the destination.
The NAT gateway — and everything that comes with it — simply isn’t part of the IPv6 traffic path.
IPv6-first Kubernetes isn’t just about having more addresses.
It’s about replacing address translation with routing.
And once the network no longer needs to hide the identity of the workload, the architecture becomes much easier to reason about.
The biggest advantage of IPv6-first Kubernetes isn’t the size of the address space. It’s that the network can route workloads instead of translating them.
AWS Documentation
메타데이터
- post_id
- b562c54e2f23
- slug
- designing-an-ipv6-first-kubernetes-cluster-b562c54e2f23
- url
- https://medium.com/@soumitramanavi.24/designing-an-ipv6-first-kubernetes-cluster-b562c54e2f23
- canonical_url
- https://medium.com/@soumitramanavi.24/designing-an-ipv6-first-kubernetes-cluster-b562c54e2f23
- author_url
- https://medium.com/@soumitramanavi.24
- status
- ok
- fetched_at
- 2026-09-04 12:38:21