8

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.

user35042
  • 2,601
  • 10
  • 32
  • 57

1 Answers1

7

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.

Michael - sqlbot
  • 21,988
  • 1
  • 57
  • 81
  • can you please elaborate on the inbound connection prevented due to asymmetric return route? I've got the setup working with a route table that includes all the ip addresses that need to give inbound connections, but I don't understand why this is necessary. – JDiMatteo Mar 01 '18 at 04:02
  • @JDiMatteo it's necessary because the NAT Gateway is not designed to be created on any subnet for which it provides NAT services. The instances reach external resources via their subnet's route table (points to NAT-GW for instances without public IP, points to IGW for instances with public IP) and the NAT-GW reaches the Internet via its subnet route table (points to IGW). – Michael - sqlbot Mar 01 '18 at 09:00
  • If an instance is using its own public IP, it must route responses out via the IGW because that's where the inbound traffic is coming from, and it can't try to leave via NAT-GW because the peer on the outside would see the reply coming from the wrong source IP if the traffic got translated. Are you saying my advice that it won't work bidirectionally isn't correct? – Michael - sqlbot Mar 01 '18 at 09:01
  • Michael, your advice is correct as far as I know. I wanted to use a NAT for most internet communication to allow IP whitelisting, but still connect to the public IPs (without using a bastion), so I setup 2 routing tables: one for the nat, and a second for the ec2 instances with public ip addresses. I setup the routes so that only a few IP addresses (e.g. my office) route without the NAT so I can still connect without a bastion (but 0.0.0.0/0 uses the NAT on this routing table). – JDiMatteo Mar 08 '18 at 01:49