Terraform AWS RDS and ElastiCache provisioning
# RDS PostgreSQL instance
resource "aws_db_instance" "main" {
identifier = "${var.project_name}-db"
engine = "postgres"
engine_version = "16.1"
instance_class = var.db_instance_class
allocated_storage = 20
max_allocated_storage = 100
storage_type = "gp3"
storage_encrypted = true
kms_key_id = aws_kms_key.db.arn
db_name = var.db_name
username = var.db_username
password = random_password.db.result
multi_az = var.environment == "production"
db_subnet_group_name = aws_db_subnet_group.main.name
vpc_security_group_ids = [aws_security_group.db.id]
parameter_group_name = aws_db_parameter_group.main.name
backup_retention_period = 7
backup_window = "03:00-04:00"
maintenance_window = "Mon:04:00-Mon:05:00"
skip_final_snapshot = var.environment != "production"
final_snapshot_identifier = "${var.project_name}-final-snapshot"
deletion_protection = var.environment == "production"
performance_insights_enabled = true
monitoring_interval = 60
monitoring_role_arn = aws_iam_role.rds_monitoring.arn
enabled_cloudwatch_logs_exports = ["postgresql"]
tags = {
Name = "${var.project_name}-db"
}
}
resource "aws_db_subnet_group" "main" {
name = "${var.project_name}-db-subnet"
subnet_ids = var.private_subnet_ids
tags = {
Name = "${var.project_name}-db-subnet"
}
}
resource "aws_db_parameter_group" "main" {
name = "${var.project_name}-pg16"
family = "postgres16"
parameter {
name = "log_statement"
value = "all"
}
parameter {
name = "log_min_duration_statement"
value = "1000"
}
parameter {
name = "shared_preload_libraries"
value = "pg_stat_statements"
}
}
resource "random_password" "db" {
length = 32
special = false
}
resource "aws_secretsmanager_secret" "db_url" {
name = "${var.project_name}/database-url"
}
resource "aws_secretsmanager_secret_version" "db_url" {
secret_id = aws_secretsmanager_secret.db_url.id
secret_string = "postgres://${var.db_username}:${random_password.db.result}@${aws_db_instance.main.endpoint}/${var.db_name}"
}
# ElastiCache Redis
resource "aws_elasticache_replication_group" "main" {
replication_group_id = "${var.project_name}-redis"
description = "Redis cluster for ${var.project_name}"
node_type = var.redis_node_type
num_cache_clusters = var.environment == "production" ? 2 : 1
port = 6379
engine_version = "7.0"
parameter_group_name = "default.redis7"
subnet_group_name = aws_elasticache_subnet_group.main.name
security_group_ids = [aws_security_group.redis.id]
at_rest_encryption_enabled = true
transit_encryption_enabled = true
auth_token = random_password.redis.result
automatic_failover_enabled = var.environment == "production"
snapshot_retention_limit = 3
snapshot_window = "03:00-05:00"
maintenance_window = "mon:05:00-mon:06:00"
tags = {
Name = "${var.project_name}-redis"
}
}
resource "aws_elasticache_subnet_group" "main" {
name = "${var.project_name}-redis-subnet"
subnet_ids = var.private_subnet_ids
}
resource "random_password" "redis" {
length = 32
special = false
}
resource "aws_security_group" "db" {
name_prefix = "${var.project_name}-db-"
vpc_id = var.vpc_id
ingress {
from_port = 5432
to_port = 5432
protocol = "tcp"
security_groups = var.app_security_group_ids
}
lifecycle {
create_before_destroy = true
}
}
resource "aws_security_group" "redis" {
name_prefix = "${var.project_name}-redis-"
vpc_id = var.vpc_id
ingress {
from_port = 6379
to_port = 6379
protocol = "tcp"
security_groups = var.app_security_group_ids
}
lifecycle {
create_before_destroy = true
}
}
Terraform provisions managed database services declaratively. AWS RDS supports PostgreSQL, MySQL, and other engines with aws_db_instance. The engine_version pins database versions. instance_class sets compute size. allocated_storage and max_allocated_storage enable auto-scaling. multi_az provides high availability with automatic failover. Subnet groups place databases in private subnets. Parameter groups customize database settings. Security groups restrict access to application subnets only. ElastiCache provides managed Redis or Memcached with aws_elasticache_cluster or aws_elasticache_replication_group for Redis cluster mode. Automated backups, encryption at rest with KMS, and encryption in transit with TLS protect data. Always store connection strings in Secrets Manager.