Understanding the distinction between “private” and “public” subnets in Amazon VPC requires an understanding of how IP routing and network address translation (NAT) works in general, and how they are specifically implemented in VPC.
The core differentiation between a public and private subnet in VPC is defined by what that subnet’s default route is, in the VPC routing tables..
This configuration, dictates the validity of using, or not using, public IP addresses on instances on that particular subnet.
Each subnet has exactly one default route, which can be only one of two things:
- The VPC’s “Internet Gateway” object, in the case of a “public” subnet
- An EC2 instance, performing the “NAT instance” role, in the case of a “private” subnet.
The Internet Gateway does not do any network address translation, so an instance without a public IP address cannot connect outwards to the Internet (to do things like downloading software updates, or accessing other AWS resources like S3 and SQS ) if the default route on its VPC subnet is the Internet Gateway object. So, if you are an instance on a “public” subnet, then you need a public IP address in order to do a significant number of things that servers commonly need to do.
For instances with only a private IP address, there’s an alternate way of outbound access to the Internet. This is where Network Address Translation and a NAT instance come in.
The machines on a private subnet can access the Internet because the default route on a private subnet is not the VPC “Internet Gateway” object — it is an EC2 instance configured as a NAT instance.
A NAT instance is an instance on a public subnet with a public IP, and specific configuration. There are AMIs that are pre-built to do this, or you can build your own.
When the private-addressed machine sends traffic outwards, the traffic is sent by VPC to the NAT instance, which replaces the source IP address on the packet (the private machine’s private IP address) with its own public IP address, sends the traffic out to the Internet, accepts the response packets, and forwards them back to the private address of the originating machine. (It may also rewrite the source port, and it remembers the mappings so it knows which internal machine should receive the response packets). A NAT instance does not allow any “unexpected” inbound traffic to reach the private instances, unless it’s been specifically configured to do so.
Thus, when accessing external Internet resource from a private subnet, the traffic passes the NAT instance, and appears to the destination to have originated from the public IP address of the NAT instance… so the response traffic comes back to the NAT instance.
Unlike conventional IP routing, where your default gateway is on your same subnet, the way it works in VPC is different: the NAT instance for any given private subnet is always on a different subnet, and that other subnet is always a public subnet, because the NAT instance needs to have a public external IP, and its default gateway has to be the VPC “Internet Gateway” object.
You cannot deploy an instance with a public IP on a private subnet. It doesn’t work, because the default route on a private subnet is (by definition) a NAT instance (which performs NAT on the traffic), and not the Internet Gateway object (which doesn’t). Inbound traffic from the Internet would hit the public IP of the instance, but the replies would try to route outward through the NAT instance, which would either drop the traffic (since it would be composed of replies to connections it’s not aware of, so they’d be deemed invalid) or would rewrite the reply traffic to use its own public IP address, which wouldn’t work since the external origin would not accept replies that came from an IP address other than the one they were trying to initiate communications with.
In essence, the “private” and “public” designations are not really about accessibility or inaccessibility from the Internet. They are about the kinds of addresses that will be assigned to the instances on that subnet, which is relevant because of the need to translate( or avoid translating) those IP addresses for Internet interactions.
Since VPC has implicit routes from all VPC subnets to all other VPC subnets, the default route does not play a role in internal VPC traffic. Instances with private IP addresses will connect to other private IP addresses in the VPC “from” their private IP address, not “from” their public IP address (if they have one)… as long as the destination address is another private address within the VPC.
If your instances with private IP addresses never, under any circumstances, need to originate outbound Internet traffic, then they technically could be deployed on a “public” subnet and would still be inaccessible from the Internet… but under such a configuration, it is impossible for them to originate outbound traffic towards the Internet, which includes connections with other AWS infrastructure services, again, like S3 or SQS.