Terraform¶
All AWS infrastructure is defined as code using Terraform in the infra/terraform/ directory.
Directory Structure¶
infra/terraform/
main.tf # Root module - orchestrates all child modules
variables.tf # Root input variables
outputs.tf # Root outputs
versions.tf # Provider version constraints
backend.tf # State backend configuration (S3)
backend-dev.hcl # Dev backend config
secrets.auto.tfvars # Auto-loaded secret variables (gitignored)
environments/ # Environment-specific variable files
dev.tfvars
staging.tfvars
prod.tfvars
modules/ # Reusable infrastructure modules
alb/ # Application Load Balancer + WAF
ecs/ # ECS Fargate cluster, services, ECR
elasticache/ # ElastiCache (Valkey)
iam/ # IAM roles, policies, OIDC provider
rds/ # RDS PostgreSQL
s3/ # S3 buckets with lifecycle policies
secrets/ # AWS Secrets Manager
vpc/ # VPC, subnets, NAT Gateway, route tables
scripts/ # Deployment helper scripts
Module Inventory¶
| Module | Source | Purpose |
|---|---|---|
| vpc | ./modules/vpc | VPC, 3-tier subnets, NAT Gateway, route tables |
| secrets | ./modules/secrets | Secrets Manager for DB password, API keys, JWT secrets |
| rds | ./modules/rds | PostgreSQL 16 with pgvector, automated backups |
| elasticache | ./modules/elasticache | Valkey (Redis-compatible) for caching and Celery broker |
| s3 | ./modules/s3 | Documents and media buckets with lifecycle policies |
| alb | ./modules/alb | Application Load Balancer, HTTPS, WAF |
| ecs | ./modules/ecs | Fargate cluster, API + Worker + Beat services, ECR |
| iam | ./modules/iam | Task roles, execution roles, GitHub Actions OIDC |
Module Dependencies¶
flowchart TB
VPC[vpc] --> RDS[rds]
VPC --> EC[elasticache]
VPC --> ALB[alb]
VPC --> ECS[ecs]
SEC[secrets] --> RDS
SEC --> ECS
ALB --> ECS
RDS --> ECS
EC --> ECS
S3[s3] --> ECS
ECS --> IAM[iam]
SEC --> IAM Key Variables¶
General¶
| Variable | Type | Default | Description |
|---|---|---|---|
environment | string | Required | dev, staging, or prod |
project_name | string | carbon-connect | Resource naming prefix |
aws_region | string | eu-north-1 | AWS region |
Database (RDS)¶
| Variable | Type | Default | Description |
|---|---|---|---|
db_instance_class | string | db.t4g.medium | Instance type |
db_allocated_storage | number | 50 | Storage in GB |
db_max_allocated_storage | number | 200 | Auto-scale limit |
db_multi_az | bool | false | Multi-AZ for production |
db_deletion_protection | bool | false | Deletion protection |
db_backup_retention_period | number | 7 | Backup retention days |
ECS¶
| Variable | Type | Default | Description |
|---|---|---|---|
api_cpu | number | 1024 | API container CPU units |
api_memory | number | 2048 | API container memory (MB) |
api_desired_count | number | 2 | Desired API tasks |
api_min_count | number | 1 | Min auto-scale |
api_max_count | number | 10 | Max auto-scale |
worker_cpu | number | 1024 | Worker container CPU |
worker_memory | number | 2048 | Worker container memory |
use_fargate_spot | bool | true | Use Spot for workers |
Secrets (Sensitive)¶
| Variable | Type | Description |
|---|---|---|
claude_api_key | string | Anthropic API key |
climatiq_api_key | string | Climatiq API key |
meilisearch_master_key | string | Meilisearch master key |
secret_key | string | Application session key |
jwt_secret_key | string | JWT signing key |
Secret Variables
Never commit secret values to version control. Use secrets.auto.tfvars (gitignored) or pass via environment variables.
State Backend¶
Terraform state is stored remotely in S3 with DynamoDB locking:
# backend.tf
terraform {
backend "s3" {
bucket = "carbon-connect-terraform-state"
key = "terraform.tfstate"
region = "eu-north-1"
encrypt = true
dynamodb_table = "carbon-connect-terraform-lock"
}
}
How to Use¶
Initialize¶
cd infra/terraform
# Initialize with environment-specific backend
terraform init -backend-config=backend-dev.hcl
Plan¶
# Plan with environment variables
terraform plan -var-file=environments/dev.tfvars -out=plan.out
# Review the plan
terraform show plan.out
Apply¶
# Apply the plan
terraform apply plan.out
# Or apply directly (with confirmation prompt)
terraform apply -var-file=environments/dev.tfvars
Validate¶
# Check syntax
terraform validate
# Check formatting
terraform fmt -check -recursive
# Security scan
tfsec infra/terraform/
Destroy¶
# Destroy all resources (use with extreme caution)
terraform destroy -var-file=environments/dev.tfvars
Environment-Specific Configurations¶
- Single NAT Gateway
db.t4g.mediumRDS- Valkey Serverless
- 1 API task, 1 Worker task
- No Multi-AZ
- No deletion protection
- Single NAT Gateway
db.t4g.mediumRDS- Valkey Serverless
- 2 API tasks, 2 Worker tasks
- No Multi-AZ
- Deletion protection enabled
- NAT Gateway per AZ
db.r6g.largeRDS- Valkey with read replicas
- 2-10 API tasks, 2-10 Worker tasks
- Multi-AZ enabled
- Deletion protection enabled
- WAF enabled with rate limiting
CI/CD Integration¶
Terraform operations are integrated into GitHub Actions:
- Quality Gates workflow runs
terraform validateandtfsecon every PR - Deploy Staging triggers infrastructure updates on merge to
staging - Deploy Production requires manual approval with plan review
GitHub Actions uses OIDC federation (no long-lived AWS credentials):