Networking
This document describes the VPC architecture, subnets, security groups, routing, and network security for MenoTime. The design follows AWS security best practices with clear separation between public and private resources.
VPC Architecture
VPC: menotime-vpc (CIDR: 10.0.0.0/16)
┌────────────────────────────────────────────────────────┐
│ menotime-vpc (10.0.0.0/16) │
├────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Public Subnets (Tier 1) │ │
│ ├──────────────────────────────────────────────────┤ │
│ │ us-west-1a: 10.0.1.0/24 │ │
│ │ ├─ ALB Subnet (primary) │ │
│ │ ├─ NAT Gateway (outbound for private subnets) │ │
│ │ └─ Internet Gateway route │ │
│ │ │ │
│ │ us-west-1b: 10.0.2.0/24 │ │
│ │ ├─ ALB Subnet (secondary) │ │
│ │ ├─ NAT Gateway (redundancy) │ │
│ │ └─ Internet Gateway route │ │
│ └──────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Private Subnets (Tier 2) - ECS Tasks │ │
│ ├──────────────────────────────────────────────────┤ │
│ │ us-west-1a: 10.0.11.0/24 │ │
│ │ ├─ ECS Tasks (no IGW access) │ │
│ │ ├─ NAT Gateway outbound (via pub 10.0.1.0/24) │ │
│ │ └─ Secrets Manager, S3 (via VPC Endpoints) │ │
│ │ │ │
│ │ us-west-1b: 10.0.12.0/24 │ │
│ │ ├─ ECS Tasks (no IGW access) │ │
│ │ ├─ NAT Gateway outbound (via pub 10.0.2.0/24) │ │
│ │ └─ Secrets Manager, S3 (via VPC Endpoints) │ │
│ └──────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Private Subnets (Tier 3) - Database │ │
│ ├──────────────────────────────────────────────────┤ │
│ │ us-west-1a: 10.0.21.0/24 │ │
│ │ └─ RDS PostgreSQL (replica in Multi-AZ mode) │ │
│ │ │ │
│ │ us-west-1b: 10.0.22.0/24 │ │
│ │ └─ RDS PostgreSQL (primary in Multi-AZ mode) │ │
│ │ │ │
│ │ Note: No internet access; accessed only from │ │
│ │ ECS tasks via RDS security group │ │
│ └──────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────┘
Subnet Details
Public Subnets (ALB & NAT Gateways)
| Subnet | CIDR | AZ | Purpose |
|---|---|---|---|
menotime-pub-a |
10.0.1.0/24 | us-west-1a | ALB, NAT GW |
menotime-pub-b |
10.0.2.0/24 | us-west-1b | ALB, NAT GW (redundancy) |
Route Table (menotime-public-rt):
Destination | Target | Purpose
0.0.0.0/0 | IGW | Internet access (HTTP/HTTPS)
10.0.0.0/16 | Local | VPC internal routing
Available IPs per subnet: - Total: 256 addresses (10.0.1.0 - 10.0.1.255) - Usable: 251 (AWS reserves 5 per subnet) - Used: ~10 (ALB ENI + NAT Gateway + bastion if applicable)
Private Subnets (ECS Tasks)
| Subnet | CIDR | AZ | Purpose |
|---|---|---|---|
menotime-priv-ecs-a |
10.0.11.0/24 | us-west-1a | ECS tasks |
menotime-priv-ecs-b |
10.0.12.0/24 | us-west-1b | ECS tasks |
Route Table (menotime-private-ecs-rt):
Destination | Target | Purpose
0.0.0.0/0 | NAT-GW | Outbound to internet (ECR pulls, SES)
10.0.0.0/16 | Local | VPC internal routing
Network ACLs (default allow all): - Inbound: Allow from public subnets (ALB) - Inbound: Allow from database subnets (rare) - Outbound: Allow to public subnets, external services
Private Subnets (Database)
| Subnet | CIDR | AZ | Purpose |
|---|---|---|---|
menotime-priv-db-a |
10.0.21.0/24 | us-west-1a | RDS PostgreSQL |
menotime-priv-db-b |
10.0.22.0/24 | us-west-1b | RDS PostgreSQL |
Route Table (menotime-private-db-rt):
Destination | Target | Purpose
10.0.0.0/16 | Local | VPC internal routing only
Network ACLs: - Inbound: Allow PostgreSQL (5432) from private ECS subnets only - Outbound: Deny all (database doesn't initiate connections)
Internet Gateway & NAT Gateway
Internet Gateway (IGW)
Name: menotime-igw
Purpose: Enables public internet access for public subnets
Configuration:
- Attached to menotime-vpc
- Route in public route table: 0.0.0.0/0 → IGW
Traffic Flow:
Client (Internet)
↓ (HTTPS 443)
CloudFront/ALB (in public subnet, us-west-1a)
↓ (via IGW)
Internet
↓ (responses)
ALB processes and routes to ECS
NAT Gateway (Network Address Translation)
Primary: menotime-nat-gw-a in public subnet 10.0.1.0/24
Secondary (redundancy): menotime-nat-gw-b in public subnet 10.0.2.0/24
Purpose: Allows private subnet resources (ECS tasks, RDS) to reach external services while remaining unreachable from the internet
Configuration:
- Elastic IP: 52.xxx.yyy.zzz (static public IP)
- Subnet: Public subnet (us-west-1a for primary, us-west-1b for secondary)
Usage: - ECS tasks pulling Docker images from ECR (internet) - ECS tasks sending emails via SES (internet) - RDS snapshots copying to S3 (internal but routed through NAT)
Traffic Flow:
ECS Task (10.0.11.10)
↓ (request to external service)
NAT Gateway (10.0.1.xxx → 52.xxx.yyy.zzz)
↓ (outbound via IGW)
External Service (e.g., ECR.us-west-1.amazonaws.com)
↓ (response to 52.xxx.yyy.zzz)
NAT Gateway (translates back to 10.0.11.10)
↓
ECS Task receives response
Cost: ~$32/month per NAT Gateway + data processing charges
Security Groups
ALB Security Group
Name: menotime-alb-sg
Purpose: Public-facing load balancer; accepts HTTP/HTTPS from internet
Inbound Rules:
Protocol | Port | Source | Purpose
---------|------|--------|----------
HTTP | 80 | 0.0.0.0/0 | Redirect to HTTPS
HTTPS | 443 | 0.0.0.0/0 | Client connections
Outbound Rules:
Protocol | Port | Destination | Purpose
---------|------|-------------|----------
TCP | 8000 | menotime-ecs-sg | Forward to ECS tasks
ECS Security Group
Name: menotime-ecs-sg
Purpose: Container tasks; accepts traffic from ALB and initiates connections to external services
Inbound Rules:
Protocol | Port | Source | Purpose
---------|------|--------|----------
TCP | 8000 | menotime-alb-sg | Health checks, requests from ALB
Outbound Rules:
Protocol | Port | Destination | Purpose
---------|------|-------------|----------
TCP | 5432 | menotime-db-sg | Database connections
TCP | 443 | 0.0.0.0/0 | HTTPS to AWS services (Secrets Manager, SES, S3, ECR)
TCP | 587 | 0.0.0.0/0 | SMTP to SES
UDP | 53 | 0.0.0.0/0 | DNS (Route 53)
RDS Security Group
Name: menotime-db-sg
Purpose: Database; accepts only PostgreSQL traffic from ECS tasks
Inbound Rules:
Protocol | Port | Source | Purpose
---------|------|--------|----------
TCP | 5432 | menotime-ecs-sg | Database connections from ECS
TCP | 5432 | menotime-bastion-sg | Bastion host (optional, operational access)
Outbound Rules:
Protocol | Port | Destination | Purpose
---------|------|-------------|----------
(none) | | Deny all | RDS doesn't initiate connections
Bastion Security Group (Optional)
Name: menotime-bastion-sg
Purpose: Jump host for operational database access (alternative to SSM Session Manager)
Inbound Rules:
Protocol | Port | Source | Purpose
---------|------|--------|----------
TCP | 22 | YourIP/32 | SSH from specific office/VPN
Outbound Rules:
Protocol | Port | Destination | Purpose
---------|------|-------------|----------
TCP | 5432 | menotime-db-sg | Database access
TCP | 443 | 0.0.0.0/0 | HTTPS (updates, etc.)
VPC Endpoints
VPC Endpoints allow private subnet resources to access AWS services without internet traversal.
S3 Gateway Endpoint
Name: menotime-s3-gateway-endpoint
Purpose: ECS tasks access S3 for logs and backups without NAT Gateway data charges
Configuration:
- Service: com.amazonaws.us-west-1.s3
- Route Table Association: menotime-private-ecs-rt
- Policy: Allow S3 buckets: menotime-logs, menotime-backups, menotime-static-assets
Route Added:
Destination | Target
s3.us-west-1.* | menotime-s3-gateway-endpoint
Secrets Manager Interface Endpoint
Name: menotime-secretsmanager-endpoint
Purpose: ECS tasks retrieve database credentials from Secrets Manager privately
Configuration:
- Service: com.amazonaws.us-west-1.secretsmanager
- Subnets: Private ECS subnets (10.0.11.0/24, 10.0.12.0/24)
- Security Group: Allow HTTPS (443) from menotime-ecs-sg
ECR Interface Endpoint
Name: menotime-ecr-endpoint
Purpose: ECS pulls container images from ECR privately (avoids NAT GW charges)
Configuration:
- Service: com.amazonaws.us-west-1.ecr.dkr (registry) + com.amazonaws.us-west-1.ecr.api (API)
- Subnets: Private ECS subnets
- Security Group: Allow HTTPS (443) from menotime-ecs-sg
ALB Configuration
Application Load Balancer
Name: menotime-alb
Subnets: Public subnets (10.0.1.0/24, 10.0.2.0/24)
Security Group: menotime-alb-sg
Scheme: Internet-facing
ALB Listeners
Listener 1: HTTP (Port 80)
Protocol: HTTP
Port: 80
Default Action: Redirect to HTTPS (301)
Target: None (redirect only)
Listener 2: HTTPS (Port 443)
Protocol: HTTPS
Port: 443
SSL Certificate: ACM certificate for menotime.ai
SSL Policy: ELBSecurityPolicy-TLS-1-2-2017-01
Default Action: Forward to Target Group
Target Group: menotime-backend-tg
Target Group Configuration
Name: menotime-backend-tg
Protocol: HTTP (targets are ECS tasks on port 8000)
Port: 8000
VPC: menotime-vpc
Health Check:
Protocol: HTTP
Path: /health
Interval: 30 seconds
Timeout: 5 seconds
Healthy Threshold: 2
Unhealthy Threshold: 3
Matcher: 200 (HTTP 200 response required)
Stickiness: Disabled (stateless API)
Deregistration Delay: 30 seconds (graceful connection drain)
DNS Configuration
Route 53 Hosted Zone
Zone: menotime.ai (public)
Record Types:
| Name | Type | Value | TTL | Purpose |
|---|---|---|---|---|
| menotime.ai | A | CloudFront Distribution ID (alias) | — | Root domain → CloudFront |
| www.menotime.ai | CNAME | menotime.ai | 300 | www subdomain → root |
| api.menotime.ai | A | ALB DNS Name (alias) | — | API direct endpoint (optional) |
| dev-api.menotime.ai | CNAME | ALB DNS (dev) | 300 | Dev environment API |
| staging-api.menotime.ai | CNAME | ALB DNS (staging) | 300 | Staging environment API |
DNSSEC
Status: Disabled (optional; can be enabled for enhanced security)
Traffic Flow Examples
Public User Request
User Browser (203.0.113.5)
↓ HTTPS to menotime.ai
Route 53 DNS Resolution
↓ Returns CloudFront Distribution IP
CloudFront Edge Location (cached)
↓ Cache miss, fetch from origin (ALB)
Public Subnet (ALB)
↓ Port 443 → 8000 (via Security Group rule)
Private Subnet (ECS Task)
↓ FastAPI processes request
HTTP Response
↓ Back through ALB → CloudFront → User
User Browser receives HTML, assets cached by CloudFront
ECS Task External Egress (ECR Pull)
Private Subnet (ECS Task 10.0.11.50)
↓ Request to ECR API (ecr.us-west-1.amazonaws.com)
ECR Interface VPC Endpoint (10.0.11.xxx)
↓ HTTPS to AWS backend
AWS Service Network
↓ Response returned
ECS Task receives Docker image layers
Database Access
Private Subnet (ECS Task 10.0.11.50)
↓ PostgreSQL request (source: 10.0.11.50:ephemeral)
Private Subnet (RDS Instance 10.0.21.100)
↓ Security group allows menotime-ecs-sg
↓ Processes SQL query
HTTP Response (via internal network)
↓
ECS Task receives result set
Network Monitoring & Troubleshooting
VPC Flow Logs
Purpose: Monitor network traffic for debugging and security analysis
Configuration:
Source: All traffic to/from VPC
Destination: CloudWatch Logs (/aws/vpc/menotime-flow-logs)
Format: ${version} ${account-id} ${interface-id} ${srcaddr} ${dstaddr} ${srcport} ${dstport} ${protocol} ${packets} ${bytes} ${windowstart} ${windowend} ${action} ${tcpflags} ${type}
Retention: 7 days
Cost: ~$0.50/million records
Query Examples:
# Connections rejected by security groups
[version, account, interface_id, srcaddr, dstaddr, srcport, dstport, protocol, packets, bytes, windowstart, windowend, action="REJECT", tcpflags, type] |
filter srcaddr like "10.0.11"
# High traffic (data exfiltration check)
fields srcaddr, dstaddr, bytes |
stats sum(bytes) as total_bytes by srcaddr, dstaddr |
filter total_bytes > 1000000
Common Network Issues
Issue: ECS task cannot reach Secrets Manager
Debug:
# 1. Check security group allows HTTPS outbound
aws ec2 describe-security-groups \
--group-ids sg-xxxxx \
--query 'SecurityGroups[0].IpPermissionsEgress'
# 2. Verify VPC Endpoint is active
aws ec2 describe-vpc-endpoints \
--filters "Name=vpc-id,Values=vpc-xxxxx" \
--query 'VpcEndpoints[?ServiceName==`com.amazonaws.us-west-1.secretsmanager`]'
# 3. Check route table has endpoint route
aws ec2 describe-route-tables \
--filters "Name=vpc-id,Values=vpc-xxxxx" \
--query 'RouteTables[?Routes[?DestinationPrefixListId]].Routes'
Issue: ECS task cannot reach database
Debug:
# 1. Verify database security group allows source
aws ec2 describe-security-groups \
--group-ids menotime-db-sg \
--query 'SecurityGroups[0].IpPermissions'
# 2. Verify ECS task is in correct subnet
aws ecs describe-tasks \
--cluster menotime-prod-cluster \
--tasks `<task-arn>` \
--query 'tasks[0].attachments[?name==`networkInterfaceId`]'
# 3. Check RDS endpoint is reachable
telnet menotime-prod.xxxxx.us-west-1.rds.amazonaws.com 5432
Issue: NAT Gateway route missing
Fix:
aws ec2 create-route \
--route-table-id rtb-xxxxx \
--destination-cidr-block 0.0.0.0/0 \
--nat-gateway-id natgw-xxxxx
Network Security Best Practices
- Least Privilege: Security groups allow only required ports/protocols
- Segmentation: Database in isolated subnet, inaccessible from internet
- Encryption: All traffic encrypted (TLS in transit, KMS at rest)
- Monitoring: VPC Flow Logs enabled for audit and troubleshooting
- Redundancy: NAT Gateways in multiple AZs for high availability
- No Public IPs: ECS tasks and RDS have no public IPs (private subnets only)
Cost Optimization
| Component | Monthly Cost | Optimization |
|---|---|---|
| ALB | ~$16 | Consider classic LB if traffic \<1M requests/month |
| NAT Gateway (2×) | ~$64 | VPC endpoints reduce data charges; consider Single NAT |
| VPC Endpoints | ~$7-14 | Reduce NAT data charges; ROI positive |
| Data Transfer | ~$10-50 | Optimize to reduce inter-AZ traffic |
| Total Network | ~$97-144 | ~15% of infrastructure cost |
Summary
MenoTime's VPC provides: - Security: Public/private subnet separation, security groups, encryption - High Availability: Multi-AZ design with redundant NAT Gateways - Performance: VPC Endpoints reduce data transfer costs - Scalability: Room for expansion (10.0.0.0/16 = 65,536 IPs) - Compliance: Encrypted, auditable, isolated databases
For load balancer configuration, see AWS Architecture. For security and IAM, see same document.