NAT or gaining internet access in private networks

In this article we will build a VPC focusing on having Internet access inside a private network while keeping it isolated from the outside world.

NAT, or a Network Address Translation, is an important component of many VPCs, most often used for gaining internet access within a private network. Less often NAT Gateways can be used to connect to other VPCs or even networks outside the cloud all-together. In AWS these are called private NAT Gateways.

It translates one set of IP Addresses into another set in order to preserve the limited amount of available IPv4 Addresses. There’s only about 4.2 billion which is very little considering the amount of devices, that is also why we’re in transition to the IPv6 internet.

NATs are also used in routers which have a public IP in order to connect to the internet. Routers assign private IP to all connected devices and then translate them into public when necessary and vice versa. This helps us a lot because private IP addresses are not connected to the internet so there can be an infinite amount of the same IP Addresses within different private networks all over the world.

Before going about creating the VPC, it is good to know what we’re trying to build. In order to visualize it, I have created a diagram showing network components and how NAT fits in with them. For the purposes of this article I am going to assume basic level knowledge about vpc and networking .

nat gateway workflow diagram

For simplicity’s sake, I used a single Availability Zone for the diagram, with a single public and private subnet. Public subnet has a route to the Internet Gateway, whereas the private subnet routes to the NAT Instance within the public subnet. This acts as a proxy and directs traffic from the private subnet to the Internet Gateway.

One thing worth noting is how NAT changes the private IP of the EC2 sending the request to its own Elastic IP. Thanks to this no one knows that it is not the NAT instance making the request but in fact an EC2 from a different network.

Create VPC with CDK

In order to easily create and destroy the private network, I have used the aws cdk. In case you’re not familiar with it, there’s a quick setup guide here . You can use the IaC from github .

There are two requirements for this to work:

  1. Generate an access key that should be used for accessing EC2 instances. If you name the key exanubes you won’t have to make any changes to the codebase.
  2. Create an IAM role for Cloudformation. You can give it admin access to make it easier. Cloudformation needs permissions to create the underlying resources, it will only assume that role this one time. If you name it exanubes-cloudformation-access you won’t have to make any changes, otherwise you’ll have to change the npm scripts.

After all that is done, synthesize the code with npx cdk synth. This will generate the cloudformation template, in cdk.out directory, that can be deployed with npm run cdk:deploy. You can also manually upload it via the AWS Console or CLI. Should you do it manually, you won’t need the IAM Role for Cloudformation.

SSH into EC2

Now that infrastructure has been created, we need to do two things. Log into the EC2 inside the public subnet as that’s our jumping off point into the private instance. In order to be able to do that though we need to take the access key with us into the public instance so we can use it again.

scp -i exanubes.pem exanubes.pem ec2-user@EC2-PUBLIC-IP:exanubes.pem

This command will use the exanubes.pem to log into the ec2-user@EC2-PUBLIC-IP machine then take the exanubes.pem file and save it under the same name on that machine.

Now we can just log into the public EC2

ssh -i exanubes.pem ec2-user@EC2-PUBLIC-IP`

and then to the instance inside the private subnet

ssh -i exanubes.pem ec2-user@EC2-PRIVATE-IP

then check to see if the internet connection is working

> ping exanubes.com
PING exanubes.com ( 56(84) bytes of data.
64 bytes from ec2-3-67-153-12.eu-central-1.compute.amazonaws.com ( icmp_seq=1 ttl=62 time=1.36 ms
64 bytes from ec2-3-67-153-12.eu-central-1.compute.amazonaws.com ( icmp_seq=2 ttl=62 time=1.02 ms
64 bytes from ec2-3-67-153-12.eu-central-1.compute.amazonaws.com ( icmp_seq=3 ttl=62 time=1.01 ms
--- exanubes.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms

by pinging https://exanubes.com and receiving packets with a drop rate of 0%, which is good news.

Remove NAT Gateway

To remove the NAT Gateway we can either change the SubnetType from private to isolated and redeploy the stack or simply log into the console and delete the NAT Gateways. Either way, now redoing the same steps we can see that the public instance can still ping the website and receive packets

> ping exanubes.com
PING exanubes.com ( 56(84) bytes of data.
64 bytes from ec2-3-64-200-242.eu-central-1.compute.amazonaws.com ( icmp_seq=1 ttl=63 time=0.825 ms
64 bytes from ec2-3-64-200-242.eu-central-1.compute.amazonaws.com ( icmp_seq=2 ttl=63 time=0.820 ms
64 bytes from ec2-3-64-200-242.eu-central-1.compute.amazonaws.com ( icmp_seq=3 ttl=63 time=0.797 ms
--- exanubes.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms

whereas the private instance cannot because it does not have a way of sending requests outside the VPC.

> ping exanubes.com
PING exanubes.com ( 56(84) bytes of data.
--- exanubes.com ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 3053ms

Last but not least, let’s run npm run cdk:destroy to tear down the infrastructure.


To sum up, we have covered that NAT is being widely used in routers and its main purpose is simply translating private IP to public and public into private. This practice facilitates the continuous use of IPv4. Without it, we would simply run out of IP addresses which would mean devices wouldn’t be able to connect to the Internet. In a VPC, we use it to translate the private IP of an EC2 instance to the Elastic IP of the NAT Gateway to give it access to the Internet. This is a one way connection which has to be established from within the VPC. Outside resources cannot send anything themselves unless they’re asked for it e.g, installing and updating packages. The wide usage of NAT will not be necessary once we finish the move to the IPv6 internet as it has 340 undecillion addresses (340 with 36 zeroes).