In most cases, your VPC needs to have a connection with the public internet. In this case, you need to create an Internet Gateway (IGW) to attach to your VPC.
In the following example, an IGW is created and attached to vpc-0ca37d4650963adbb:
//create IGW, it returns IGW id as igw-01769bff334dcc035
$ aws ec2 create-internet-gateway
{
"InternetGateway": {
"Attachments": [],
"InternetGatewayId": "igw-01769bff334dcc035",
"Tags": []
}
}
//attach igw-01769bff334dcc035 to vpc-0ca37d4650963adbb
$ aws ec2 attach-internet-gateway --vpc-id vpc-0ca37d4650963adbb --internet-gateway-id igw-01769bff334dcc035
Once the IGW is attached, set a routing table (default gateway) for a subnet that points to the IGW. If a default gateway points to an IGW, this subnet is able to have a public IP address and access from/to the internet. Therefore, if the default gateway doesn't point to IGW, it's determined as a private subnet, which means no public access.
In the following example, a routing table is created that points to IGW and is set to the public subnet:
//create route table within vpc-0ca37d4650963adbb
//it returns route table id as rtb-0f45fc46edec61d8f
$ aws ec2 create-route-table --vpc-id vpc-0ca37d4650963adbb
{
"RouteTable": {
"Associations": [],
"PropagatingVgws": [],
"RouteTableId": "rtb-0f45fc46edec61d8f",
...
//then set default route (0.0.0.0/0) as igw-01769bff334dcc035
$ aws ec2 create-route --route-table-id rtb-0f45fc46edec61d8f --gateway-id igw-01769bff334dcc035 --destination-cidr-block 0.0.0.0/0
//finally, update public 2 subnets to use this route table
$ aws ec2 associate-route-table --route-table-id rtb-0f45fc46edec61d8f --subnet-id subnet-09f8f7f06c27cb0a0
$ aws ec2 associate-route-table --route-table-id rtb-0f45fc46edec61d8f --subnet-id subnet-026058e32f09c28af
//public subnet can assign public IP when launch EC2 $ aws ec2 modify-subnet-attribute --subnet-id subnet-09f8f7f06c27cb0a0 --map-public-ip-on-launch
$ aws ec2 modify-subnet-attribute --subnet-id subnet-026058e32f09c28af --map-public-ip-on-launch
On the other hand, the private subnet doesn't need a public IP address. However, a private subnet sometimes needs to access the internet, for example, to download some packages and access the AWS service. In this case, we still have an option to connect to the internet. This is called a Network Address Translation Gateway (NAT-GW).
A NAT-GW allows private subnets to access the public internet through the NAT-GW. Consequently, the NAT-GW must be located at a public subnet, and the private subnet routing table points to the NAT-GW as a default gateway. Note that in order to access a NAT-GW on the public network, it needs an Elastic IP (EIP) attached to the NAT-GW.
In the following example, a NAT-GW is created:
//allocate EIP, it returns allocation id as eipalloc-044f4dbafe870a04a $ aws ec2 allocate-address
{
"PublicIp": "54.161.228.168",
"AllocationId": "eipalloc-044f4dbafe870a04a",
"PublicIpv4Pool": "amazon",
"Domain": "vpc"
}
//create NAT-GW on public subnet (subnet-09f8f7f06c27cb0a0) //also assign EIP eipalloc-044f4dbafe870a04a $ aws ec2 create-nat-gateway --subnet-id subnet-09f8f7f06c27cb0a0 --allocation-id eipalloc-044f4dbafe870a04a
{
"NatGateway": {
"CreateTime": "2018-12-09T20:17:33.000Z",
"NatGatewayAddresses": [
{
"AllocationId": "eipalloc-044f4dbafe870a04a"
}
],
"NatGatewayId": "nat-05e34091f53f10172",
"State": "pending",
"SubnetId": "subnet-09f8f7f06c27cb0a0",
"VpcId": "vpc-0ca37d4650963adbb"
}
}
Creating a NAT-GW takes a few minutes. Once it's created, update a private subnet routing table that points to the NAT-GW, and then any EC2 instances are able to access the internet; again, however, due to no public IP address on the private subnet, there's no chance of access from the public internet to the private subnet EC2 instances.
In the following example, an update routing table for the private subnet points to a NAT-GW as the default gateway:
//as same as public route, need to create a route table first $ aws ec2 create-route-table --vpc-id vpc-0ca37d4650963adbb
{
"RouteTable": {
"Associations": [],
"PropagatingVgws": [],
"RouteTableId": "rtb-08572c332e7e4f14e",
...
//then assign default gateway as NAT-GW $ aws ec2 create-route --route-table-id rtb-08572c332e7e4f14e --nat-gateway-id nat-05e34091f53f10172 --destination-cidr-block 0.0.0.0/0
//finally update private subnet routing table $ aws ec2 associate-route-table --route-table-id rtb-08572c332e7e4f14e --subnet-id subnet-04b78ed9b5f96d76e
$ aws ec2 associate-route-table --route-table-id rtb-08572c332e7e4f14e --subnet-id subnet-08e16157c15cefcbc
Overall, there are four subnets that have been configured as two public subnets and two private subnets. Each subnet has a default route to use IGW and NAT-GW as follows. Note that the ID varies because AWS assigns a unique identifier:
Types of subnet |
CIDR block | Availability zone | Subnet ID | Route table ID | Default gateway | Assign Public IP while EC2 launches |
Public | 10.0.1.0/24 | us-east-1a |
subnet- 09f8f7f06c27cb0a0 |
rtb- 0f45fc46edec61d8f |
igw- 01769bff334dcc035 (IGW) |
Yes |
Private | 10.0.2.0/24 | us-east-1b |
subnet- 04b78ed9b5f96d76e |
rtb- 08572c332e7e4f14e |
nat- 05e34091f53f10172 (NAT-GW) |
No (default) |
Public | 10.0.3.0/24 | us-east-1b |
subnet- 026058e32f09c28af |
rtb- 0f45fc46edec61d8f |
igw- 01769bff334dcc035 (IGW) |
Yes |
Private | 10.0.4.0/24 | us-east-1a |
subnet- 08e16157c15cefcbc |
rtb- 08572c332e7e4f14e |
nat- 05e34091f53f10172 (NAT-GW) |
No (default) |
Now if you launch an EC2 instance on the public subnet, it becomes public facing, so you can serve your application from this subnet.
On the other hand, if you launch an EC2 instance on the private subnet, it can still access the internet through the NAT-GW, but there will be no access from the internet. However, it can still access it from the EC2 host on the public subnet. So, ideally, you can deploy internal services such as databases, middleware, and monitoring tools on the private subnet.