Enabling IPv6

Glossary

  • CAPA - Cluster API Provider AWS
  • NLB - Network Load Balancer
  • CCM - Cloud Controller Manager
  • Dualstack - In this document, dualstack (IPv4 + IPv6) refers to network infrastructure (VPC, subnets, and load balancers) that supports both IPv4 and IPv6 address families. This is distinct from Kubernetes dualstack, where pods and services are assigned addresses from both IP families.

Overview

CAPA enables you to create IPv6 only and dualstack (IPv4 + IPv6) Kubernetes clusters on Amazon Web Services (AWS) on a dualstack network infrastructure.

Important: CAPA does not support in-place migration on self-managed and managed clusters from IPv4 to dualstack or IPv6. You must create a new cluster.

Prerequisites

The instance types for control plane and worker machines must support IPv6. To see a list of instance types that support IPv6 in your region, run the following command:

aws ec2 describe-instance-types \
  --region <region> \
  --filters "Name=network-info.ipv6-supported,Values=true" \
  --query 'InstanceTypes[].InstanceType'

If you want to check whether a specific instance type supports IPv6, run the following command (output true):

aws ec2 describe-instance-types \
  --region <region> \
  --instance-types <instance-type> \
  --query 'InstanceTypes[0].NetworkInfo.Ipv6Supported'

If you are launching machines in IPv6-only subnets, the instance type must be Nitro-based. To check whether the instance type is Nitro-based, run the following command (output "nitro"):

aws ec2 describe-instance-types \
  --region <region> \
  --instance-types <instance-type> \
  --query 'InstanceTypes[0].Hypervisor'

Enabling IPv6 capabilities

To instruct CAPA to configure IPv6 capabilities for the cluster’s network infrastructure, you must explicitly define spec.network.vpc.ipv6 in either AWSCluster or AWSManagedControlPlane. See IPv6 CIDR Allocations for different IPv6 CIDR configuration options.

spec:
  network:
    vpc:
      ipv6: {}

Note: CAPA, by default, will provision a dualstack network infrastructure (i.e. dualstack VPC and subnets). However, your Kubernetes cluster can be configured as either Kubernetes IPv6-only or dualstack depending on your pod/service CIDR configuration.

Supported Network Configurations

CAPA supports various network configuration combinations for creating clusters with different IPv4/IPv6 requirements. The following table shows all possible combinations of subnet and load balancer configurations (assuming internet-facing load balancer):

Public SubnetPrivate SubnetLoad Balancer IP TypeTarget Group IP TypeStatusNotes
IPv4IPv4ipv4ipv4✅ SupportedTraditional IPv4 cluster
dualstackdualstackdualstackipv6✅ SupportedDualstack LB with IPv6 as primary
dualstackdualstackdualstackipv4✅ SupportedDualstack LB with IPv4 as primary
dualstackdualstackipv4ipv4✅ SupportedIPv4-only LB on dualstack infrastructure
dualstackIPv4dualstackipv4✅ SupportedDualstack LB with IPv4-only control plane
dualstackIPv6-onlydualstackipv6✅ SupportedDualstack LB with IPv6-only control plane
dualstackIPv4dualstackipv6❌ InvalidCannot use IPv6 targets when control plane has no IPv6 addresses
IPv6-only***❌ InvalidLoad Balancers cannot use IPv6-only subnets
**ipv6*❌ Invalidipv6 is not a valid load balancer IP type

When Kubernetes pods have only IPv6 addresses and need to communicate with IPv4-only internet services, NAT64/DNS64 must be enabled for the subnets where nodes reside. CAPA automatically enables NAT64/DNS64 for IPv6-only subnets that it creates (see Mixing subnets of different IP families on how to tell CAPA to create IPv6-only subnets). For pre-existing subnets, you must enable NAT64/DNS64 manually.

IPv6 CIDR Allocations

CAPA supports various methods to allocate an IPv6 CIDR to the cluster VPC.

AWS-assigned IPv6 VPC CIDR

To request AWS to automatically assign an IPv6 CIDR from an AWS defined address pool, use the following setting:

spec:
  network:
    vpc:
      ipv6: {}

By default, Amazon provides one fixed size (/56) IPv6 CIDR block to a VPC.

Bring-your-own IPv6 VPC CIDR (EC2)

If you own an IPv6 address space, you can import it into AWS EC2 IPv6 address pool (See guide). After importing it, you can assign /56 ranges from the space to individual VPCs in the same account.

To define your own IPv6 address pool and CIDR set the following values:

spec:
  network:
    vpc:
      ipv6:
        poolId: pool-id
        cidrBlock: "2009:1234:ff00::/56"

Bring-your-own IPv6 VPC CIDR via VPC Address Manager (VPC IPAM)

If you want to allocate an IPv6 CIDR to the VPC from an existing VPC IPAM pool, define the pool ID and a prefix length as follows:

spec:
  network:
    vpc:
      ipv6:
        ipamPool:
          id: ipam-pool-id
          netmaskLength: 56

By default, if you omit netmaskLength, CAPA will set it to the default 56.

Bring-your-own IPv6 VPC

If you have an existing dualstack VPC that you would like to use, you must explicitly provide the IPv6 CIDR block and egress-only internet gateway ID specs:

spec:
  network:
    vpc:
      id: vpc-1234567890abcdefg
      cidrBlock: 10.0.0.0/16
      ipv6:
        cidrBlock: "2001:1234:ff00::/56"
        egressOnlyInternetGatewayId: eigw-1234567890abcdefg

This has to be done to explicitly express the user intention to use the IPv6 capabilities of the VPC.

Creating IPv6 EKS-managed Clusters

An example configuration for deploying an IPv6 EKS cluster can be found here: IPv6 EKS cluster template.

Notes: All addons must be enabled. A working IPv6 cluster configuration defines spec.network.vpc.ipv6 and all addons as follows:

kind: AWSManagedControlPlane
apiVersion: controlplane.cluster.x-k8s.io/v1beta1
metadata:
  name: "${CLUSTER_NAME}-control-plane"
spec:
  network:
    vpc:
      ipv6: {}
  region: "${AWS_REGION}"
  sshKeyName: "${AWS_SSH_KEY_NAME}"
  version: "${KUBERNETES_VERSION}"
  addons:
    - name: "vpc-cni"
      version: "v1.11.0-eksbuild.1"  # Note: Check for latest compatible version
      # this is important, otherwise environment property update will not work
      conflictResolution: "overwrite"
    - name: "coredns"
      version: "v1.8.7-eksbuild.1"  # Note: Check for latest compatible version
    - name: "kube-proxy"
      version: "v1.22.6-eksbuild.1"  # Note: Check for latest compatible version

Creating IPv6 Self-managed Clusters

An example configuration for deploying an IPv6 self-managed cluster can be found here: IPv6 cluster template.

When creating a self-managed cluster, you can define the IPv6 Pod and Service CIDR. For example, you can define ULA IPv6 range fd01::/48 for pod networking and fd02::/112 for service networking.

apiVersion: cluster.x-k8s.io/v1beta1
kind: Cluster
metadata:
  name: "${CLUSTER_NAME}"
spec:
  clusterNetwork:
    pods:
      cidrBlocks:
      - fd01::/48
    services:
      cidrBlocks:
      - fd02::/112

Creating Dualstack Self-managed Clusters

An example configuration for deploying a dualstack self-managed cluster can be found here:

When creating a self-managed cluster, you can define both IPv4 and IPv6 Pod and Service CIDRs. The first entry defines the primary IP family. For example, the below configuration sets up a dualstack IPv6 primary cluster:

apiVersion: cluster.x-k8s.io/v1beta1
kind: Cluster
metadata:
  name: "${CLUSTER_NAME}"
spec:
  clusterNetwork:
    pods:
      cidrBlocks:
      - fd01::/48
      - 192.168.0.0/16
    services:
      cidrBlocks:
      - fd02::/112
      - 172.30.0.0/16

Cloud Controller Manager (CCM) Node IP Configurations

You need to provide cloud-config to the CCM via a ConfigMap to set the NodeIPFamilies to include IPv6. This instructs the CCM to consider IPv6 in the machine network interface, if any. If not configured, the CCM will only consider the node’s IPv4 address. This causes nodes to have only IPv4 and new pods with hostNetwork: true will only pick up the node’s IPv4 address.

For example, provide the following ConfigMap to cloud-controller-manager-addon:

apiVersion: v1
kind: ConfigMap
metadata:
  name: cloud-config
  namespace: kube-system
data:
  cloud-config.conf: |
    [Global]
    NodeIPFamilies=ipv6
    NodeIPFamilies=ipv4

And then provide the cloud-config.conf to the CCM DaemonSet as follows:

spec:
  containers:
  - name: aws-cloud-controller-manager
    image: registry.k8s.io/provider-aws/cloud-controller-manager:v1.28.3
    args:
      - --v=2
      - --cloud-provider=aws
      - --use-service-account-credentials=true
      - --configure-cloud-routes=false
      - --cloud-config=/etc/kubernetes/cloud-config.conf # Define cloud-config file path
    volumeMounts:
    - name: cloud-config
      mountPath: /etc/kubernetes/cloud-config.conf
      subPath: cloud-config.conf
  hostNetwork: true
  volumes:
  - name: cloud-config
    configMap:
      name: cloud-config

Cloud Controller Manager Load Balancer Limitations

CNI IPv6 Support for Self-managed Clusters

By default, no CNI plugin is installed when provisioning a self-managed cluster. You need to install your own CNI solution that supports IPv6, for example, Calico with VXLAN. You can find the guides to enable IPv6 and VXLAN support for Calico on their official documentation.

Important notes for Calico with IPv6:

  • Calico supports IPv6 with VXLAN encapsulation only (IP-in-IP is not supported for IPv6)
  • VXLAN for IPv6 requires kernel version ≥ 4.19.1 (or Red Hat kernel ≥ 4.18.0)
  • If you are using Calico as the CNI provider, ensure the CNI ingress rule allows VXLAN for cross-subnet communications. You can set the rule in the AWSCluster resource, for example:
spec:
  network:
    cni:
      cniIngressRules:
      # If using Calico as CNI provider, this rule is required.
      # Note: Calico currently supports IPv6 with VXLAN.
      - description: "VXLAN (calico)"
        protocol: udp
        fromPort: 4789
        toPort: 4789

Mixing subnets of different IP families

CAPA allows you to define the AZs the subnets should be created in, the number of subnets per AZ and whether a subnet is IPv4, dualstack, or IPv6-only. For example:

spec:
  network:
    subnets:
      # This creates a dualstack public subnet in us-east-1a
      # Both cidrBlock + isIpv6==true
    - cidrBlock: 10.0.0.0/20
      isIpv6: true
      isPublic: true
      availabilityZone: us-east-1a
      id: ${CLUSTER_NAME}-subnet-public-us-east-1a
    # This creates a dualstack public subnet in us-east-1b
    # Both cidrBlock + isIpv6==true
    - cidrBlock: 10.0.16.0/20
      isIpv6: true
      isPublic: true
      availabilityZone: us-east-1b
      id: ${CLUSTER_NAME}-subnet-public-us-east-1b
    # This creates an IPv4 private subnet in us-east-1a
    # Only cidrBlock defined + isIpv6==false (default)
    - cidrBlock: 10.0.128.0/20
      isPublic: false
      availabilityZone: us-east-1a
      id: ${CLUSTER_NAME}-subnet-private-us-east-1a
    # This creates an IPv6-only private subnet in us-east-1a
    # cidrBlock is undefined + isIpv6==true
    - isPublic: false
      isIpv6: true
      availabilityZone: us-east-1a
      id: ${CLUSTER_NAME}-subnet-private-1-us-east-1a
    # This creates an IPv4 private subnet in us-east-1b
    # Only cidrBlock defined + isIpv6==false (default)
    - cidrBlock: 10.0.144.0/20
      isPublic: false
      availabilityZone: us-east-1b
      id: ${CLUSTER_NAME}-subnet-private-us-east-1b
    # This creates an IPv6-only private subnet in us-east-1b
    # cidrBlock is undefined + isIpv6==true
    - isPublic: false
      isIpv6: true
      availabilityZone: us-east-1b
      id: ${CLUSTER_NAME}-subnet-private-1-us-east-1b
    vpc:
      cidrBlock: 10.0.0.0/16
      # The VPC IPv6 CIDR will be allocated by AWS.
      ipv6: {}
  region: us-east-1

A subnet IP specification is defined as follows (applied to CAPA-managed VPC only):

Subnet TypeisIpv6cidrBlockipv6CidrBlockNotes
IPv4-onlyfalse or omittedRequiredN/ATraditional IPv4 subnet
DualstacktrueRequiredOptionalAuto-assigned from VPC CIDR if omitted
IPv6-onlytrueOmitted/emptyOptionalAuto-assigned from VPC CIDR if omitted

IPv6 support for Local and Wavelength zones

According to the AWS docs, the state of IPv6 support is as follows:

  • ❌ No IPv6 support for Wavelength zones. See reference.
  • ⚠️ Limited support for Local zones, which requires a dedicated IPv6 CIDR for local zone network border group. See reference.

Thus, CAPA currently does not support creating IPv6-enabled subnets in Local and Wavelength zones.

However, if you have an existing VPC with IPv6-only or dualstack subnets in Local zones, you can define them in the cluster spec.

spec:
  network:
    subnets:
    - id: "cluster-subnet-private-us-east-1a"
    - id: "cluster-subnet-public-us-east-1a"
    - id: "cluster-subnet-private-us-east-1b"
    - id: "cluster-subnet-public-us-east-1b"
    - id: "cluster-subnet-private-us-east-1-nyc-1a"
    - id: "cluster-subnet-public-us-east-1-nyc-1a"
    - id: "cluster-subnet-private-us-east-1-wl1-was-wlz-1"
    - id: "cluster-subnet-public-us-east-1-wl1-was-wlz-1"
    vpc:
      id: vpc-1234567890abcdefg
      cidrBlock: 10.0.0.0/16
      ipv6:
        cidrBlock: "2001:1234:ff00::/56"
        egressOnlyInternetGatewayId: eigw-1234567890abcdefg