Files
sentryagent-idp/terraform/modules/rds/main.tf
SentryAgent.ai Developer 6913d62648 feat(phase-2): workstream 8 — Multi-Region Terraform Deployment
AWS environment:
- VPC (3-AZ, public + private subnets, NAT gateways, VPC endpoints for ECR/SM/CW)
- ECS Fargate service (sentryagent/agentidp) — secrets from Secrets Manager
- RDS PostgreSQL 14 (Multi-AZ, encrypted, VPC-internal, storage autoscaling)
- ElastiCache Redis 7 (primary + replica, at-rest + in-transit encryption)
- ALB with HTTPS/443, HTTP→HTTPS redirect, ACM certificate
- Route 53 alias record

GCP environment:
- VPC + private services access + Serverless VPC connector
- Cloud Run service — secrets from Secret Manager
- Cloud SQL PostgreSQL 14 (private IP, no public endpoint)
- Cloud Memorystore Redis 7 (VPC-internal, AUTH enabled)

Shared:
- 4 reusable modules: agentidp (dual AWS/GCP), rds, redis, lb
- No hardcoded secrets; all sensitive vars marked sensitive=true
- terraform.tfvars.example for both environments
- docs/devops/deployment.md — AWS + GCP step-by-step walkthrough, rollback procedures

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 06:25:14 +00:00

181 lines
5.5 KiB
HCL

################################################################################
# Module: rds
# Main — AWS RDS PostgreSQL 14
#
# - Multi-AZ for HA
# - Encryption at rest (AWS-managed KMS key)
# - No public access — VPC-internal only
# - Storage autoscaling up to max_allocated_storage
# - Enhanced monitoring and Performance Insights enabled by default
# - Access restricted to explicitly allowed security groups (app only)
################################################################################
terraform {
required_version = ">= 1.6.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.40.0"
}
}
}
locals {
identifier = "${var.project}-${var.environment}"
common_tags = {
environment = var.environment
project = var.project
managed_by = "terraform"
}
}
################################################################################
# Security Group — only the app SGs may connect on 5432
################################################################################
resource "aws_security_group" "rds" {
name = "${local.identifier}-rds-sg"
description = "Controls inbound access to RDS PostgreSQL — allow only app SG on 5432"
vpc_id = var.vpc_id
# No ingress rules defined here — added dynamically below to avoid circular deps.
egress {
description = "All outbound (RDS initiates no outbound connections; this satisfies AWS requirement)"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = merge(local.common_tags, {
Name = "${local.identifier}-rds-sg"
})
}
resource "aws_security_group_rule" "rds_ingress_from_app" {
for_each = toset(var.allowed_security_group_ids)
type = "ingress"
description = "PostgreSQL from app security group"
from_port = 5432
to_port = 5432
protocol = "tcp"
source_security_group_id = each.value
security_group_id = aws_security_group.rds.id
}
################################################################################
# DB Subnet Group — must cover at least 2 AZs for Multi-AZ
################################################################################
resource "aws_db_subnet_group" "main" {
name = "${local.identifier}-db-subnet-group"
description = "Private subnets for AgentIdP RDS instance"
subnet_ids = var.subnet_ids
tags = merge(local.common_tags, {
Name = "${local.identifier}-db-subnet-group"
})
}
################################################################################
# DB Parameter Group — enforce SSL connections
################################################################################
resource "aws_db_parameter_group" "main" {
name = "${local.identifier}-pg14-params"
family = var.parameter_group_family
description = "AgentIdP custom parameter group — enforces SSL"
parameter {
name = "rds.force_ssl"
value = "1"
apply_method = "immediate"
}
parameter {
name = "log_connections"
value = "1"
apply_method = "immediate"
}
parameter {
name = "log_disconnections"
value = "1"
apply_method = "immediate"
}
parameter {
name = "log_min_duration_statement"
value = "1000"
apply_method = "immediate"
}
tags = local.common_tags
}
################################################################################
# RDS Instance
################################################################################
resource "aws_db_instance" "main" {
identifier = local.identifier
# Engine
engine = "postgres"
engine_version = "14"
instance_class = var.instance_class
# Storage
storage_type = "gp3"
allocated_storage = var.allocated_storage
max_allocated_storage = var.max_allocated_storage
storage_encrypted = true
# kms_key_id is omitted — defaults to the AWS-managed RDS KMS key.
# For customer-managed key, set kms_key_id to your CMK ARN.
# Database
db_name = var.db_name
username = var.db_username
password = var.db_password
# Network — VPC-internal only, no public endpoint
db_subnet_group_name = aws_db_subnet_group.main.name
vpc_security_group_ids = [aws_security_group.rds.id]
publicly_accessible = false
multi_az = var.multi_az
port = 5432
# Parameter group
parameter_group_name = aws_db_parameter_group.main.name
# Backups
backup_retention_period = var.backup_retention_days
backup_window = var.backup_window
delete_automated_backups = false
copy_tags_to_snapshot = true
skip_final_snapshot = var.skip_final_snapshot
final_snapshot_identifier = var.skip_final_snapshot ? null : "${local.identifier}-final-snapshot"
# Maintenance
maintenance_window = var.maintenance_window
auto_minor_version_upgrade = true
apply_immediately = false
# Observability
enabled_cloudwatch_logs_exports = ["postgresql", "upgrade"]
performance_insights_enabled = var.performance_insights_enabled
performance_insights_retention_period = var.performance_insights_enabled ? var.performance_insights_retention_period : null
monitoring_interval = var.monitoring_interval
monitoring_role_arn = var.monitoring_interval > 0 ? var.monitoring_role_arn : null
# Protection
deletion_protection = var.deletion_protection
tags = merge(local.common_tags, {
Name = local.identifier
})
}