Skip to content

VPC and subnets

2 min read · main part only; folded sections are optional

After this you can answer: Why do the database and the cache sit in subnets the internet cannot reach?

flowchart TB
subgraph VPC["VPC 10.0.0.0/16"]
P1["public-1<br/>10.0.0.0/24<br/>ALB, tasks"]
P2["public-2<br/>10.0.1.0/24<br/>ALB, tasks"]
R1["private-1<br/>10.0.10.0/24<br/>Postgres, Valkey"]
R2["private-2<br/>10.0.11.0/24"]
end
I((Internet)) --> P1
I --> P2

Each column is one availability zone. Only the public subnets touch the internet.

  1. The VPC sets the address range. 10.0.0.0/16 gives about 65,000 private addresses. DNS support is on, so database endpoints resolve to private addresses.
  2. A subnet is a slice of that range in one availability zone. A /24 holds 256 addresses (AWS keeps 5 of them).
  3. Public or private is decided by the route table, not by the subnet itself. A subnet whose route table sends 0.0.0.0/0 to the internet gateway is public. One without that route is private.
  4. Two of each, in two zones. An internet-facing ALB, an RDS subnet group and an ElastiCache subnet group all demand at least two availability zones.

All four subnets are made in infra/src/network.ts → createNetwork: minitickets-dev-public-1 and -public-2, minitickets-dev-private-1 and -private-2. The private subnets have mapPublicIpOnLaunch false, so nothing there ever gets a public IP.

The api and web tasks run in the public subnets with a public IP. That is unusual, and it is on purpose: there is no NAT gateway, so a task needs a public IP to reach ECR, Secrets Manager and CloudWatch Logs. Their security groups still allow traffic only from the load balancer.

From → toWhat happensWhat allows it
Private subnets → VPC10.0.10.0/24 and 10.0.11.0/24 are slices of 10.0.0.0/16
  • config aws.ec2.Subnet vpcId = the VPC, mapPublicIpOnLaunch falsecreateNetwork
Private subnets → Private route tableboth private subnets use this route table: local route only
  • route route table associations minitickets-dev-private-rta-1 and -2; no 0.0.0.0/0 routecreateNetwork
RDS Postgres → Private subnetsonly when dataEnabled = truethe database lives in the private subnets
  • config DB subnet group minitickets-dev-db-subnets (both private subnets), publiclyAccessible: falsecreatePostgres
ElastiCache Valkey → Private subnetsonly when dataEnabled = truethe cache lives in the private subnets
  • config cache subnet group minitickets-dev-valkey-subnets (both private subnets)createCache
See stage 1 on the map →

VPC → Subnets → filter minitickets-dev. Look at IPv4 CIDR, Availability Zone and the Route table tab.

SymptomCauseWhere to look
New tasks stop: unable to pull secrets or registry authThe task got no public IP, and there is no NATECS → stopped task → Stopped reason
A review finds an internet route on a private subnetIt was associated with the public route tableVPC → Subnets → Route table tab
Creating the ALB failsOnly one public subnet was givenEC2 → Load Balancers → Network mapping
Isn't a task with a public IP a security risk?

The public IP is a way out, not a way in: the web and api security groups allow inbound traffic only from the ALB’s security group. The risk is a wrong rule. A NAT gateway would add a second layer, at about 30+ USD a month.

Why two availability zones if we run one task?

The ALB, RDS and ElastiCache refuse to be created with fewer than two. It also means a second task could start in the other zone if one zone has trouble.

What happens if two subnet ranges overlap?

AWS refuses to create the second subnet: every address must belong to exactly one subnet. pulumi preview shows the conflict before anything changes.

Advanced: Subnet values

The ranges come from publicCidrs and privateCidrs in infra/src/network.ts, placed in the first two availability zones the region reports. RDS uses the DB subnet group minitickets-dev-db-subnets; Valkey uses minitickets-dev-valkey-subnets. Both list only the two private subnets.

Answer these without scrolling up. If one feels hard, reread that section.

  1. What is the VPC’s address range?
  2. What makes a subnet public?
  3. Which pieces live in the private subnets?
  4. Why do the tasks have public IPs, and what stops the internet from calling them?
  5. Why two availability zones?

Redraw it from memory: the VPC with two public and two private subnets, their ranges, and what lives in each

Try this: on the map, select Private subnets and open the Connections tab: which pieces live there?

Read this book online: https://book.theversehub.in/