On AWS, when you create a NLB, you have the possibility to specify the instance ID instead of the instance IP address. This causes the NLB to preserve the client IP.
However, if I configure the NLB to target instances in a private subnet where the route table includes a default route to a NAT gateway, how can the response be routed back via the NLB interface and not the NAT gateway?
Consider the following:
- A VPC with a CIDR block of 10.0.0.0/16;
- A public subnet with a CIDR block of 10.0.3.0/24;
- A private subnet with a CIDR block of 10.0.6.0/24.
The public subnet has a default route to the internet gateway and the private subnet has a default route to the NAT gateway. The NAT gateway has an interface with private IP 10.0.3.12 and the NLB has an interface with private IP 10.0.3.18.
An EC2 instance with IP 10.0.6.4 is deployed in the private subnet and is part of the NLB target group. The instance has a default route to the VPC router at 10.0.6.1 inside the OS routing table.
Let's say that a packet with client IP 22.128.22.136 is forwarded to the EC2 instance, how the EC2 instance will manage to send the packet back to 10.0.3.18 and not to the NAT gateway. The private subnet routing table has a default route to 10.0.3.12.
I presume that AWS immediately "injects" a route to the NLB for any client IP when a packet arrives on the NLB interface. I would like to know more about the internals.
With tcpdump
on the EC2 instance, I can see the client IP being preserved:
$ sudo tcpdump -n -i eth0 host 22.128.22.136 port 80