Signs of Triviality

Creating AWS IPv4/IPv6 Dual Stack EC2 Instances

May 19th, 2020

AWS EC2 is a
wonderful tool for teaching
System Administration: you can quickly and easily
spin up instances running different operating systems
in different regions across the globe and play around
with them in a matter of minutes. Unfortunately, by
default, all of them come up as IPv4 only.

When it comes to IPv6 support, AWS has been
surprisingly slow in its adoption. EC2 only gained
support for IPv6 in
2017 (!), and Elastic IPs are stillIPv4
only. Even basic dualstack support for
EC2 instances requires the creation of a VPC and a number
of configuration steps that are not trivial for
novice users to implement.

If you've had your AWS account for long enough
(i.e., you're on "EC2-Classic"),
you don't even have a default VPC and thus can't
enable IPv6 on that. For that reason, I've been
going back to using an
IPv6 tunnelbroker to enable IPv6 on my default EC2
instances when I wanted to create a dualstack
environment.[1]

Anyway, since I'll forget how to do this or where
to find the right commands, here are my notes on
creating a dualstack VPC in the hopes that somebody
else may find them useful. At the bottom, you'll also
find a single script to run all commands in one go:

After creation of the VPC, select it and 'Enable
DNS hostnames' and 'Enable DNS resolution'. (Note:
DNS hostnames are only added with IPv4 addresses. As
of May 2020, Amazon says:
We do not support IPv6 DNS hostnames for your
instance.)

Via the command-line, we'll use JSON output as the
default (output = json in
~/.aws/config) and then utilize the versatile
jq(1)
command. To create the VPC, you'd
then run:

Hosts on our VPC want to talk to the internet, so
let's create an internet gateway. To create a new
Internet Gateway using the UI, go to
'Services'->'Network & Content Delivery' ->
'VPC' -> 'Internet Gateways'. Select 'Create
Internet Gateway'. For consistency, let's name it
"dualstack" as well.

The Route Table needs to be associated with the
subnet you created above. In the UI, select the newly
created Route Table, then select 'Actions' -> 'Edit
Subnet Associations', select your "dualstack" subnet
and save.

A Route Table is all nice and well, but it's not
very useful without any routes. Let's add some!

In the UI, select the route table you just created,
then select 'Actions'->'Edit routes', then 'Add route'
and enter "0.0.0.0/0" and select the Internet Gateway
you created above as the target. Then repeat the same
for IPv6 by using "::/0" as the destination with the
same Internet Gateway.

We need to create a new security group for our EC2
instances. Since security groups are stateful, we
don't need to create rules for established TCP
connections as you would have to for network ACLs and
can only worry about which ports we want to allow
traffic into.

In this example, since we are looking to
demonstrate what a full dualstack host looks like on
the internet, we want to allow any and
all traffic. For your purposes, you may wish to
restrict the traffic you allow to come in, but you'll
have to remember to add rules for both IPv4 and
IPv6!

So far, so good. But this is still a pain, because
while with the (IPv4-only) defaults, you can trivially
launch an instance in any region so long as you know
the AMI ID, but if you want to launch a dualstack
instance in a given region, you do of course have to
repeat the above setup for that region, and then
specify the correct subnet and security group
again.

For example, suppose your default region is
us-east-1, but you wish to launch an instance
in sa-east-1, you'd first have to run through
all the steps above to create the "dualstack" VPC in
that region. Fortunately, this is a one-time
thing.

But we're lazy, so let's create a simple script so we
can easily run this for any region we wish to
support:

Now the next annoying thing is that you now have
different subnet- and security-group IDs in each
region, so if you want to spin up a dualstack
instance, you need to remember which subnet goes with
which region. What a pain. Good thing we labeled our
resources consistently, so that we can now on-demand
search for "dualstack" subnets or security groups and
create a shell function to grab the right id from that
label. For example: