Amazon VPC Basics
For the past five weeks, we have been getting deep in our Scalable Solutions series. At Entasis we work with our customers to help them build solutions that are Scalable in design, Resilient by nature, with Performance on demand. We feel that these three components are the pillars that all truly scalable solutions are built with. Here is what we have gone over thus far:
Week 1 – Amazon Route 53 Basics
Week 2 – AWS Certificate Manager
Week 3 – AWS Systems Manager Parameter Store
Week 4 – AWS Application Load Balancer
Week 5 – Amazon EC2 Security Groups
Today we are going to dive into another core service of AWS, Amazon VPC, now inside of the Amazon VPC product there are actually multiple constructs (one of which is named VPC) we are not going to limit ourselves to this, but rather we will go over core networking in AWS.
Create a VPC
The first thing we should discuss is why you might want to create a VPC. The single biggest reason is if you plan on interconnecting multiple AWS accounts. All AWS accounts come with a Default VPC which has an IP space of 172.31.0.0/16. This, of course, means that routing between one accounts Default VPC and another accounts Default VPC is not possible (or another cloud or datacenter location with the same 172.31.0.0/16 IP space in use). However, we can simply create a replacement VPC with the correct settings, early in the life of an account this is very simple.
The VPC is a regional construct, meaning that when you create a VPC it is created in all availability zones in a region.
PS> aws ec2 create-vpc –cidr-block 172.30.0.0/16 –region us-east-1
{
“Vpc”: {
“VpcId”: “vpc-1194576b”,
“InstanceTenancy”: “default”,
“Tags”: [],
“CidrBlockAssociationSet”: [
{
“AssociationId”: “vpc-cidr-assoc-d53fedb9”,
“CidrBlock”: “172.30.0.0/16”,
“CidrBlockState”: {
“State”: “associated”
}
}
],
“Ipv6CidrBlockAssociationSet”: [],
“State”: “pending”,
“DhcpOptionsId”: “dopt-970141ef”,
“CidrBlock”: “172.30.0.0/16”,
“IsDefault”: false
}
}
Now here we can see that we have created vpc-1194576b with a CIDR block of 172.30.0.0/16.
Create a Subnet
Now that we have a VPC we need to set up some subnets, here we are going to specify the VPC we created earlier and a subset of IP���s that are in the VPC CIDR block. So for example, if we specified 172.30.0.0/16 this would mean we could only have a single subnet in this VPC.A few things to remember about subnets and availability zones.
- Subnets can only be associated with a single availability zone.
- Not all services are available in all availability zones.
- On account creation the availability zone is randomized, so if you have multiple accounts you will need to keep in mind that us-east-1a in one account and us-east-1a in the other account are not necessarily the same availability zone. Practically this means that in the event of a total failure of a single availability zone, that we can actually experience different effects in different accounts (my us-east-1a could be your us-east-1d), our architecture must account for this. With the most important component being full multi-AZ where applicable.
- When designing your subnets you must remember to split your workloads across availability zones, so if you had a db tier and web tier and you wanted them to be in their own subnets (perhaps the DB tier is in a private subnet, and the web is in the public) you must make sure that you end up with one of each in each availability zones.
PS> aws ec2 create-subnet –vpc-id vpc-1194576b –cidr-block 172.30.0.0/24 –availability-zone us-east-1a –region us-east-1
{
“Subnet”: {
“AvailabilityZone”: “us-east-1a”,
“AvailableIpAddressCount”: 251,
“DefaultForAz”: false,
“Ipv6CidrBlockAssociationSet”: [],
“VpcId”: “vpc-1194576b”,
“State”: “pending”,
“MapPublicIpOnLaunch”: false,
“SubnetId”: “subnet-ae2767e4”,
“CidrBlock”: “172.30.0.0/24”,
“AssignIpv6AddressOnCreation”: false
}
}
A very simple pattern is to use a /16 at the VPC level but then to use /24 on the subnet level. This allows significant room to grow and it is very easy to visualize even for folks without a networking background, that said you do not need to use these, you can specify a smaller or larger CIDR block based on your requirements.
Now of course if we only create the one subnet, then we are tied to a single availability zone. This is not good for resiliency, let’s create another subnet and ensure that we specify a different availability zone than we did in the first example.
PS> aws ec2 create-subnet –vpc-id vpc-1194576b –cidr-block 172.30.1.0/24 –availability-zone us-east-1b –profile entasisawsug
{
“Subnet”: {
“AvailabilityZone”: “us-east-1b”,
“AvailableIpAddressCount”: 251,
“DefaultForAz”: false,
“Ipv6CidrBlockAssociationSet”: [],
“VpcId”: “vpc-1194576b”,
“State”: “pending”,
“MapPublicIpOnLaunch”: false,
“SubnetId”: “subnet-a8f845f4”,
“CidrBlock”: “172.30.1.0/24”,
“AssignIpv6AddressOnCreation”: false
}
}
Excellent now we have two subnets in two different availability zones.
Create Internet Gateway
Of course most use cases are going to require external connectivity, we have a couple of options for that but first, let’s talk about the Internet Gateway. Basically, if we assign an Internet Gateway to a VPC, we can then assign public IP addresses (Dynamic or Elastic IP) to resources in our VPC.
First let’s create an internet gateway.
PS> aws ec2 create-internet-gateway –region us-east-1
{
“InternetGateway”: {
“Tags”: [],
“Attachments”: [],
“InternetGatewayId”: “igw-8c8fbcf4”
}
}
This creates an internet gateway however it is not attached to any VPC, there for it is not used.
Attach Internet Gateway to VPC
Let’s attach our internet gateway to our VPC.
PS> aws ec2 attach-internet-gateway –vpc-id vpc-1194576b –internet-gateway-id igw-8c8fbcf4 –region us-east-1
So at this point, it is now attached which means we can create routes that utilize this as a target.
Create Route Table
First, we must create a route table to hold our routes. This gets created in our VPC.
PS> aws ec2 create-route-table –vpc-id vpc-1194576b –region us-east-1
{
“RouteTable”: {
“Associations”: [],
“RouteTableId”: “rtb-fedb4181”,
“VpcId”: “vpc-1194576b”,
“PropagatingVgws”: [],
“Tags”: [],
“Routes”: [
{
“GatewayId”: “local”,
“DestinationCidrBlock”: “172.30.0.0/16”,
“State”: “active”,
“Origin”: “CreateRouteTable”
}
]
}
}
Create Route for Internet Gateway
Now we can create a default route which will point all traffic 0.0.0.0/0 to our internet gateway that we created before.
PS> aws ec2 create-route –route-table-id rtb-fedb4181 –destination-cidr-block 0.0.0.0/0 –gateway-id igw-8c8fbcf4 –region us-east-1
{
“Return”: true
}
At this point any subnets that utilize this route table however since this was a new setup that association must be done manually.
Associate Route Table with Subnets
To actually make the routes effective you must associate the route table with every subnet that you would like to use its routes.
PS> aws ec2 associate-route-table –route-table-id rtb-fedb4181 –subnet-id subnet-ae2767e4 –region us-east-1
{
“AssociationId”: “rtbassoc-e22da89c”
}
You can also set a route table as the main route table, this basically makes it the default association for the VPC, so that you do not need to manually associate it with each subnet.
Create VPC Peering Connection Request
Now there comes some times where you will need to enable connectivity between two different VPCs. This can either be inside of the same account or it can be across two accounts. This will create the request which needs to be accepted on the other VPC.
PS> aws ec2 create-vpc-peering-connection –vpc-id vpc-bfa608c4 –peer-vpc-id vpc-1194576b –region us-east-1
{
“VpcPeeringConnection”: {
“Status”: {
“Message”: “Initiating Request to 310843369992”,
“Code”: “initiating-request”
},
“Tags”: [],
“RequesterVpcInfo”: {
“PeeringOptions”: {
“AllowEgressFromLocalVpcToRemoteClassicLink”: false,
“AllowDnsResolutionFromRemoteVpc”: false,
“AllowEgressFromLocalClassicLinkToRemoteVpc”: false
},
“VpcId”: “vpc-bfa608c4”,
“Region”: “us-east-1”,
“OwnerId”: “310843369992”,
“CidrBlockSet”: [
{
“CidrBlock”: “172.31.0.0/16”
}
],
“CidrBlock”: “172.31.0.0/16”
},
“VpcPeeringConnectionId”: “pcx-bf259dd7”,
“ExpirationTime”: “2018-08-01T04:48:48.000Z”,
“AccepterVpcInfo”: {
“OwnerId”: “310843369992”,
“Region”: “us-east-1”,
“VpcId”: “vpc-1194576b”
}
}
}
Now that we have created the VPC Peering request we need to accept that peering request on the distant VPC.
Accept VPC Peering Request
Once we accept the peering request we can the use the peering connection as a route target.
PS> aws ec2 accept-vpc-peering-connection –vpc-peering-connection-id pcx-bf259dd7 –region us-east-1
{
“VpcPeeringConnection”: {
“Status”: {
“Message”: “Provisioning”,
“Code”: “provisioning”
},
“Tags”: [],
“AccepterVpcInfo”: {
“PeeringOptions”: {
“AllowEgressFromLocalVpcToRemoteClassicLink”: false,
“AllowDnsResolutionFromRemoteVpc”: false,
“AllowEgressFromLocalClassicLinkToRemoteVpc”: false
},
“VpcId”: “vpc-1194576b”,
“Region”: “us-east-1”,
“OwnerId”: “310843369992”,
“CidrBlockSet”: [
{
“CidrBlock”: “172.30.0.0/16”
}
],
“CidrBlock”: “172.30.0.0/16”
},
“VpcPeeringConnectionId”: “pcx-bf259dd7”,
“RequesterVpcInfo”: {
“PeeringOptions”: {
“AllowEgressFromLocalVpcToRemoteClassicLink”: false,
“AllowDnsResolutionFromRemoteVpc”: false,
“AllowEgressFromLocalClassicLinkToRemoteVpc”: false
},
“VpcId”: “vpc-bfa608c4”,
“Region”: “us-east-1”,
“OwnerId”: “310843369992”,
“CidrBlockSet”: [
{
“CidrBlock”: “172.31.0.0/16”
}
],
“CidrBlock”: “172.31.0.0/16”
}
}
}
We will need routes on both sides.
Create Route for Peer VPC (Requester to Accepter)
We need routes on both sides in order to allow traffic from the network to another.
PS> aws ec2 create-route –route-table-id rtb-fedb4181 –destination-cidr-block 172.31.0.0/16 –vpc-peering-connection-id pcx-bf259dd7 –region us-east-1
{
“Return”: true
}
Create Route for Peer VPC (Accepter to Requester)
We need routes on both sides in order to allow traffic from network to another. This enables the return traffic.
PS> aws ec2 create-route –route-table-id rtb-2c31ec50 –destination-cidr-block 172.30.0.0/16 –vpc-peering-connection-id pcx-bf259dd7 –region us-east-1
{
“Return”: true
}
Describe Existing VPC(s)
Of course one of the things we often need to do is describe all of the VPCs in a region.
PS C:\Users\MatthewMattoon> aws ec2 describe-vpcs –region us-east-1
{
“Vpcs”: [
{
“VpcId”: “vpc-bfa608c4”,
“InstanceTenancy”: “default”,
“CidrBlockAssociationSet”: [
{
“AssociationId”: “vpc-cidr-assoc-4a3c9627”,
“CidrBlock”: “172.31.0.0/16”,
“CidrBlockState”: {
“State”: “associated”
}
}
],
“State”: “available”,
“DhcpOptionsId”: “dopt-970141ef”,
“CidrBlock”: “172.31.0.0/16”,
“IsDefault”: true
}
]
}
Describe Existing Subnet(s)
Of course we also often need to describe subnets.
PS C:\Users\MatthewMattoon> aws ec2 describe-subnets –region us-east-1
{
“Subnets”: [
{
“AvailabilityZone”: “us-east-1f”,
“AvailableIpAddressCount”: 4091,
“DefaultForAz”: true,
“Ipv6CidrBlockAssociationSet”: [],
“VpcId”: “vpc-bfa608c4”,
“State”: “available”,
“MapPublicIpOnLaunch”: true,
“SubnetId”: “subnet-45b36c4a”,
“CidrBlock”: “172.31.64.0/20”,
“AssignIpv6AddressOnCreation”: false
},
{
“AvailabilityZone”: “us-east-1a”,
“AvailableIpAddressCount”: 4091,
“DefaultForAz”: true,
“Ipv6CidrBlockAssociationSet”: [],
“VpcId”: “vpc-bfa608c4”,
“State”: “available”,
“MapPublicIpOnLaunch”: true,
“SubnetId”: “subnet-233dd569”,
“CidrBlock”: “172.31.16.0/20”,
“AssignIpv6AddressOnCreation”: false
},
{
“AvailabilityZone”: “us-east-1b”,
“AvailableIpAddressCount”: 4091,
“DefaultForAz”: true,
“Ipv6CidrBlockAssociationSet”: [],
“VpcId”: “vpc-bfa608c4”,
“State”: “available”,
“MapPublicIpOnLaunch”: true,
“SubnetId”: “subnet-5d88ac00”,
“CidrBlock”: “172.31.32.0/20”,
“AssignIpv6AddressOnCreation”: false
},
{
“AvailabilityZone”: “us-east-1c”,
“AvailableIpAddressCount”: 4091,
“DefaultForAz”: true,
“Ipv6CidrBlockAssociationSet”: [],
“VpcId”: “vpc-bfa608c4”,
“State”: “available”,
“MapPublicIpOnLaunch”: true,
“SubnetId”: “subnet-aa525fce”,
“CidrBlock”: “172.31.0.0/20”,
“AssignIpv6AddressOnCreation”: false
},
{
“AvailabilityZone”: “us-east-1d”,
“AvailableIpAddressCount”: 4090,
“DefaultForAz”: true,
“Ipv6CidrBlockAssociationSet”: [],
“VpcId”: “vpc-bfa608c4”,
“State”: “available”,
“MapPublicIpOnLaunch”: true,
“SubnetId”: “subnet-ce0627e1”,
“CidrBlock”: “172.31.80.0/20”,
“AssignIpv6AddressOnCreation”: false
},
{
“AvailabilityZone”: “us-east-1e”,
“AvailableIpAddressCount”: 4091,
“DefaultForAz”: true,
“Ipv6CidrBlockAssociationSet”: [],
“VpcId”: “vpc-bfa608c4”,
“State”: “available”,
“MapPublicIpOnLaunch”: true,
“SubnetId”: “subnet-ad742d92”,
“CidrBlock”: “172.31.48.0/20”,
“AssignIpv6AddressOnCreation”: false
}
]
}