Skip to content
beginner Phase 11 · Cloud Fundamentals

Cloud Networking

Design virtual networks with subnets, route tables, internet gateways, and private connectivity in the cloud.

50m
0 problems
Topic Progress 0%

VPC Architecture

VPC Architecture

VPC Design

Production VPC (10.0.0.0/16 = 65,536 IPs)

┌─────────────────────────────────────────────────────┐
│                    VPC 10.0.0.0/16                    │
│                                                       │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  │
│  │ Public Subnet│  │ Public Subnet│  │ Public Subnet│  │
│  │  10.0.1.0/24│  │  10.0.2.0/24│  │  10.0.3.0/24│  │
│  │   AZ-1a     │  │   AZ-1b     │  │   AZ-1c     │  │
│  │  ALB, NAT GW│  │  ALB, NAT GW│  │  ALB, NAT GW│  │
│  └─────────────┘  └─────────────┘  └─────────────┘  │
│                                                       │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  │
│  │Private Subnet│  │Private Subnet│  │Private Subnet│  │
│  │ 10.0.10.0/24│  │ 10.0.20.0/24│  │ 10.0.30.0/24│  │
│  │   AZ-1a     │  │   AZ-1b     │  │   AZ-1c     │  │
│  │  App Servers │  │  App Servers │  │  App Servers │  │
│  └─────────────┘  └─────────────┘  └─────────────┘  │
│                                                       │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  │
│  │Private Subnet│  │Private Subnet│  │Private Subnet│  │
│  │ 10.0.100.0/24│ │ 10.0.200.0/24│ │ 10.0.250.0/24│  │
│  │   AZ-1a     │  │   AZ-1b     │  │   AZ-1c     │  │
│  │  Databases  │  │  Databases   │  │  Databases   │  │
│  └─────────────┘  └─────────────┘  └─────────────┘  │
└─────────────────────────────────────────────────────┘

Public subnets:  Internet-facing (ALB, Bastion, NAT)
Private subnets: No direct internet (App servers, Databases)

Terraform VPC

resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = { Name = "production-vpc" }
}

resource "aws_subnet" "public" {
  count                   = 3
  vpc_id                  = aws_vpc.main.id
  cidr_block              = cidrsubnet(aws_vpc.main.cidr_block, 8, count.index + 1)
  availability_zone       = data.aws_availability_zones.available.names[count.index]
  map_public_ip_on_launch = true

  tags = { Name = "public-${count.index + 1}" }
}

resource "aws_subnet" "private" {
  count             = 3
  vpc_id            = aws_vpc.main.id
  cidr_block        = cidrsubnet(aws_vpc.main.cidr_block, 8, count.index + 10)
  availability_zone = data.aws_availability_zones.available.names[count.index]

  tags = { Name = "private-${count.index + 1}" }
}

resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id
  tags   = { Name = "main-igw" }
}

resource "aws_nat_gateway" "main" {
  allocation_id = aws_eip.nat.id
  subnet_id     = aws_subnet.public[0].id
  tags          = { Name = "main-nat" }
}

resource "aws_eip" "nat" {
  domain = "vpc"
}

Subnet Routing

# Public route table
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.main.id
  }
  tags = { Name = "public-rt" }
}

# Private route table (through NAT)
resource "aws_route_table" "private" {
  vpc_id = aws_vpc.main.id
  route {
    cidr_block     = "0.0.0.0/0"
    nat_gateway_id = aws_nat_gateway.main.id
  }
  tags = { Name = "private-rt" }
}

# Associate subnets
resource "aws_route_table_association" "public" {
  count          = 3
  subnet_id      = aws_subnet.public[count.index].id
  route_table_id = aws_route_table.public.id
}

resource "aws_route_table_association" "private" {
  count          = 3
  subnet_id      = aws_subnet.private[count.index].id
  route_table_id = aws_route_table.private.id
}

VPC Peering

# Peering between two VPCs
aws ec2 create-vpc-peering-connection \
    --vpc-id vpc-abc123 \
    --peer-vpc-id vpc-def456

# Accept peering
aws ec2 accept-vpc-peering-connection --vpc-peering-connection-id pcx-abc

# Add route to peered VPC
aws ec2 create-route \
    --route-table-id rtb-abc \
    --destination-cidr-block 10.1.0.0/16 \
    --vpc-peering-connection-id pcx-abc

Load Balancing

Load Balancing

Application Load Balancer (ALB)

resource "aws_lb" "web" {
  name               = "web-alb"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.alb.id]
  subnets            = aws_subnet.public[*].id

  enable_deletion_protection = true

  access_logs {
    bucket  = aws_s3_bucket.alb_logs.id
    prefix  = "alb"
    enabled = true
  }
}

resource "aws_lb_target_group" "web" {
  name     = "web-tg"
  port     = 80
  protocol = "HTTP"
  vpc_id   = aws_vpc.main.id

  health_check {
    path                = "/health"
    port                = "traffic-port"
    healthy_threshold   = 3
    unhealthy_threshold = 3
    timeout             = 5
    interval            = 30
    matcher             = "200"
  }
}

resource "aws_lb_listener" "http" {
  load_balancer_arn = aws_lb.web.arn
  port              = 80
  protocol          = "HTTP"

  default_action {
    type = "redirect"
    redirect {
      port        = "443"
      protocol    = "HTTPS"
      status_code = "HTTP_301"
    }
  }
}

resource "aws_lb_listener" "https" {
  load_balancer_arn = aws_lb.web.arn
  port              = 443
  protocol          = "HTTPS"
  ssl_policy        = "ELBSecurityPolicy-TLS13-1-2-2021-06"
  certificate_arn   = aws_acm_certificate.web.arn

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.web.arn
  }
}

# Path-based routing
resource "aws_lb_listener_rule" "api" {
  listener_arn = aws_lb_listener.https.arn
  priority     = 100

  action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.api.arn
  }

  condition {
    path_pattern {
      values = ["/api/*"]
    }
  }
}

Network Load Balancer (NLB)

# NLB for TCP/UDP workloads (databases, game servers)
resource "aws_lb" "db" {
  name               = "db-nlb"
  internal           = true
  load_balancer_type = "network"
  subnets            = aws_subnet.private[*].id
}

resource "aws_lb_target_group" "db" {
  name     = "db-tg"
  port     = 5432
  protocol = "TCP"
  vpc_id   = aws_vpc.main.id
}

ALB vs NLB

Feature ALB NLB
Layer L7 (HTTP/HTTPS) L4 (TCP/UDP)
Content routing Yes No
WebSocket Yes Yes
Static IP No Yes
Latency Higher Lower
Cost Lower Higher
Use case Web apps, APIs Databases, game servers

DNS and CDN

DNS and CDN

Route 53

# Create hosted zone
aws route53 create-hosted-zone --name example.com --caller-reference $(date +%s)

# Create A record
aws route53 change-resource-record-sets --hosted-zone-id Z123 --change-batch '{
  "Changes": [{
    "Action": "CREATE",
    "ResourceRecordSet": {
      "Name": "api.example.com",
      "Type": "A",
      "AliasTarget": {
        "DNSName": "alb-123.us-east-1.elb.amazonaws.com",
        "HostedZoneId": "Z35SXDOTRQ7X7K",
        "EvaluateTargetHealth": true
      }
    }
  }]
}'

# Health-checked DNS (failover)
aws route53 change-resource-record-sets --hosted-zone-id Z123 --change-batch '{
  "Changes": [{
    "Action": "CREATE",
    "ResourceRecordSet": {
      "Name": "api.example.com",
      "Type": "A",
      "SetIdentifier": "primary",
      "Failover": "PRIMARY",
      "TTL": 60,
      "ResourceRecords": [{"Value": "1.2.3.4"}]
    }
  }, {
    "Action": "CREATE",
    "ResourceRecordSet": {
      "Name": "api.example.com",
      "Type": "A",
      "SetIdentifier": "secondary",
      "Failover": "SECONDARY",
      "TTL": 60,
      "ResourceRecords": [{"Value": "5.6.7.8"}]
    }
  }]
}'

CloudFront (CDN)

resource "aws_cloudfront_distribution" "web" {
  origin {
    domain_name = aws_lb.web.dns_name
    origin_id   = "alb"

    custom_origin_config {
      http_port              = 80
      https_port             = 443
      origin_protocol_policy = "https-only"
      origin_ssl_protocols   = ["TLSv1.2"]
    }
  }

  enabled             = true
  default_root_object = "index.html"
  aliases             = ["example.com", "www.example.com"]

  default_cache_behavior {
    allowed_methods        = ["GET", "HEAD", "OPTIONS"]
    cached_methods         = ["GET", "HEAD"]
    target_origin_id       = "alb"
    viewer_protocol_policy = "redirect-to-https"
    compress               = true

    forwarded_values {
      query_string = false
      cookies {
        forward = "none"
      }
    }

    min_ttl     = 0
    default_ttl = 86400    # 1 day
    max_ttl     = 31536000 # 1 year
  }

  # Cache static assets longer
  ordered_cache_behavior {
    path_pattern           = "/static/*"
    allowed_methods        = ["GET", "HEAD"]
    cached_methods         = ["GET", "HEAD"]
    target_origin_id       = "alb"
    viewer_protocol_policy = "redirect-to-https"
    min_ttl                = 0
    default_ttl            = 86400
    max_ttl                = 31536000
  }

  viewer_certificate {
    acm_certificate_arn = aws_acm_certificate.web.arn
    ssl_support_method  = "sni-only"
  }

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }
}

Best Practices

# 1. Use multiple AZs for high availability
# 2. Put databases in private subnets
# 3. Use NAT gateways for private subnet internet access
# 4. Use VPC endpoints for AWS services (avoid NAT costs)
# 5. Use security groups (stateful) not NACLs (stateless)
# 6. Enable VPC flow logs for debugging
# 7. Use SSM Session Manager instead of bastion hosts
# 8. Use CloudFront for static assets and caching