Building Scalable AWS VPC Infrastructure with Terraform Modules for SaaS Applications

Scalable AWS VPC Infrastructure with Terraform for SaaS Apps

Building Scalable AWS VPC Infrastructure with Terraform Modules for SaaS Applications

Written by: An AWS Solutions Architect with 25+ years of experience in Java enterprise applications and cloud infrastructure design.

As a Java architect, I’ve learned that infrastructure foundation is everything. A poorly designed VPC can cost thousands, create security gaps, and limit scalability.

Today, I'll show you how to build a production-ready, cost-optimized VPC infrastructure using Terraform modules that scales from development to enterprise.


Table of Contents


Why VPC Architecture Matters for SaaS Success

After architecting multiple enterprise SaaS platforms, I've seen how infrastructure decisions made in the first month can make or break a SaaS business. Here's why VPC design is critical:

🏗️ Foundation for Multi-Tenant Architecture

Your VPC is the foundation for:

  • Tenant Isolation - Separate subnets for different customer tiers
  • Security Boundaries - Network-level protection for sensitive data
  • Compliance Requirements - SOC2, HIPAA, PCI-DSS compliance
  • Performance Optimization - Reduced latency through proper subnet placement

💰 Cost Impact on Revenue

Poor VPC design can cost you:

Poor DesignMonthly Cost ImpactRevenue Impact
Single-AZ in Production$0 savings, 99.5% uptime-$50K ARR from downtime
No Private Subnets$200 in security tools-$100K from security breach
Over-provisioned Dev$500 wasted monthly-$6K annually
No NAT Gateway optimization$300 extra monthly-$3.6K annually

The Power of Terraform Modules for Enterprise SaaS

For applications serving at scale, modularity is non-negotiable. Here's why Terraform modules are essential:

🔄 Reusability Across Environments

# Same module, different configurations
module "vpc_dev" {
  source      = "./modules/vpc"
  environment = "dev"
  # Single AZ, minimal cost
}

module "vpc_prod" {
  source      = "./modules/vpc"
  environment = "prod"
  # Multi-AZ, high availability
}

📈 Scalability Benefits

  • Consistent Architecture - Same patterns across all environments
  • Reduced Human Error - Automated, tested configurations
  • Faster Deployment - New environments in minutes, not hours
  • Version Control - Infrastructure changes tracked like code

Cost Optimization Strategy: Dev vs Production

In SaaS platforms, cost optimization in development environments can save 60-80% on infrastructure costs without impacting development velocity.

💡 Development Environment Strategy

config = {
  dev = {
    az_count        = 1          # Single AZ
    create_private  = false      # Public subnets only
    nat_gateway     = false      # No NAT Gateway
    instance_types  = ["t3.micro", "t3.small"]
  }
}

Cost Savings:

  • NAT Gateway: $45/month saved
  • Additional AZ: $20/month saved
  • Smaller instances: $50/month saved
  • Total Dev Savings: $115/month per environment

🏢 Production Environment Strategy

config = {
  prod = {
    az_count        = 2          # Multi-AZ for HA
    create_private  = true       # Private subnets for security
    nat_gateway     = true       # Secure internet access
    instance_types  = ["m5.large", "m5.xlarge"]
  }
}

Business Value:

  • 99.99% uptime SLA capability
  • Enterprise security compliance
  • Auto-scaling for traffic spikes
  • Disaster recovery ready

Step-by-Step Implementation

🏗️ VPC Module Architecture

Here's the production-ready VPC module approach for SaaS applications:

# modules/vpc/main.tf
locals {
  config = {
    dev = {
      az_count        = 1
      create_private  = false
      nat_gateway     = false
    }
    prod = {
      az_count        = 2
      create_private  = true
      nat_gateway     = true
    }
  }

  env_config  = local.config[var.environment]
  selected_azs = slice(data.aws_availability_zones.available.names, 0, local.env_config.az_count)
}

resource "aws_vpc" "main" {
  cidr_block           = var.vpc_cidr
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = {
    Name        = "${var.project_name}-${var.environment}-vpc"
    Environment = var.environment
    Project     = var.project_name
  }
}

🔧 Environment-Specific Subnets

# Public Subnets (Always created)
resource "aws_subnet" "public" {
  count = local.env_config.az_count

  vpc_id                  = aws_vpc.main.id
  cidr_block              = cidrsubnet(var.vpc_cidr, 8, count.index)
  availability_zone       = local.selected_azs[count.index]
  map_public_ip_on_launch = true

  tags = {
    Name = "${var.project_name}-${var.environment}-public-${count.index + 1}"
    Type = "public"
  }
}

# Private Subnets (Production only)
resource "aws_subnet" "private" {
  count = local.env_config.create_private ? local.env_config.az_count : 0

  vpc_id            = aws_vpc.main.id
  cidr_block        = cidrsubnet(var.vpc_cidr, 8, count.index + 10)
  availability_zone = local.selected_azs[count.index]

  tags = {
    Name = "${var.project_name}-${var.environment}-private-${count.index + 1}"
    Type = "private"
  }
}

🌐 NAT Gateway for Production Security

# NAT Gateway (Production only)
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id
}

resource "aws_eip" "nat" {
  count  = local.env_config.nat_gateway ? 1 : 0
  domain = "vpc"

  tags = {
    Name = "${var.project_name}-${var.environment}-nat-eip"
  }
}

resource "aws_nat_gateway" "main" {
  count         = local.env_config.nat_gateway ? 1 : 0
  allocation_id = aws_eip.nat[0].id
  subnet_id     = aws_subnet.public[0].id
  depends_on    = [aws_internet_gateway.main]
}

📁 Directory Structure

terraform/
├── modules/vpc/
│   ├── main.tf          # VPC resources
│   ├── variables.tf     # Input variables
│   └── outputs.tf       # Output values
├── env/dev/
│   ├── main.tf          # Dev environment
│   └── variables.tf     # Dev-specific vars
├── env/prod/
│   ├── main.tf          # Prod environment
│   └── variables.tf     # Prod-specific vars
└── README.md

Security Best Practices for SaaS Applications

🔒 Network Segmentation

Recommended segmentation:

TierSubnet TypePurposeSecurity Level
Web TierPublicLoad Balancers, CDNHigh
App TierPrivateSpring Boot APIsVery High
Data TierPrivateMongoDB, RedisMaximum

🛡️ Security Group Strategy

# Example: Secure database access
resource "aws_security_group" "database" {
  name_prefix = "${var.project_name}-${var.environment}-db"
  vpc_id      = module.vpc.vpc_id

  ingress {
    from_port       = 27017
    to_port         = 27017
    protocol        = "tcp"
    security_groups = [aws_security_group.app_tier.id]  # Only from app tier
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

Monitoring and Scaling for Production SaaS

📊 VPC Flow Logs

resource "aws_flow_log" "vpc_flow_log" {
  count = var.environment == "prod" ? 1 : 0

  iam_role_arn    = aws_iam_role.flow_log[0].arn
  log_destination = aws_cloudwatch_log_group.vpc_flow_log[0].arn
  traffic_type    = "ALL"
  vpc_id          = aws_vpc.main.id
}

🚨 CloudWatch Alarms

# Monitor NAT Gateway costs
resource "aws_cloudwatch_metric_alarm" "nat_gateway_cost" {
  count = var.environment == "prod" ? 1 : 0

  alarm_name          = "nat-gateway-high-usage"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = "2"
  metric_name         = "BytesOutToDestination"
  namespace           = "AWS/NATGateway"
  period              = "300"
  statistic           = "Sum"
  threshold           = "10000000000"  # 10GB
  alarm_description   = "NAT Gateway high usage alert"
}

Revenue Impact and ROI Analysis

💰 Cost Optimization ROI

With proper VPC architecture, teams typically achieve:

MetricBefore OptimizationAfter OptimizationAnnual Savings
Dev Environment Costs$200/month$85/month$1,380
Staging Environment$300/month$120/month$2,160
Production EfficiencyManual scalingAuto-scaling$5,000
Security Incidents2 per year0 per year$25,000

Total Annual ROI: $33,540

📈 Business Growth Enablement

  • Faster Time to Market: New environments in 10 minutes vs 2 hours
  • Compliance Ready: SOC2 Type II readiness from day one
  • Enterprise Sales: Security architecture that wins enterprise deals
  • Global Expansion: Reusable modules for multi-region deployment

🚀 Deployment Commands

Development Environment

cd terraform/env/dev
terraform init
terraform plan
terraform apply
# Creates: Single-AZ VPC, public subnets only

Production Environment

cd terraform/env/prod
terraform init
terraform plan
terraform apply
# Creates: Multi-AZ VPC, public/private subnets, NAT Gateway

🎯 Key Takeaways for SaaS Architects

  1. Start with Modules: Never write infrastructure code twice.
  2. Optimize for Cost: Development environments should be ~70% cheaper than production.
  3. Security First: Private subnets and proper segmentation are non-negotiable.
  4. Plan for Scale: Your VPC should handle 10x growth without redesign.
  5. Monitor Everything: VPC Flow Logs and CloudWatch are your best friends.

🔗 What's Next?

This VPC foundation enables:

  • 🔐 Security Groups: Least-privilege network access
  • 🗄️ Database Integration: MongoDB Atlas with private connectivity
  • 🔑 Secrets Management: AWS Secrets Manager integration
  • 📊 Monitoring: CloudWatch logs and metrics
  • 🚀 CI/CD Pipeline: Automated deployments

In my next post, I'll cover "Implementing Zero-Trust Security Groups for Multi-Tenant SaaS Applications" - stay tuned!


Final Thoughts

Infrastructure is not just about servers and networks — it's about enabling your business to scale, stay secure, and deliver value to customers. The VPC architecture we've built today will serve as the foundation for a SaaS platform that can grow from startup to enterprise.

Remember: Good infrastructure is invisible to your customers but essential to your success.

--
Ganesh
AWS Solutions Architect | Java Enterprise Specialist | SaaS Infrastructure Expert
Building scalable systems for 25+ years

Comments

Popular posts from this blog

CodeForge Full-Stack Guide with AI: Spring Boot, React, AWS using ChatGPT-5, Amazon Q & GitHub Copilot