Cloud Infrastructure Fundamentals · Module 03 of 12

Cloud networking: VPCs, subnets and routing

Build a practical networking mental model for CIDR, usable addresses, route-table association and longest-prefix matching, public/private paths, NAT/endpoints, IPv6, VPC interconnects, and stateful versus stateless controls.

Learning objectives

By the end of this module, you should be able to:

  • Calculate subnet boundaries and usable-address implications from CIDR prefixes.
  • Classify public, private and isolated subnet paths from the effective route table, including implicit use of a VPC main route table.
  • Differentiate stateful security groups from stateless subnet network ACLs and reason about return traffic.
  • Explain IPv4 NAT, S3 gateway endpoints, interface endpoints/PrivateLink and basic dual-stack IPv6 routing.
  • Recognize when VPC peering, Transit Gateway and VPC Flow Logs fit an architecture.

A VPC is an isolated virtual network boundary

A VPC/VNet defines address space and routing boundaries. Subnets divide that space into smaller ranges, usually aligned to availability zones, trust zones and workload roles. CIDR planning must leave room for growth and avoid overlap with networks that may later connect.

CIDR size is not the same as usable AWS IPv4 addresses

A /24 contains 256 IPv4 addresses mathematically. AWS reserves the first four and the last IPv4 address in each subnet, so a standard AWS /24 has 251 usable IPv4 addresses. Treat this as an AWS mapping; other providers can reserve addresses differently.

Public and private describe the effective route path

A subnet is public in AWS when its effective route table has a route to an internet gateway. An individual IPv4 workload additionally needs public addressing and security controls that permit the traffic before it can communicate with the internet.

A subnet can be explicitly associated with a route table or can implicitly use the VPC main route table. Therefore, classifying subnets requires resolving the effective table, not merely listing explicit associations.

Routes use longest-prefix matching

When several routes match a destination, the most specific destination prefix wins. A local VPC route can therefore coexist with a broad 0.0.0.0/0 default route, and more-specific endpoint, peering or transit routes can override that default for matching traffic.

NAT and VPC endpoints solve different private-egress problems

A NAT device gives private IPv4 workloads outbound internet access without exposing them directly for unsolicited inbound internet connections. Managed NAT gateways can add hourly and data-processing cost.

For Amazon S3 and DynamoDB, gateway VPC endpoints provide a private route without requiring an internet gateway or NAT device and have no additional gateway-endpoint charge. Interface endpoints use AWS PrivateLink for supported services and have their own pricing model.

Security groups are stateful; network ACLs are stateless

In AWS, security groups track connection state, so response traffic for an allowed flow is automatically permitted by the security group. Network ACLs evaluate inbound and outbound traffic separately. A restrictive NACL can therefore allow TCP 443 inbound yet still break the connection by blocking return traffic on ephemeral ports.

IPv6 changes the egress pattern

Dual-stack workloads can use both IPv4 and IPv6. A public IPv6 path commonly uses ::/0 to an internet gateway. For private outbound-only IPv6, AWS provides an egress-only internet gateway; NAT gateways are not the IPv6 equivalent. Security rules still need explicit IPv6 coverage.

Peering, transit and flow logs extend the network model

VPC peering provides private point-to-point connectivity between VPCs and does not provide transitive routing. AWS Transit Gateway acts as a centralized routing hub and supports transitive connectivity through its route tables.

VPC Flow Logs capture metadata about IP traffic to and from VPC resources. They do not replace packet capture, but they connect networking directly to the observability and audit concepts used later in Module 10.

Worked examples

See the idea in practice.

Four /24 subnets from a /22

VPC: 10.20.0.0/22
public-a:  10.20.0.0/24 → 256 addresses → 251 usable in AWS
private-a: 10.20.1.0/24 → 256 addresses → 251 usable in AWS
public-b:  10.20.2.0/24 → 256 addresses → 251 usable in AWS
private-b: 10.20.3.0/24 → 256 addresses → 251 usable in AWS
  • The /22 contains 1024 IPv4 addresses and can be divided into four non-overlapping /24s.
  • AWS reserves five IPv4 addresses per subnet; provider reservations differ, so keep CIDR math separate from provider-specific usable-address rules.

Route classification

10.20.0.0/16 → local
10.30.0.0/16 → pcx-peer
pl-s3        → vpce-s3
0.0.0.0/0   → igw-123

8.8.8.8      → IGW (public IPv4 path)
10.30.4.10   → peering route (more specific)
S3 prefix    → gateway endpoint (more specific)
  • Route lookup is longest-prefix match.
  • A default route tells you the broad egress path; more-specific routes can intentionally bypass it.
Core lab · Modes 1–2 · Concept + local simulation

Lab — CIDR, route resolution and stateful/stateless filtering

Goal: Prove all three networking objectives locally: subnet math, public/private route classification, and security-group versus NACL return-traffic behavior.

Before you start

  • Linux, macOS or Windows 11 with WSL2.
  • Python 3. No cloud account or AWS credentials required.
STEP 1

Calculate subnets and usable AWS IPv4 addresses

python3 - <<'PY'
import ipaddress
vpc=ipaddress.ip_network('10.20.0.0/22')
subs=list(vpc.subnets(new_prefix=24))
assert len(subs)==4
for s in subs:
    usable=s.num_addresses-5
    print(s,'addresses=',s.num_addresses,'aws_usable=',usable)
    assert usable==251
PY
STEP 2

Resolve effective routes using longest-prefix match

cat > /tmp/cloud-routes.json <<'JSON'
{
  "public-a":[{"dest":"10.20.0.0/22","target":"local"},{"dest":"0.0.0.0/0","target":"igw-123"}],
  "private-a":[{"dest":"10.20.0.0/22","target":"local"},{"dest":"0.0.0.0/0","target":"nat-123"},{"dest":"10.30.0.0/16","target":"pcx-123"}],
  "isolated":[{"dest":"10.20.0.0/22","target":"local"}]
}
JSON
python3 - <<'PY'
import ipaddress,json
r=json.load(open('/tmp/cloud-routes.json'))
def resolve(table,dst):
    ip=ipaddress.ip_address(dst)
    matches=[x for x in table if ip in ipaddress.ip_network(x['dest'])]
    return max(matches,key=lambda x:ipaddress.ip_network(x['dest']).prefixlen) if matches else None
def classify(table):
    default=next((x for x in table if x['dest']=='0.0.0.0/0'),None)
    return 'public' if default and default['target'].startswith('igw-') else ('private-egress' if default and default['target'].startswith('nat-') else 'isolated')
for name,table in r.items(): print(name,classify(table))
assert classify(r['public-a'])=='public'
assert classify(r['private-a'])=='private-egress'
assert classify(r['isolated'])=='isolated'
assert resolve(r['private-a'],'10.30.4.10')['target']=='pcx-123'
assert resolve(r['private-a'],'8.8.8.8')['target']=='nat-123'
PY
STEP 3

Watch a stateless NACL break return traffic

python3 - <<'PY'
# Client opens an HTTPS connection from ephemeral source port 53000 to server port 443.
flow={'client_port':53000,'server_port':443}
sg={'inbound':[443]}                     # stateful: response is associated with accepted flow
nacl={'inbound':[443],'outbound':[443]}  # intentionally wrong: no ephemeral return destination
sg_request=flow['server_port'] in sg['inbound']
sg_response=sg_request                    # stateful return accepted
nacl_request=flow['server_port'] in nacl['inbound']
nacl_response=flow['client_port'] in nacl['outbound']
print('security_group request/return',sg_request,sg_response)
print('nacl request/return',nacl_request,nacl_response)
assert sg_request and sg_response
assert nacl_request and not nacl_response
print('diagnosis: NACL outbound rules must allow the client ephemeral return port/range')
PY
STEP 4

Explain the effective-route-table caveat

A subnet with no explicit route-table association uses the VPC main route table. In your notes, write why an audit that inspects only Associations[].SubnetId can miss the real route path.

Verify

  • Each /24 is contained within 10.20.0.0/22 and has 251 usable AWS IPv4 addresses.
  • The resolver classifies IGW, NAT and isolated defaults correctly and chooses the more-specific peering route.
  • The stateful security-group model permits response traffic while the intentionally incomplete stateless NACL blocks the ephemeral return path.

Expected outcome

  • You can classify a subnet from its effective routes, explain why resource addressing still matters, and diagnose a return-path failure caused by a stateless filter.

Diagnose / troubleshoot

  • AssertionError during CIDR validation usually means a subnet is outside the VPC or overlaps another range; print each network and verify prefixes first.
  • A subnet that looks unassociated can still use the VPC main route table; inspect the main association before calling it isolated.
  • If a request reaches TCP 443 but the client times out, inspect reverse-direction NACL rules and ephemeral ports rather than changing the route table blindly.
  • If S3 traffic follows NAT unexpectedly, check for a more-specific S3 prefix-list route to a gateway VPC endpoint.
Real-world connection

Production network reviews combine effective route tables, endpoint/peering/transit paths, resource addressing, SG/NACL rules and Flow Logs. Names such as “public-a” are documentation, not evidence.

Mode 3 · Optional AWS lab

Optional AWS — inspect effective VPC routing safely

Read VPC/subnet/route-table metadata with routes and associations, then classify public/private/isolated paths without changing the network.

Resources created

  • None — this is a read-only inspection lab.

Estimated cost / risk

  • Expected incremental resource cost: none because the supplied commands are read-only.
  • Existing resources in the account can still incur their normal charges; confirm current AWS pricing for the selected Region/account.

Prerequisites

  • Optional sandbox AWS account and AWS CLI.
  • Use a least-privilege or federated identity; do not paste long-lived access keys into course files.
AWS 1
aws ec2 describe-vpcs --query 'Vpcs[].{VpcId:VpcId,IPv4:CidrBlock,IPv6:CidrBlockAssociationSet[].Ipv6CidrBlock}' --output json
AWS 2
aws ec2 describe-subnets --query 'Subnets[].{Subnet:SubnetId,Vpc:VpcId,IPv4:CidrBlock,IPv6:Ipv6CidrBlockAssociationSet[].Ipv6CidrBlock,MapPublicIPv4:MapPublicIpOnLaunch}' --output json
AWS 3
aws ec2 describe-route-tables --query 'RouteTables[].{RT:RouteTableId,Vpc:VpcId,Associations:Associations[].{Subnet:SubnetId,Main:Main},Routes:Routes[].{IPv4:DestinationCidrBlock,IPv6:DestinationIpv6CidrBlock,Gateway:GatewayId,NAT:NatGatewayId,Endpoint:VpcEndpointId,Peering:VpcPeeringConnectionId,TGW:TransitGatewayId}}' --output json
AWS 4
aws ec2 describe-vpc-endpoints --query 'VpcEndpoints[].{Id:VpcEndpointId,Service:ServiceName,Type:VpcEndpointType,Vpc:VpcId,State:State}' --output table
AWS 5
aws ec2 describe-vpc-peering-connections --query 'VpcPeeringConnections[].{Id:VpcPeeringConnectionId,Status:Status.Code,Requester:RequesterVpcInfo.VpcId,Accepter:AccepterVpcInfo.VpcId}' --output table

Verify

  • For each subnet, identify an explicit route-table association or the VPC main route table that applies implicitly.
  • Classify 0.0.0.0/0 targets: internet gateway = public routing path; NAT = private outbound IPv4 path; no default = isolated unless another route supplies the required destination.
  • Observe any ::/0 route separately from IPv4 and identify internet-gateway versus egress-only-internet-gateway intent.
  • No AWS resources are created by the supplied commands.

Cleanup

  • No AWS cleanup is required because this lab creates no AWS resources.

Warnings

  • Optional only: not required for course completion or the main validator.
  • Do not create a NAT Gateway for this course; managed NAT can incur continuing hourly/data-processing charges.
  • A gateway endpoint for S3/DynamoDB is different from a PrivateLink interface endpoint; inspect existing resources only.
  • Do not change routes, endpoints, peerings or IPv6 settings in a shared or production VPC.
Avoid these traps

Common mistakes

  • Using overlapping CIDR ranges that later prevent straightforward peering or hybrid routing.
  • Calling a subnet public without resolving its effective route table, including implicit main-table association.
  • Assuming an internet-gateway route alone gives an IPv4 instance internet access without public addressing and security rules.
  • Treating stateful security groups and stateless NACLs as interchangeable.
  • Paying for NAT traffic to S3 when an appropriate gateway endpoint can satisfy the private path.
  • Adding IPv6 addresses but forgetting ::/0 routing and IPv6 security rules.
Knowledge check

Can you explain it without looking back?

Open each answer only after you have tried to answer the question yourself.

1What does longest-prefix match mean?

When multiple routes match a destination, the route with the most specific destination prefix is selected.

2What makes an AWS subnet public at the routing layer?

Its effective route table has a route to an internet gateway; an individual IPv4 resource still needs public addressing and appropriate security controls for internet communication.

3Why can a NACL break return traffic even when the inbound application port is allowed?

NACLs are stateless, so the reverse direction must be allowed separately, including the required ephemeral destination port/range.

4Scenario: a private subnet has 0.0.0.0/0 → NAT, but S3 traffic should avoid NAT cost. What route pattern is appropriate?

Associate an S3 gateway VPC endpoint and use its more-specific S3 prefix-list route so S3 traffic takes the endpoint while other IPv4 internet traffic can still use the NAT path.

My Learning

Record your progress for this module.

Progress is saved in this browser immediately. When you sign in to My Learning, it can also sync across devices.

Not started

Attempt the core lab and knowledge checks before marking the module complete.