A production-grade, multi-region SaaS infrastructure deployed across AWS US-East-1 and EU-West-1 using Terraform, featuring high availability, disaster recovery, and comprehensive observability.
- Overview
- Architecture
- Features
- Tech Stack
- Prerequisites
- Project Structure
- Getting Started
- Module Documentation
- Deployment Guide
- Security
- Monitoring & Observability
- Disaster Recovery
- Cost Optimization
- Troubleshooting
- Contributing
- License
This repository contains enterprise-grade Infrastructure as Code (IaC) for deploying a highly available, multi-region SaaS platform on AWS. The infrastructure is designed with production best practices including:
- Multi-Region Architecture: Primary region (US-East-1) with active-active failover to secondary region (EU-West-1)
- Zero Trust Security: Comprehensive security controls including KMS encryption, AWS Config, GuardDuty, and Security Hub
- Global Data Replication: Aurora Global Database, DynamoDB Global Tables, and S3 Cross-Region Replication
- Edge Delivery: CloudFront CDN with WAF protection and AWS Global Accelerator for optimal performance
- Service Mesh: AWS App Mesh for microservices communication and observability
- CI/CD Pipeline: Automated Blue/Green deployments using AWS CodePipeline and CodeDeploy
- Comprehensive Monitoring: CloudWatch, X-Ray, OpenSearch, Prometheus, and Grafana integration
The infrastructure is deployed across two AWS regions for high availability and disaster recovery:
- β Multi-AZ VPC with public, private (app), and data subnets
- β ECS Fargate clusters for containerized workloads
- β Aurora PostgreSQL Global Database (writer instance)
- β DynamoDB Global Tables
- β Kinesis Data Streams and Firehose
- β Application Load Balancer with Blue/Green deployment capability
- β Identical VPC architecture (different CIDR: 10.1.0.0/16)
- β ECS Fargate clusters (read replicas)
- β Aurora PostgreSQL Global Database (reader instance)
- β DynamoDB Global Tables replica
- β S3 Data Lake with cross-region replication
- π CloudFront Distribution with origin failover
- π AWS Global Accelerator for TCP/UDP traffic
- π Route 53 with health checks
- π WAF v2 Web ACL
- π Multi-region KMS encryption
- Encryption at Rest: Multi-region KMS keys with automatic rotation
- Encryption in Transit: TLS 1.2+ enforced across all services
- Network Isolation: Private subnets for application and data tiers
- VPC Endpoints: Interface and Gateway endpoints to avoid internet egress
- AWS Config: Continuous compliance monitoring
- GuardDuty: Intelligent threat detection
- Security Hub: Centralized security findings aggregation
- Secrets Management: AWS Secrets Manager with cross-region replication
- Multi-AZ Deployment: All stateful services deployed across 2+ AZs
- Auto-Scaling: CPU/Memory-based scaling for ECS services
- Global Database: Aurora Global Database with <1s RPO and <1m RTO
- CDN Failover: Automatic CloudFront origin group failover
- Health Checks: ALB, Route 53, and application-level health monitoring
- Blue/Green Deployments: Zero-downtime deployments via CodeDeploy
- Centralized Logging: CloudWatch Logs with retention policies
- Distributed Tracing: AWS X-Ray integration in all services
- Metrics & Dashboards: Amazon Managed Prometheus and Grafana
- Log Analytics: OpenSearch for log search and analysis
- Application Insights: ECS Container Insights enabled
- Custom Alarms: SNS-based alerting for critical metrics
- Stream Processing: Kinesis Data Streams for real-time ingestion
- ETL: Kinesis Firehose with Lambda transformations
- Data Lake: Versioned S3 buckets with lifecycle policies
- Event-Driven: EventBridge for decoupled event processing
- Queue Management: SQS with Dead Letter Queues
- Infrastructure as Code: 100% Terraform, modular design
- CI/CD Pipeline: Multi-region CodePipeline with parallel deployments
- Container Registry: ECR with image scanning enabled
- Service Mesh: AWS App Mesh for traffic management
- GitOps Ready: Structured for GitOps workflows
- IaC: Terraform 1.6+
- Cloud Provider: AWS (Multi-Region)
- Networking: VPC, Transit Gateway, PrivateLink
- Container Orchestration: ECS Fargate
- Application Runtime: Docker containers on ECS
- Serverless: Lambda functions for event processing
- Service Mesh: AWS App Mesh with Envoy proxy
- Load Balancing: Application Load Balancer (ALB)
- Relational Database: Aurora PostgreSQL (Global)
- NoSQL Database: DynamoDB (Global Tables)
- Object Storage: S3 with Cross-Region Replication
- Streaming: Kinesis Data Streams & Firehose
- Caching: ElastiCache (optional, can be added)
- Encryption: AWS KMS (Multi-Region Keys)
- Secrets: AWS Secrets Manager
- Threat Detection: GuardDuty, Security Hub
- Compliance: AWS Config, CloudTrail
- Logging: CloudWatch Logs, OpenSearch
- Metrics: CloudWatch, Prometheus (AMP)
- Tracing: AWS X-Ray
- Visualization: Grafana (AMG)
- Alerting: SNS, CloudWatch Alarms
- CDN: CloudFront with origin failover
- Acceleration: AWS Global Accelerator
- DNS: Route 53 with health-based routing
- Security: WAF v2 with managed rules
Before deploying this infrastructure, ensure you have:
# Terraform
terraform >= 1.6.0
# AWS CLI
aws-cli >= 2.x
# Git
git >= 2.x- β AWS Account with appropriate permissions
- β Programmatic access (Access Key ID and Secret Access Key)
- β
Permissions to create resources in
us-east-1andeu-west-1 - β Service quotas verified (VPCs, EIPs, NAT Gateways, etc.)
-
S3 Backend Bucket: Create before running Terraform
aws s3 mb s3://acme-terraform-state-prod-1 --region us-east-1 aws s3api put-bucket-versioning \ --bucket acme-terraform-state-prod-1 \ --versioning-configuration Status=Enabled
-
DynamoDB Lock Table: For state locking
aws dynamodb create-table \ --table-name acme-terraform-locks-prod-1 \ --attribute-definitions AttributeName=LockID,AttributeType=S \ --key-schema AttributeName=LockID,KeyType=HASH \ --billing-mode PAY_PER_REQUEST \ --region us-east-1
-
Container Images: Build and push to ECR
# Authenticate to ECR aws ecr get-login-password --region us-east-1 | \ docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-east-1.amazonaws.com # Build and push your application image docker build -t saas-api:latest . docker tag saas-api:latest 123456789012.dkr.ecr.us-east-1.amazonaws.com/saas-api:latest docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/saas-api:latest
.
βββ backend.tf # S3 backend configuration
βββ providers.tf # AWS provider configuration (multi-region)
βββ live/
β βββ prod/
β βββ global.tf # Global resources (Edge, Security Baseline)
β βββ providers.tf # Environment-specific providers
β βββ us-east-1/
β β βββ main.tf # US primary region resources
β β βββ networking/
β β βββ main.tf # VPC, subnets for US
β β βββ outputs.tf
β βββ eu-west-1/
β βββ main.tf # EU secondary region resources
β βββ networking/
β βββ main.tf # VPC, subnets for EU
β βββ outputs.tf
β
βββ modules/
βββ networking/ # VPC, Subnets, NAT, IGW, VPC Endpoints
βββ compute/ # ECS Fargate, ALB, Auto-scaling
βββ database/ # Aurora PostgreSQL (Regional)
βββ database-global/ # Aurora Global Database
βββ dynamodb-global/ # DynamoDB Global Tables
βββ app-mesh/ # AWS App Mesh configuration
βββ security-baseline/ # KMS, GuardDuty, Security Hub, Config
βββ edge/ # CloudFront, WAF, Global Accelerator, Route53
βββ observability/ # CloudWatch, X-Ray, OpenSearch, Prometheus, Grafana
βββ data-pipeline/ # Kinesis, Firehose, Lambda, S3 Data Lake
βββ cicd/ # CodePipeline, CodeBuild, CodeDeploy
| Module | Purpose | Key Resources |
|---|---|---|
| networking | Network foundation | VPC, Subnets, NAT Gateway, Internet Gateway, VPC Endpoints |
| compute | Application runtime | ECS Cluster, Fargate Tasks, ALB, Target Groups, Auto-scaling |
| database | Regional database | Aurora PostgreSQL Cluster, Instances, Security Groups |
| database-global | Global database | Aurora Global Cluster, Multi-region replication |
| dynamodb-global | NoSQL global tables | DynamoDB with global replication |
| app-mesh | Service mesh | App Mesh, Virtual Nodes, Cloud Map |
| security-baseline | Security foundation | Multi-region KMS, GuardDuty, Security Hub, AWS Config |
| edge | Edge delivery | CloudFront, WAF, Global Accelerator, Route 53 |
| observability | Monitoring stack | CloudWatch, X-Ray, OpenSearch, Prometheus, Grafana |
| data-pipeline | Data processing | Kinesis Streams, Firehose, Lambda, S3, EventBridge, SQS |
| cicd | Deployment pipeline | CodePipeline, CodeBuild, CodeDeploy |
git clone https://github.com/rohandeb2/terraform-aws-multi-region-saas-platform.git
cd terraform-aws-multi-region-saas-platform# Configure AWS CLI
aws configure
# Or export environment variables
export AWS_ACCESS_KEY_ID="your-access-key"
export AWS_SECRET_ACCESS_KEY="your-secret-key"
export AWS_DEFAULT_REGION="us-east-1"Create terraform.tfvars (this file is gitignored for security):
# Update these values for your environment
name_prefix = "acme-prod"
domain_name = "yourdomain.com"
alert_email = "alerts@yourdomain.com"
container_image = "123456789012.dkr.ecr.us-east-1.amazonaws.com/saas-api:latest"
# Database credentials (use Secrets Manager in production)
db_username = "admin_user"
# db_password will be auto-generated by Terraformterraform initterraform plan -out=tfplanterraform apply tfplan# Check ECS services
aws ecs list-services --cluster acme-prod-use1-cluster --region us-east-1
# Check ALB health
aws elbv2 describe-target-health \
--target-group-arn <target-group-arn> \
--region us-east-1
# Test application endpoint
curl https://www.yourdomain.com/healthLocation: modules/networking/
Creates a production-grade VPC with the following:
- 3-tier subnet architecture: Public, Private (App), Private (Data)
- Multi-AZ: Resources spread across 2 availability zones
- NAT Gateway: High availability with one NAT GW per AZ
- VPC Endpoints: S3, DynamoDB (Gateway), ECR, Secrets Manager, CloudWatch (Interface)
Inputs:
vpc_cidr: CIDR block for VPC (e.g., "10.0.0.0/16")name_prefix: Naming prefix for resourcesendpoint_sg_id: Security group for VPC interface endpoints
Outputs:
vpc_id,public_subnet_ids,app_subnet_ids,data_subnet_ids
Location: modules/compute/
Deploys containerized applications on ECS Fargate:
- ECS Cluster: With Container Insights enabled
- Fargate Tasks: Including app container, X-Ray daemon, and Envoy sidecar
- Application Load Balancer: With Blue/Green target groups
- Auto-scaling: Based on CPU/Memory utilization
- Service Mesh Integration: App Mesh virtual node configuration
Inputs:
container_image: ECR image URIvpc_id,public_subnet_ids,app_subnet_idsapp_mesh_node_arn: ARN of the App Mesh virtual nodemin_capacity,max_capacity: Auto-scaling bounds
Outputs:
alb_dns_name,ecs_cluster_name,ecs_service_nameblue_target_group_name,green_target_group_nameservice_sg_id: Security group for ECS tasks
Location: modules/database/
Deploys Aurora PostgreSQL cluster:
- Aurora Cluster: PostgreSQL 15.4 engine
- Multi-AZ: 2 instances (1 writer, 1 reader)
- Encryption: KMS encryption at rest
- Backups: 7-day retention with point-in-time recovery
- Performance Insights: Enabled for query analysis
- Secrets Manager: Auto-generated credentials
Inputs:
vpc_id,data_subnet_idskms_key_arn,app_security_group_idglobal_cluster_identifier: For joining global cluster (optional)
Outputs:
cluster_endpoint,reader_endpoint,secrets_manager_arn
Location: modules/database-global/
Creates Aurora Global Database spanning multiple regions:
- Global Cluster: Shell resource for global replication
- Primary Cluster: Writer cluster in us-east-1
- Secondary Cluster: Read replica in eu-west-1
- Cross-Region Replication: <1 second replication lag
- Disaster Recovery: Promotion capability for RTO <1 minute
Inputs:
- Region-specific subnet groups, security groups, and KMS keys
master_username,master_password
Outputs:
global_cluster_id,primary_endpoint,secondary_reader_endpoint
Location: modules/security-baseline/
Foundational security controls:
- Multi-Region KMS: Primary key in us-east-1 with replica in eu-west-1
- GuardDuty: Enabled in both regions
- Security Hub: With findings aggregation to primary region
- AWS Config: Continuous compliance recording
- IAM Roles: Least-privilege auditor role
Inputs:
name_prefix,config_bucket_name,security_alerts_email
Outputs:
kms_primary_key_arn,kms_replica_key_arnguardduty_primary_id,security_hub_aggregator_arn
Location: modules/edge/
Global edge delivery infrastructure:
- CloudFront: Distribution with origin failover group
- WAF v2: Web ACL with managed rule sets
- Global Accelerator: For TCP traffic acceleration
- Route 53: Health-checked DNS records
- ACM Certificate: SSL/TLS for custom domain
Inputs:
us_alb_dns_name,eu_alb_dns_name(ALB endpoints)us_alb_arn,eu_alb_arn(for Global Accelerator)domain_name: Primary domain
Outputs:
- CloudFront distribution domain name
- Global Accelerator DNS name
Location: modules/observability/
Comprehensive monitoring and observability:
- CloudWatch Logs: Centralized log aggregation
- X-Ray: Distributed tracing with sampling rules
- OpenSearch: Log search and analytics (2-node cluster)
- Prometheus (AMP): Metrics collection workspace
- Grafana (AMG): Visualization and dashboards
- SNS Alerts: Email notifications for critical events
Inputs:
name_prefix,kms_key_arn,alert_email
Outputs:
prometheus_endpoint,grafana_endpoint,opensearch_endpoint
Location: modules/data-pipeline/
Event-driven data pipeline:
- Kinesis Data Streams: Real-time data ingestion
- Kinesis Firehose: Delivery to S3 with Lambda transformation
- EventBridge: Custom event bus
- SQS: Queue with Dead Letter Queue
- S3 Data Lake: Versioned, encrypted, with cross-region replication
- Lambda: Event processing functions
Inputs:
kms_key_arn,destination_bucket_arn,destination_kms_key_arnkinesis_shards: Number of Kinesis shards
Outputs:
event_bus_arn,kinesis_stream_name,data_lake_bucket_id
Location: modules/cicd/
Automated deployment pipeline:
- CodePipeline: Multi-stage pipeline with parallel regional deployments
- CodeBuild: Docker image builds with ECR push
- CodeDeploy: Blue/Green ECS deployments
- Cross-Account: Support for separate CI/CD account
- Artifact Replication: Dual-region artifact buckets
Inputs:
- Repository info, ECS cluster/service names
- ALB listener ARN, target group names
- Cross-account role ARNs
Outputs:
pipeline_arn,codebuild_project_name
Deploy foundational networking and security:
# Deploy security baseline first (KMS, GuardDuty, etc.)
cd live/prod
terraform apply -target=module.security_baseline
# Deploy VPC and networking in both regions
terraform apply -target=module.vpc_us_east_1
terraform apply -target=module.vpc_eu_west_1Deploy databases and storage:
# Deploy regional Aurora clusters
terraform apply -target=module.aurora
# Deploy DynamoDB global tables
terraform apply -target=module.dynamodb_global
# Deploy data pipeline
terraform apply -target=module.data_pipelineDeploy application runtime:
# Deploy ECS clusters and App Mesh
terraform apply -target=module.ecs_fargate
terraform apply -target=module.app_meshDeploy CDN and global routing:
# Deploy CloudFront, WAF, and Global Accelerator
terraform apply -target=module.edge_stackDeploy monitoring stack:
# Deploy observability infrastructure
terraform apply -target=module.observabilityDeploy automation:
# Deploy CodePipeline and CodeDeploy
terraform apply -target=module.cicdApply complete infrastructure:
# Review the full plan
terraform plan
# Apply everything
terraform apply- At Rest: All data encrypted using AWS KMS with multi-region keys
- In Transit: TLS 1.2+ enforced on all connections
- Secrets: AWS Secrets Manager with automatic rotation
- Private Subnets: Application and data tiers isolated from internet
- Security Groups: Least-privilege access rules
- NACLs: Additional network layer protection (can be added)
- VPC Endpoints: Eliminates internet gateway for AWS services
- IAM Roles: Service-specific roles with minimal permissions
- No Hardcoded Credentials: All secrets in Secrets Manager
- Auditing: CloudTrail enabled in all regions
- AWS Config: Continuous compliance monitoring
- GuardDuty: ML-based threat detection
- Security Hub: Aggregated security findings
- Automated Alerts: SNS notifications for security events
β
Deletion protection on production databases
β
MFA delete on S3 buckets (can be enabled)
β
Versioning on critical S3 buckets
β
KMS key rotation enabled
β
VPC Flow Logs (can be added)
β
S3 bucket public access blocked
β
Encrypted EBS volumes
β
RDS automated backups
Pre-configured dashboards for:
- ECS service health and performance
- ALB request metrics
- Aurora database performance
- Lambda function execution
- API Gateway metrics (if added)
Distributed tracing enabled for:
- ECS tasks (with X-Ray daemon sidecar)
- Lambda functions
- API calls between services
Available in Amazon Managed Prometheus:
- Container metrics
- Custom application metrics
- Infrastructure metrics
Managed Grafana workspace with:
- CloudWatch data source
- Prometheus data source
- X-Ray data source
- Pre-built dashboards for AWS services
- CloudWatch Logs: Real-time log streaming
- OpenSearch: Log search and analysis with Kibana
- Retention: 30-day retention on application logs
SNS topics configured for:
- High CPU/Memory utilization
- Database connection pool exhaustion
- ALB 5xx error rate spikes
- GuardDuty findings
- Security Hub critical findings
- Recovery Time Objective (RTO): < 5 minutes
- Recovery Point Objective (RPO): < 1 second
Aurora Global Database automatic failover:
# Promote EU cluster to primary (in case of us-east-1 failure)
aws rds failover-global-cluster \
--global-cluster-identifier acme-prod-global-db \
--target-db-cluster-identifier acme-prod-euw1-aurora-cluster \
--region eu-west-1CloudFront automatically routes to healthy origin:
- Primary origin health check fails β traffic routed to EU
- Recovery is automatic, no manual intervention required
Route 53 health checks monitor ALB endpoints:
- Unhealthy endpoint β Route 53 removes from DNS pool
- Automatic recovery when health is restored
- RDS: Automated daily backups (7-day retention)
- DynamoDB: Point-in-time recovery enabled
- S3: Versioning enabled on all buckets
- ECS: Task definitions versioned
- Terraform State: S3 versioning + DynamoDB locking
# Simulate region failure
# 1. Stop ECS tasks in us-east-1
aws ecs update-service \
--cluster acme-prod-use1-cluster \
--service acme-prod-use1-api-service \
--desired-count 0 \
--region us-east-1
# 2. Verify CloudFront routes to EU
curl -I https://www.yourdomain.com
# 3. Restore service
aws ecs update-service \
--cluster acme-prod-use1-cluster \
--service acme-prod-use1-api-service \
--desired-count 2 \
--region us-east-1| Service | Estimated Cost (USD) |
|---|---|
| ECS Fargate (2 regions) | $150 - $300 |
| Aurora Global Database | $400 - $600 |
| DynamoDB (on-demand) | $50 - $200 |
| ALB (2 regions) | $40 - $60 |
| NAT Gateway (4 total) | $180 - $200 |
| S3 + Replication | $50 - $150 |
| CloudFront + WAF | $100 - $300 |
| OpenSearch | $100 - $200 |
| Prometheus + Grafana | $50 - $100 |
| Total (approx) | $1,120 - $2,110/mo |
Note: Costs vary based on traffic, data transfer, and usage patterns
-
Right-Sizing
- Use Fargate Spot for non-critical workloads
- Aurora Serverless v2 for variable workloads
- Reserved Instances for predictable workloads
-
Network Costs
- Use VPC endpoints to avoid NAT Gateway charges
- Optimize cross-region data transfer
- Enable S3 Transfer Acceleration only when needed
-
Storage Optimization
- S3 Intelligent-Tiering for data lake
- Lifecycle policies to move old data to Glacier
- Clean up old EBS snapshots
-
Monitoring Costs
- Adjust CloudWatch log retention
- Use Prometheus for custom metrics (cheaper than CloudWatch custom metrics)
- Sample X-Ray traces (5% sampling configured)
-
Development/Staging Environments
- Use Terraform workspaces for lower environments
- Reduce instance counts in dev/staging
- Shut down non-prod environments after hours
Problem: Error acquiring the state lock
Solution:
# Identify the lock
aws dynamodb get-item \
--table-name acme-terraform-locks-prod-1 \
--key '{"LockID": {"S": "acme-terraform-state-prod-1/prod/multi-region-platform/terraform.tfstate-md5"}}'
# Force unlock (use with caution)
terraform force-unlock <LOCK_ID>Problem: Tasks fail to start or immediately crash
Solution:
# Check task logs
aws logs tail /ecs/acme-prod-use1-app --follow --region us-east-1
# Describe stopped tasks
aws ecs describe-tasks \
--cluster acme-prod-use1-cluster \
--tasks <task-id> \
--region us-east-1Common causes:
- Container image not found in ECR
- Insufficient IAM permissions
- Resource limits (CPU/memory)
- Health check failures
Problem: Replication lag > 1 second
Solution:
# Check replication lag
aws rds describe-db-clusters \
--db-cluster-identifier acme-prod-euw1-aurora-cluster \
--region eu-west-1 \
--query 'DBClusters[0].GlobalWriteForwardingStatus'
# Check CloudWatch metrics
# Navigate to: CloudWatch > Metrics > RDS > AuroraGlobalDBReplicationLagProblem: CDN serving stale content
Solution:
# Create invalidation
aws cloudfront create-invalidation \
--distribution-id <distribution-id> \
--paths "/*"Problem: Services can't connect to AWS APIs via VPC endpoints
Solution:
- Verify security group allows HTTPS (443) from VPC CIDR
- Check route tables include endpoint routes
- Ensure DNS is enabled on VPC
We welcome contributions! Please follow these guidelines:
- Fork the repository
- Create a feature branch
git checkout -b feature/amazing-feature
- Commit your changes
git commit -m 'Add amazing feature' - Push to your branch
git push origin feature/amazing-feature
- Open a Pull Request
- Follow Terraform best practices
- Use meaningful variable and resource names
- Add comments for complex logic
- Update documentation for new features
- Test changes in a dev environment first
- Code follows project conventions
- Documentation updated (README, module docs)
-
terraform fmtapplied -
terraform validatepasses - Tested in isolated environment
- No sensitive data committed
This project is licensed under the MIT License - see the LICENSE file for details.
Made with β€οΈ by DevOps Engineers, for DevOps Engineers
