Cloud Tech by Victor
DevOpsIntermediate

AWS VPC Networking

How Amazon VPC, subnets, security groups, and network ACLs control traffic in AWS, and why security groups (stateful, instance-level) and network ACLs (stateless, subnet-level) are not interchangeable.

Updated 2026-07-244 min read

Overview

Amazon VPC is the isolated virtual network within a region, defined by a CIDR block, with subnets dividing it per Availability Zone. Traffic control happens at two distinct layers that are easy to confuse: security groups are stateful and attach to instances/ENIs, allow rules only, with return traffic automatically permitted, while network ACLs are stateless and attach to whole subnets, supporting numbered allow and deny rules evaluated in order, with no memory of prior traffic. Connecting VPCs together adds a third thing to get right, peering connections are explicitly non-transitive and still require both a manual route-table entry and permissive security groups before traffic actually flows, accepting a peering connection alone doesn't route anything.

Quick Reference

ConceptPurposeKey trait
VPCIsolated virtual network within a regionDefined by a CIDR block
SubnetAZ-scoped segment of a VPCPublic (route to an internet gateway) or private
Security groupStateful, instance/ENI-level firewallAllow rules only, return traffic auto-permitted
Network ACLStateless, subnet-level firewallNumbered allow/deny rules, evaluated in order, first match wins
VPC peeringDirect one-to-one VPC connectivityNon-transitive, needs a route-table entry on both sides

Syntax

bash
aws ec2 create-vpc --cidr-block 10.0.0.0/16

aws ec2 authorize-security-group-ingress \
  --group-id sg-0123456789abcdef0 \
  --protocol tcp --port 443 --cidr 0.0.0.0/0

Examples

bash
# Accepting a peering connection does not route any traffic by
# itself; both VPC owners still have to add a route pointing at
# the peer's CIDR before instances on either side can reach each other.
aws ec2 create-route \
  --route-table-id rtb-0123456789abcdef0 \
  --destination-cidr-block 10.1.0.0/16 \
  --vpc-peering-connection-id pcx-0123456789abcdef0

Network ACLs are stateless - allow both directions explicitly

Allowing inbound traffic on a network ACL does not automatically allow the matching outbound response the way a security group would. Forgetting the return-traffic rule on a custom NACL is one of the most common causes of "the security group looks right but it still doesn't work."

Visual Diagram

Common Mistakes

  • Forgetting that network ACLs are stateless and only opening one direction of a rule, silently blocking the return traffic a security group would have allowed automatically.
  • Assuming VPC peering is transitive, then being confused when a hub VPC peered to two spokes can't route traffic between those spokes without a direct peering connection of their own.
  • Accepting a VPC peering connection and stopping there, forgetting that a route-table entry on both sides is still required before any traffic actually flows.
  • Choosing overlapping CIDR blocks between VPCs that later need to be peered, which AWS will simply refuse to connect until one side is re-addressed.

Performance

  • Security group and network ACL evaluation happen in the packet-processing path but add no meaningful latency; the real risk is rule correctness, not throughput.
  • VPC peering and Transit Gateway traffic within a Region travels over AWS's own network with low added latency; inter-Region peering adds real latency proportional to physical distance, and a lower jumbo-frame MTU (8500 vs 9001 bytes in-Region).
  • A NAT gateway scales its bandwidth automatically, from 5 Gbps up to 100 Gbps, so it isn't sized like a fixed-capacity instance; the real risks are its bandwidth ceiling, packet-per-second limits, and per-destination connection limits, exceeding any of them means distributing traffic across multiple NAT gateways or additional NAT gateway IP addresses, not just waiting for it to scale further.

Best Practices

  • Design non-overlapping CIDR blocks across every VPC from the start, anticipating future peering or Transit Gateway needs.
  • Use security groups as the primary, least-privilege access control, and treat network ACLs as an optional, coarser second layer at the subnet boundary, not a replacement.
  • Use a Transit Gateway instead of a full peering mesh once more than a couple of VPCs need to reach each other.
  • Separate public and private subnets per Availability Zone for genuine multi-AZ resilience, not a single AZ with a manually-managed "backup."

Interview questions

What is the difference between a security group and a network ACL in a VPC?

A security group is stateful and attaches at the instance/ENI level: it only supports allow rules, and if inbound traffic is allowed, the corresponding response traffic is automatically allowed back out regardless of outbound rules. A network ACL is stateless and attaches at the subnet level: it supports both explicit allow and explicit deny rules, numbered and evaluated in order starting from the lowest number, and because it has no memory of prior traffic, allowing inbound traffic does not automatically allow the matching outbound response, that has to be permitted by its own rule. Security groups are the primary, fine-grained access control per resource; network ACLs are a coarser, optional second layer at the subnet boundary.

If VPC A is peered with VPC B, and VPC B is peered with VPC C, can A reach C through B?

No. AWS VPC peering connections are explicitly non-transitive: a peering connection is a strict one-to-one relationship between exactly two VPCs, and you cannot use one VPC as a transit point for another peering connection it happens to also have. To let A reach C, a separate, direct peering connection between A and C has to be created; there is no way to route through B. A Transit Gateway, not a mesh of peering connections, is the AWS-recommended way to connect more than a couple of VPCs that all need to reach each other.

What is the difference between a public and a private subnet in a VPC?

The difference is entirely about the subnet's route table, not any property of the subnet itself: a public subnet has a route to an internet gateway for `0.0.0.0/0`, so resources with a public IP in it can reach and be reached from the internet directly. A private subnet has no such route, so its resources typically use a NAT gateway (in a public subnet) for outbound-only internet access, or no internet path at all. Both subnet types can otherwise have identical security group and NACL configuration; "public" and "private" describe reachability via routing, not a separate networking feature.

References

ShareXLinkedInReddit
Was this page helpful?
Suggest an improvement