Testing IPv6 connectivity on AWS

Do you need to verify that a particular service handles IPv6 traffic, yet your ISP doesn’t provide you an IPv6 address? This guide will help you work around this by setting up an IPv6-only EC2 and connecting it to the service in question.

As a rough overview, you’ll need at least these pieces:

  • dual-stack VPC
  • dual-stack ALB
  • A(AAA) record to the ALB
  • IPv6-only subnet
  • IPv6-only EC2

We’ll highlight the needed modifications for each, using Terraform. There’re more pieces needed, but the unlisted ones aren’t directly related to IPv6.

Dual-stack VPC

We start with an already existing VPC. The following configurations have to be added to the VPC module:

enable_ipv6 = true
assign_ipv6_address_on_creation
private_subnet_assign_ipv6_address_on_creation
public_subnet_ipv6_prefixes
private_subnet_ipv6_prefixes
database_subnet_ipv6_prefixes

enable_ipv6 lets Amazon provide you an IPv6 CIDR block, in which case you cannot set on its prefix length nor IP range. (You may alternatively bring your own IP.)

IPv6-only subnet

The subnet’s definition is straightforward:

resource "aws_subnet" "this" {
  vpc_id                                         = var.vpc_id
  ipv6_cidr_block                                = var.cidr
  ipv6_native                                    = true
  assign_ipv6_address_on_creation                = true
  enable_resource_name_dns_aaaa_record_on_launch = true
}

Here’s how you might set the above vars. (We’re using Terragrunt, thence the dependency keyword.)

locals {
  # Fixed when using AWS-provided IPv6 CIDR block.
  cidr_prefix_length_vpc    = 56  cidr_prefix_length_subnet = 64  count_existing_subnets    = 8}
vpc_id = dependency.vpc.outputs.id
cidr   = cidrsubnet(
  dependency.vpc.outputs.ipv6_cidr,
  local.cidr_prefix_length_subnet - local.cidr_prefix_length_vpc,
  local.count_existing_subnets + 1)

Two things to note about the highlighted lines, in order:

  1. The CIDR prefix lengths are fixed: at 56 for VPCs and at 64 for subnets. Hence the VPC’s CIDR prefix is extended by 64 - 56 bits above.
  2. The VPC already had 8 existing subnets and we add the IPv6-only subnet as the 9th one; thus the 9 on the 2nd highlighted line above.

(Note: outside of this hypothetical scenario, this particular IPv6 subnet would be provisioned from the same configuration as the rest. That is, there wouldn’t be a + 1 subnet added in such an ad hoc manner.)

ALB

ip_address_type = "dualstack"

Related to ALB, note that, as of now, its Target Group must be of target_type = "ip".

IPv6 target groups only support IP type targets.

A(AAA) record

The AAAA record is required for our IPv6 testing, while the A record is a nice to have, as it’ll make a potential Route53 healthcheck pass. If using Route53, it’s best to use an ‘alias’ extension, letting the AAAA record resolve via ALB’s DNS.

EC2

Only changes to the "aws_instance" resource are

  • the addition of ipv6_address_count, set to a non-zero value, and
  • disablement of associate_public_ip_address which presumes an IPv4 address. Then, as long as you pick a relatively recent ami, you should be all set.

In one the dual-stack subnets you’ll also need an EC2 with both IPv4 and IPv6 connectivity.

Conclusion

Finally, to actually test the above setup, you’d SSH into a dual-stack EC2 and from there on SSH further into the IPv6-only EC2. From there you’d then, finally, be able test the IPv6 connectivity of your service in question.

Note that you could also merely add an IPv6 interface directly to the service’s EC2 and obviate the need of setting up the LB. But since many services find themselves behind an LB, I found it fitting to include ALB setup as well. Especially since its target-groups currently have an IPv6-related limitation.

We haven’t laid out all the steps in detail, though the above are the important bits needed to test IPv6 in AWS. Reach out if you aren’t able to fill in the missing gaps and I’ll expand on the unclear parts.