Home β€Ί AWS Resources β€Ί Amazon VPC

Amazon VPC

VPC architecture on AWS: subnets, NAT vs VPC endpoints, security groups, and network design for production workloads.

What Is a VPC?

A VPC (Virtual Private Cloud) is your isolated network on AWS. Every resource that needs a network interface (EC2 instances, RDS databases, Lambda functions (when VPC-attached), ECS tasks, ElastiCache clusters) lives in a VPC.

You control the IP address range, subnet layout, routing tables, internet access, and network access controls. It's the foundation of your AWS security posture.

Subnet Architecture

The standard production pattern uses three subnet tiers:

Public subnets

  • Have a route to an Internet Gateway
  • Resources get public IP addresses
  • Use for: ALBs, NAT Gateways, bastion hosts (if you still use them)

Private subnets (with egress)

  • No direct inbound from the internet
  • Outbound internet access via NAT Gateway or VPC endpoints
  • Use for: Application servers (ECS, Lambda), worker processes

Isolated subnets (no egress)

  • No route to the internet at all
  • Can only communicate with other resources in the VPC (or via VPC endpoints)
  • Use for: Databases, caches, internal services that should never reach the internet

Multi-AZ layout

Deploy subnets across at least 2 Availability Zones for high availability:

VPC: 10.0.0.0/16

Public:   10.0.0.0/24 (AZ-a)  |  10.0.1.0/24 (AZ-b)  |  10.0.2.0/24 (AZ-c)
Private:  10.0.10.0/24 (AZ-a) |  10.0.11.0/24 (AZ-b)  |  10.0.12.0/24 (AZ-c)
Isolated: 10.0.20.0/24 (AZ-a) |  10.0.21.0/24 (AZ-b)  |  10.0.22.0/24 (AZ-c)

NAT Gateway vs VPC Endpoints

This is the most common cost and security decision in VPC design.

NAT Gateway

Allows private subnet resources to reach the internet (for calling external APIs, downloading packages, etc.):

  • $0.045/hour (~$32/month per AZ) + $0.045/GB processed
  • Required for any internet-bound traffic from private subnets
  • Single point of egress. All traffic goes through it

VPC Endpoints (Gateway and Interface)

Connect directly to AWS services without going through the internet:

  • Gateway endpoints (S3, DynamoDB): Free. No reason not to use them.
  • Interface endpoints (most other services): $0.01/hour (~$7.20/month per AZ) + $0.01/GB processed

The cost trap

A NAT Gateway processing 1TB/month of traffic to S3 costs ~$45 in data processing fees alone. Plus the hourly charge. A free S3 gateway endpoint handles the same traffic at zero cost.

The security argument

VPC endpoints keep traffic on the AWS backbone. It never traverses the public internet. For regulated workloads (healthcare, finance), this matters for compliance.

Recommended approach: Use VPC endpoints for all AWS services your workloads access frequently (S3, DynamoDB, SQS, SNS, CloudWatch, ECR, etc.). Only deploy a NAT Gateway if you genuinely need to reach external (non-AWS) endpoints.

Security Groups vs NACLs

Security groups (stateful)

  • Attached to individual resources (ENIs)
  • Allow rules only (no explicit deny)
  • Stateful: if you allow inbound, the response is automatically allowed outbound
  • Can reference other security groups (e.g., "allow traffic from the ALB security group")

Network ACLs (stateless)

  • Applied at the subnet level
  • Allow and deny rules
  • Stateless: you need explicit rules for both request and response
  • Processed in rule-number order

In practice: Security groups do 95% of the work. NACLs are useful for subnet-level deny rules (block a known bad IP range) but most teams leave them at the default allow-all and rely on security groups.

Security group design

Reference security groups by ID rather than IP addresses:

ALB SG:       Allow inbound 443 from 0.0.0.0/0
App SG:       Allow inbound 8080 from ALB SG
Database SG:  Allow inbound 5432 from App SG
Cache SG:     Allow inbound 6379 from App SG

This way, when you add or remove app instances, the rules don't change. The security group membership handles it.

VPC Flow Logs

Capture metadata about network traffic for debugging and security monitoring:

<version> <account-id> <interface-id> <srcaddr> <dstaddr> <srcport> <dstport> <protocol> <packets> <bytes> <start> <end> <action> <log-status>

Send to CloudWatch Logs or S3. Use for:

  • Debugging connectivity issues ("why can't my Lambda reach the database?")
  • Security analysis (unexpected traffic patterns)
  • Compliance auditing

Common Patterns

Hub-and-spoke with Transit Gateway

Central "hub" VPC (shared services, DNS, inspection) connected to "spoke" VPCs (workloads) via Transit Gateway. Scales to hundreds of VPCs.

VPC Peering

Direct connection between two VPCs. Simple, no additional hop. Good for 2-3 VPCs. Doesn't scale well because peering isn't transitive.

PrivateLink (VPC Endpoint Services)

Expose a service from one VPC to another without peering. The consumer creates an interface endpoint; traffic stays on AWS backbone. Good for SaaS products or shared microservices.

CDK Example

import { Vpc, SubnetType, SecurityGroup, Port, GatewayVpcEndpoint, 
         GatewayVpcEndpointAwsService, InterfaceVpcEndpoint,
         InterfaceVpcEndpointAwsService } from 'aws-cdk-lib/aws-ec2';

const vpc = new Vpc(this, 'AppVpc', {
  maxAzs: 3,
  natGateways: 1, // or 0 if using only VPC endpoints
  subnetConfiguration: [
    { name: 'public', subnetType: SubnetType.PUBLIC, cidrMask: 24 },
    { name: 'private', subnetType: SubnetType.PRIVATE_WITH_EGRESS, cidrMask: 24 },
    { name: 'isolated', subnetType: SubnetType.PRIVATE_ISOLATED, cidrMask: 24 },
  ],
});

// Free gateway endpoints
vpc.addGatewayEndpoint('S3Endpoint', {
  service: GatewayVpcEndpointAwsService.S3,
});
vpc.addGatewayEndpoint('DynamoEndpoint', {
  service: GatewayVpcEndpointAwsService.DYNAMODB,
});

// Interface endpoints for common services
vpc.addInterfaceEndpoint('SqsEndpoint', {
  service: InterfaceVpcEndpointAwsService.SQS,
});
vpc.addInterfaceEndpoint('SecretsEndpoint', {
  service: InterfaceVpcEndpointAwsService.SECRETS_MANAGER,
});

Cost Considerations

Component Cost
VPC itself Free
Subnets, route tables, security groups Free
NAT Gateway $0.045/hour + $0.045/GB
Interface VPC Endpoint $0.01/hour/AZ + $0.01/GB
Gateway VPC Endpoint (S3, DynamoDB) Free
VPC Peering Free (data transfer charges apply)
Transit Gateway $0.05/hour + $0.02/GB

The biggest surprise for most teams: NAT Gateway costs. A multi-AZ deployment with moderate traffic can easily cost $200-500/month in NAT charges alone.

Further Reading

Looking for hands-on help? View my AWS architecture services β†’

Designing your network architecture?

Drop me a message β€” I typically respond within one business day.