AWS Networking Deep Dive: VPC, Route 53, CloudFront, and Load Balancers (Part 4 of 6)

Networking is the foundation of every AWS architecture. This guide covers VPC design, DNS with Route 53, content delivery with CloudFront, and load balancing—with production-ready code examples.

📚
AWS FUNDAMENTALS SERIES

This is Part 4 of a 6-part series covering AWS Cloud Platform.

  • Part 1: Fundamentals
  • Part 2: Compute Services
  • Part 3: Storage & Databases
  • Part 4 (this article): Networking
  • Part 5: Security & Compliance
  • Part 6: DevOps & IaC

AWS Networking Services Overview

AWS networking services enable you to build secure, scalable, and globally distributed applications. From VPCs for network isolation to CloudFront for global content delivery.

AWS Networking Services Overview
Figure 1: AWS Networking Services Architecture

Amazon VPC (Virtual Private Cloud)

VPC is your isolated network in AWS. You control IP addressing, subnets, route tables, and network gateways. Every resource you launch runs inside a VPC.

AWS VPC Multi-AZ Architecture
Figure 2: Production VPC Design with Public and Private Subnets

VPC Design Best Practices

Component Best Practice Why
CIDR Block Use /16 for VPC, /24 for subnets Room to grow, avoid overlap with on-prem
Subnets Minimum 2 AZs, prefer 3 High availability, AZ failure tolerance
NAT Gateway One per AZ for HA Avoid single point of failure
VPC Endpoints Use for S3, DynamoDB, ECR Private traffic, reduce NAT costs
Flow Logs Enable on all VPCs Security analysis, troubleshooting

VPC with AWS CDK

// AWS CDK: Production VPC with all best practices
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as logs from 'aws-cdk-lib/aws-logs';

export class VpcStack extends cdk.Stack {
  public readonly vpc: ec2.Vpc;

  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Production VPC
    this.vpc = new ec2.Vpc(this, 'ProductionVpc', {
      ipAddresses: ec2.IpAddresses.cidr('10.0.0.0/16'),
      maxAzs: 3,
      
      // NAT Gateway per AZ for high availability
      natGateways: 3,
      
      subnetConfiguration: [
        {
          cidrMask: 24,
          name: 'Public',
          subnetType: ec2.SubnetType.PUBLIC,
        },
        {
          cidrMask: 24,
          name: 'Private',
          subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
        },
        {
          cidrMask: 24,
          name: 'Isolated',
          subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
        },
      ],
      
      // VPC Flow Logs
      flowLogs: {
        'FlowLog': {
          destination: ec2.FlowLogDestination.toCloudWatchLogs(
            new logs.LogGroup(this, 'VpcFlowLogs', {
              retention: logs.RetentionDays.ONE_MONTH,
            })
          ),
          trafficType: ec2.FlowLogTrafficType.ALL,
        },
      },
    });

    // Gateway endpoints (free, no NAT charges)
    this.vpc.addGatewayEndpoint('S3Endpoint', {
      service: ec2.GatewayVpcEndpointAwsService.S3,
    });

    this.vpc.addGatewayEndpoint('DynamoDbEndpoint', {
      service: ec2.GatewayVpcEndpointAwsService.DYNAMODB,
    });

    // Interface endpoints (for services like ECR, Secrets Manager)
    this.vpc.addInterfaceEndpoint('EcrDockerEndpoint', {
      service: ec2.InterfaceVpcEndpointAwsService.ECR_DOCKER,
    });

    this.vpc.addInterfaceEndpoint('SecretsManagerEndpoint', {
      service: ec2.InterfaceVpcEndpointAwsService.SECRETS_MANAGER,
    });
  }
}

VPC with Terraform

# Terraform: Production VPC using AWS VPC module
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 5.0"

  name = "production-vpc"
  cidr = "10.0.0.0/16"

  azs             = ["us-east-1a", "us-east-1b", "us-east-1c"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
  database_subnets = ["10.0.201.0/24", "10.0.202.0/24", "10.0.203.0/24"]

  # NAT Gateway - one per AZ
  enable_nat_gateway     = true
  single_nat_gateway     = false
  one_nat_gateway_per_az = true

  # DNS settings
  enable_dns_hostnames = true
  enable_dns_support   = true

  # VPC Flow Logs
  enable_flow_log                      = true
  create_flow_log_cloudwatch_log_group = true
  create_flow_log_cloudwatch_iam_role  = true
  flow_log_max_aggregation_interval    = 60

  # Tags for EKS if needed
  public_subnet_tags = {
    "kubernetes.io/role/elb" = 1
  }

  private_subnet_tags = {
    "kubernetes.io/role/internal-elb" = 1
  }
}

# VPC Endpoints
module "vpc_endpoints" {
  source  = "terraform-aws-modules/vpc/aws//modules/vpc-endpoints"
  version = "~> 5.0"

  vpc_id = module.vpc.vpc_id

  endpoints = {
    s3 = {
      service         = "s3"
      service_type    = "Gateway"
      route_table_ids = module.vpc.private_route_table_ids
    }
    dynamodb = {
      service         = "dynamodb"
      service_type    = "Gateway"
      route_table_ids = module.vpc.private_route_table_ids
    }
  }
}
⚠️
VPC LIMITS & COSTS
  • 5 VPCs per region (soft limit, can increase)
  • 200 subnets per VPC
  • NAT Gateway: ~$32/month + $0.045/GB processed
  • Interface Endpoint: ~$7.30/month + $0.01/GB
  • VPC Peering: Free within region, $0.01/GB cross-region

Amazon Route 53

Route 53 is AWS’s highly available DNS service. It offers domain registration, DNS routing, and health checking with 100% availability SLA.

Route 53 Routing Policies

Policy Use Case How It Works
Simple Single resource Returns one or all values randomly
Weighted Blue/green, A/B testing Route % of traffic to each endpoint
Latency Multi-region apps Route to lowest latency region
Failover Active-passive DR Route to secondary if primary fails
Geolocation Content localization Route based on user location
Multivalue Simple load balancing Return multiple healthy IPs
# Terraform: Route 53 with health checks and failover
resource "aws_route53_zone" "main" {
  name = "example.com"
}

# Health check for primary
resource "aws_route53_health_check" "primary" {
  fqdn              = "primary.example.com"
  port              = 443
  type              = "HTTPS"
  resource_path     = "/health"
  failure_threshold = 3
  request_interval  = 30

  tags = {
    Name = "primary-health-check"
  }
}

# Primary record with failover
resource "aws_route53_record" "primary" {
  zone_id = aws_route53_zone.main.zone_id
  name    = "app.example.com"
  type    = "A"

  alias {
    name                   = aws_lb.primary.dns_name
    zone_id                = aws_lb.primary.zone_id
    evaluate_target_health = true
  }

  failover_routing_policy {
    type = "PRIMARY"
  }

  set_identifier  = "primary"
  health_check_id = aws_route53_health_check.primary.id
}

# Secondary (failover) record
resource "aws_route53_record" "secondary" {
  zone_id = aws_route53_zone.main.zone_id
  name    = "app.example.com"
  type    = "A"

  alias {
    name                   = aws_lb.secondary.dns_name
    zone_id                = aws_lb.secondary.zone_id
    evaluate_target_health = true
  }

  failover_routing_policy {
    type = "SECONDARY"
  }

  set_identifier = "secondary"
}

Amazon CloudFront

CloudFront is AWS’s global CDN with 600+ edge locations. It accelerates static and dynamic content, provides DDoS protection, and reduces origin load.

AWS CloudFront CDN Architecture
Figure 3: CloudFront CDN with Edge Locations and Origins

CloudFront with AWS CDK

// AWS CDK: CloudFront distribution with S3 origin
import * as cdk from 'aws-cdk-lib';
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
import * as origins from 'aws-cdk-lib/aws-cloudfront-origins';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as acm from 'aws-cdk-lib/aws-certificatemanager';

export class CloudFrontStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // S3 bucket for static content
    const bucket = new s3.Bucket(this, 'WebsiteBucket', {
      blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
      encryption: s3.BucketEncryption.S3_MANAGED,
    });

    // CloudFront OAC (Origin Access Control)
    const oac = new cloudfront.S3OriginAccessControl(this, 'OAC', {
      signing: cloudfront.Signing.SIGV4_ALWAYS,
    });

    // Distribution
    const distribution = new cloudfront.Distribution(this, 'Distribution', {
      defaultBehavior: {
        origin: origins.S3BucketOrigin.withOriginAccessControl(bucket, {
          originAccessControl: oac,
        }),
        viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
        cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED,
        compress: true,
      },
      
      // Custom domain (optional)
      // domainNames: ['cdn.example.com'],
      // certificate: acm.Certificate.fromCertificateArn(this, 'Cert', certArn),
      
      defaultRootObject: 'index.html',
      
      // Price class (use all edge locations or subset)
      priceClass: cloudfront.PriceClass.PRICE_CLASS_100,
      
      // Error responses
      errorResponses: [
        {
          httpStatus: 404,
          responseHttpStatus: 200,
          responsePagePath: '/index.html',  // SPA routing
          ttl: cdk.Duration.minutes(5),
        },
      ],
      
      // Origin Shield for cache efficiency
      enableLogging: true,
    });

    // API behavior (for dynamic content)
    distribution.addBehavior('/api/*', new origins.HttpOrigin('api.example.com'), {
      viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.HTTPS_ONLY,
      cachePolicy: cloudfront.CachePolicy.CACHING_DISABLED,
      originRequestPolicy: cloudfront.OriginRequestPolicy.ALL_VIEWER,
      allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL,
    });
  }
}

Load Balancing: ALB vs NLB

Feature ALB (Application) NLB (Network)
Layer Layer 7 (HTTP/HTTPS) Layer 4 (TCP/UDP)
Latency ~400ms added ~100μs added
Static IP No (use Global Accelerator) Yes (Elastic IP support)
Path routing ✅ Yes ❌ No
Host routing ✅ Yes ❌ No
WebSocket ✅ Yes ✅ Yes
Best For Web apps, microservices IoT, gaming, real-time

Key Takeaways

  • Design VPCs for HA – Use 3 AZs, NAT Gateway per AZ, VPC endpoints
  • Use private subnets – Only ALBs and NAT Gateways in public subnets
  • Enable Flow Logs – Essential for security and troubleshooting
  • CloudFront for everything – Even dynamic APIs benefit from edge caching
  • ALB for HTTP, NLB for TCP – Choose based on protocol requirements
  • Use Route 53 health checks – Automatic failover for DR

Conclusion

AWS networking provides the foundation for secure, scalable applications. VPCs isolate your resources, Route 53 provides reliable DNS, CloudFront accelerates content globally, and load balancers distribute traffic. In Part 5, we’ll explore AWS security services including KMS, WAF, and Shield.

References


Discover more from C4: Container, Code, Cloud & Context

Subscribe to get the latest posts sent to your email.

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.