AWS VPC routing table with both Internet Gateway and NAT Gateway
I have a single VPC in Amazon Web Services with the subnet 172.31.0.0/16. I have created an EC2 instance in this subnet and given it a public Elastic IP. There is an Internet Gateway on this VPC. So, my route table looks like this:
172.31.0.0/16 local
0.0.0.0/0 igw-b4ac67d0
In order to get around some IP access issues on an external service I do not control, I added a NAT gateway to this VPC so that all traffic to the single external address A.B.C.D would route through the NAT gateway. That is, I want the route table to look like this:
# GOAL
172.31.0.0/16 local
A.B.C.D/32 nat-451b3be9
0.0.0.0/0 igw-b4ac67d0
However, try as I might, the AWS interface switches the order when I click "SAVE" so that I always end up with
# What AWS gives me
172.31.0.0/16 local
0.0.0.0/0 igw-b4ac67d0
A.B.C.D/32 nat-451b3be9
This route table seems silly: the NAT gateway would never get used and my traffic to A.B.C.D
still appears to be coming from the EC2 instance's Elastic IP.
How do I get the route table GOAL?
Note: The external service will allow me to add a single IP address that it will allow access. If I only had a single EC2 instance, I could simply give them the EC2 instance's Elastic IP address. But, I want to add several more EC2 instances set up the same way. Hence, the NAT gateway. Also, I cannot simply dispense with the Internet Gateway and use only the NAT gateway as I need services on the EC2 instance to be accessible by the outside world.
Solution 1:
This route table seems silly
Yes, in your interpretation of it... but your interpretation isn't correct. The route table entries in VPC do not actually have an order.
The most specific route is always selected.
Each route in a table specifies a destination CIDR and a target (for example, traffic destined for the external corporate network 172.16.0.0/12 is targeted for the virtual private gateway). We use the most specific route that matches the traffic to determine how to route the traffic.
http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_Route_Tables.html
However, your configuration still doesn't work if the NAT Gateway is actually located on a subnet that uses this route table. The NAT Gateway must be on a subnet whose route table doesn't have any routes pointing back to the NAT Gateway -- otherwise, that's a routing loop. Towards the Internet, the NAT Gateway uses the VPC route table of the subnet to which it is actually attached in order to access the Internet Gateway... so it has to be on a different subnet from the one with the instances that are going to use it, because this /32
route can't be placed where it will impact the outbound traffic from the NAT Gateway.
This is counterintuitive to people who don't realize that the VPC network is not a conventional Ethernet network with routers. The entire network is software-defined, not physical, so there is no performance penalty when traffic crosses subnet boudaries within an availability zone, such as is the case with an EC2 instance on one subnet using a NAT Gateway (or NAT Instance) on a different subnet, or an Elastic Load Balancer on one subnet connecting to an EC2 instance on a different subnet. Indeed, traffic crossing from one subnet to another in these cases is the standard configuration, placing NAT Gateways and ELBs on public subnets (default route is IGW) and EC2 instances on private ones (default route is NAT device).
Note further that the configuration you're attempting will allow outbound, but never permit inbound connections (initiated from outside) from the A.B.C.D
address to anything on this subnet, because the return route is asymmetric through the NAT gateway.