The VPC is the central container element in EC2 networking. It holds all the other building blocks and provides a separate environment where you can launch instances and define how they can connect to each other and the internet.
VPC stands for “Virtual Private Cloud” and the cloud part is in a sense that it’s like multiple virtual data centers with routing, servers, and all the other things you’d find in a cluster of real data centers.
A VPC is region-specific. There are ways to connect two or more of them across regions, called VPC peering, but that’s a more advanced feature.
The primary configuration of a VPC is its IP address range. It determines which addresses are inside the VPC. Each machine (network interface) gets an address from this range and can find other machines using their internal IPs. This range is also internal to the VPC, as it affects only things inside but an outside observer can not see it.
IP address blocks are defined in a so-called CIDR block, which is a combination of a network IP and a mask. It is covered in the next section if you are not familiar with this term.
The official recommendation is to use a /16 range, such as 10.0.0.0/16, which contains 65536 addresses (10.0.0.0 - 10.0.255.255). this is usually enough for most workloads.
CIDR blocks (Classless Inter-Domain Routing) are how routing works on the Internet and thus match how IP addresses are allocated.
A block consists of two parts: an address and a network mask. The network mask defines how many bits identify the network in the address. To think about bits, it’s easier to convert the IP into binary form: 203.0.113.0 is 11001011.00000000.01110001.00000000. The
/24 network mask defines that the first 24 bits are the network: 11001011.00000000.01110001.00000000. This leaves the last 8 bits for addresses inside this CIDR block.
The CIDR block matches all IP addresses that start with the network address. For the 203.0.113.0/24, the first address is 11001011.00000000.01110001.00000000 and the last one is 11001011.00000000.01110001.11111111, or in decimal form: 203.0.113.0 - 203.0.113.255.
Due to the way the network mask is defined, the
/32 network mask matches only 1 address, and the
/0 mask matches all addresses.
The main feature of a VPC is that it allows networked devices to communicate with each other. Let’s see first how to configure connections!
A region has multiple Availability Zones (AZs, for short). These are individual data centers that are separated from each other, so (theoretically) if something affects one zone it won’t impact the others. Using multiple AZs is the basis of engineering for high availability: these data centers are integrated enough to make it easy to spread computing workload across them but separated enough that a problem won’t knock all of them offline.
A subnet is part of the VPC that is AZ-specific. Think of it as a network inside a single data center.
A subnet also needs an IP address range, this time from the range allocated to the VPC. For example, if the VPC has a range of 10.0.0.0/16, then you can create subnets 10.0.0.0/24 and 10.0.1.0/24, each having 256 addresses in them. Each subnet loses 5 IP addresses as they are reserved in AWS, leaving a /24 subnet 251 usable addresses. The official recommendation is to use /24 for a subnet.
You’ll find that subnets are usually referred to as “public” and “private”. This is not a checkbox configuration but refers to whether the subnet has access to the internet through a gateway. When the machines inside the subnet can reach out to the public net, it is a “public” subnet. If it can only reach other IPs inside the VPC then it’s a “private” one.
When thinking about networking devices in a subnet it’s usually about EC2 instances. You can start an instance in a subnet and it gets an IP address from the range of the subnet, then it can communicate with other EC2 instances in the VPC.
But it’s more appropriate to think about connected devices as network interfaces rather than EC2 instances. An instance can have outlets in multiple subnets, and they each behave just like a full instance. Also, there are network interfaces that are not tied to EC2 instances, such as a Lambda endpoint or an S3 gateway.
The route table defines how packets are routed inside a subnet. The VPC has a main route table that all subnets use as the default, making it easier to manage them.
All the interfaces in the VPC can route to all the others, and there is no way to change that. You can use security groups and NACLs to define rules inside the VPC, but you can’t limit routing.
The route table is usually only used when you use an Internet gateway or a NAT gateway.
By default, connections are possible inside the VPC. Let’s see how to connect the interfaces to the internet!
When you create a VPC, all the interfaces can do is to communicate with each other. To also allow them access to the internet, you need to add an internet gateway (IGW, for short) and add a route pointing to it in the route table. An IGW is also a requirement if you need public IP addresses or want to use Elastic IPs.
An IGW is a separate entity from the VPC, and you need to attach it to make it usable. If you delete the VPC you need to also delete the IGW.
After attaching the IGW to the VPC, you need to add a route so that traffic destined to the outside is routed to it. To do this, add an entry to the route table with the destination of
0.0.0.0/0 (meaning all IP addresses) and the target of the IGW.
With this configuration set, the interfaces inside the VPC have internet connectivity.
The other way to provide internet to the interfaces in the VPC is to use a NAT gateway. This works differently from the IGW as it does not allow connections initiated from the outside. As a result, a machine in the VPC can reach the internet and can receive responses but it is unavailable from the outside. Because of this, this setup is not suitable for things like web servers that listen for connections.
The problem with this solution is pricing. While you only pay for bandwidth when you use an IGW, the NAT gateway has additional costs. You can use a NAT instance, that does the same but with software you manage and it can be cheaper but brings additional maintenance burden.
Usually, you’ll want to use an IGW, and only use a NAT gateway (or instance) when you specifically need it.
If you want to expose an instance to the internet, such as a web server that users can connect to, you’ll need a public IP address. You can configure the subnet (or the network interface) to assign a public address to instances, but those are tied to the lifecycle of the instance. If you terminate it or want to migrate the service to a different one, the IP changes.
An Elastic IP is a stable address that you can move between instances and it is fixed until you release it. You can allocate an Elastic IP and use that for a DNS record. This way you are free to reconfigure your network without users noticing.
Watch out for the pricing though. As long as an Elastic IP is attached to an instance it’s free (1 per instance), but when it’s not then there is an hourly parking fee.
VPC security is to define how interfaces inside it can communicate with each other and with the world. It defines managed firewalls on the interface, and the subnet level.
A security group defines what traffic is allowed for the interface. As we’ve covered in the Network interface chapter, an EC2 instance can have multiple interfaces. These can have different sets of security groups, allowing different types of traffic to flow through them.
A security group allows traffic based on where it’s coming from (or going to) and what port and protocol it uses. For example, a web server can allow TCP traffic on port 80:
You can also define outbound rules. For example, you can define that the web server can communicate with backend servers but not directly with the databases. These are outbound rules that define the destinations.
By default, each security group gets an outbound rule that allows all traffic:
Usually, you’ll want to define a stricter rule, according to the principle of least privilege. This rule denies all outgoing traffic:
Security groups are stateful. This means they allow return traffic automatically, you only need to configure how a connection can be made. For example, you allow port 80 for a web server and that’s enough to make it serve HTTP requests without any outgoing rule to allow sending HTTP responses.
While security groups work on the interface-level, NACLs (Network Access Control List) control traffic going in and out of a subnet. Every packet that crosses the boundary is subject to these rules.
You can use NACLs to define how subnets can communicate with each other, such as which ones are allowed to reach which others. For example, you can define 3 subnets: one for web servers, one for backend servers, and one for the databases (a fairly common 3-tiered architecture). With NACLs, you can restrict that only the backend servers can communicate with the databases.
Contrary to security groups, NACLs are stateless. When a packet reaches an instance, the return packet must also be allowed to go out, otherwise the sender is unable to receive the response.
Let’s see an example! To allow a web server in a subnet to receive HTTP requests on port 80, you need to add an allow rule that enables incoming requests to enter the subnet:
When a browser makes a request to a web server, it uses a local port in the ephemeral range. There is an official recommendation for this, which allocates ports 49152 - 65535 to listen for return traffic. But in practice, the range is usually wider than that. For example, Linux usually use 32768 - 65535, but AWS Lambda and ELB go down as low as 1024. The safest setting is the 1024 - 65535 range.
Ephemeral ports are important for return traffic. When there are multiple connections to the same server, it can use different ports so that when responses are coming back there is a way to know which are for which requests. But that also means a NACL must allow outgoing traffic on these ports. You can configure it with an outbound rule:
NACLs use a priority-based rule system. You can define allow and deny rules as well, and the first one that matches the connection will be effective. In the above examples, if the first rule does not match, the second (all traffic) will, and deny the packet.
VPC is a powerful tool to define how machines and interfaces can communicate with each other and with the world. You as a network architect have a lot of tools to fine-tune how IPs are assigned, which parts of the network can reach the internet, and what traffic is allowed.