RDS Postgres
An encrypted Postgres 17 instance in private subnets that only accepts TLS connections.
GovCloudCMKView source
- Module
- rds-postgres
- Layer
- Data
- Interface
- 23 inputs, 6 outputs
- Used by
- 9 Kaizen apps
Why it matters
Most Kaizen apps keep their records in Postgres, and losing that data or exposing it is the most expensive failure a project can have. This module encrypts storage, refuses unencrypted connections, keeps a standby copy in a second availability zone, and blocks accidental deletion. Federal stacks add a customer managed key, log export, and DDL audit logging with five settings.
Use it when
- The app needs a relational database, for example with Prisma.
- A tool such as openobserve needs a metadata store that the caller manages.
Reach for something else when
- You need a cache, session store, or queue with low latency. Use redis.
- You store files, uploads, or exports. Use s3-bucket.
What it creates
aws_db_subnet_group(private subnets)aws_security_group(port 5432 from allowed_security_group_ids and allowed_cidr_blocks only)aws_db_parameter_group(rds.force_ssl = 1, optional DDL and slow query logging)aws_db_instance(Postgres 17, gp3, encrypted, Multi-AZ, Performance Insights)
Secure by default
- Storage is encrypted (storage_encrypted = true, not configurable).
- Connections without TLS are refused (rds.force_ssl = 1).
- A standby runs in a second availability zone (multi_az = true).
- Deletion protection is on, and destroy takes a final snapshot (skip_final_snapshot = false).
- Automated backups are kept for 7 days and Performance Insights is on.
Commercial and GovCloud
module "rds" {
source = "git::ssh://git@github.com/the-kaizen-labs/terraform-modules.git//rds-postgres?ref=v1.7.0"
app_name = local.app_name
vpc_id = module.networking.vpc_id
private_subnet_ids = module.networking.private_subnet_ids
allowed_security_group_ids = [module.ecs_service.security_group_id]
instance_class = "db.t4g.micro"
db_name = "my_app"
db_username = "app_user"
db_password = data.aws_ssm_parameter.db_password.value
tags = local.tags
}| Setting | Commercial default | Federal setting | Note |
|---|---|---|---|
kms_key_id | null (AWS managed RDS key) | customer managed KMS key ARN | FedRAMP SC-13. |
performance_insights_kms_key_id | null (AWS managed) | the same key as kms_key_id | |
enabled_cloudwatch_logs_exports | [] | ["postgresql"] | |
enable_audit_logging | false | true | Adds log_statement = ddl and log_min_duration_statement = 1000. |
copy_tags_to_snapshot | false | true |
How it connects
- From networking: vpc_id, private_subnet_ids
- From ecs-service: security_group_id (as allowed_security_group_ids)
- From bastion: security_group_id (as allowed_security_group_ids)
- From openobserve: task_security_group_id (as allowed_security_group_ids)
- To ecs-service: db_host, in an SSM DATABASE_URL
- To openobserve: db_host, in the SSM DSN passed as metadata_postgres_dsn_ssm_arn
Inputs
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
app_name | string | yes | Application name used in resource naming | |
db_name | string | yes | Database name | |
db_password | string | yes | Master password - pass this from an SSM data source, never hardcode Sensitive. | |
db_username | string | yes | Master username | |
instance_class | string | yes | RDS instance class (e.g. db.t4g.micro, db.t4g.medium) | |
private_subnet_ids | list(string) | yes | Private subnet IDs for the RDS subnet group | |
vpc_id | string | yes | VPC ID | |
allocated_storage | number | 20 | no | Allocated storage in GiB |
allowed_cidr_blocks | list(string) | [] | no | CIDR blocks allowed to connect on port 5432. Use when security group creates a circular dependency. |
allowed_security_group_ids | list(string) | [] | no | Security group IDs allowed to connect on port 5432 (use module.ecs_service.security_group_id) |
backup_retention_days | number | 7 | no | Number of days to retain automated backups |
copy_tags_to_snapshot | bool | false | no | Copy instance tags to automated snapshots. AWS provider default is false; off here for v1 compatibility. |
deletion_protection | bool | true | no | Protect the instance from accidental deletion |
enable_audit_logging | bool | false | no | Add log_statement = ddl and log_min_duration_statement = 1000 to the parameter group (DDL audit + slow-query log). Off by default to avoid parameter group churn for v1 callers. |
enabled_cloudwatch_logs_exports | list(string) | [] | no | Postgres log types to export to CloudWatch (e.g. ["postgresql"]). Empty disables export. Federal posture should enable export to support the audit trail. |
engine_version | string | "17" | no | PostgreSQL engine version |
environment | string | "" | no | Environment suffix (dev, prod, staging). Leave empty if the account has no env concept. |
kms_key_id | string | null | no | Customer-managed KMS key ARN for storage encryption. Null falls back to the AWS-managed RDS key. Required for federal posture (FedRAMP SC-13). |
multi_az | bool | true | no | Enable Multi-AZ for high availability |
parameter_group_family | string | "postgres17" | no | Parameter group family. Must match engine_version (e.g. postgres17 for engine 17). |
performance_insights_kms_key_id | string | null | no | KMS key ARN for Performance Insights encryption. Null falls back to the AWS-managed key. Federal posture should set this to the same key as kms_key_id. |
skip_final_snapshot | bool | false | no | If true, no final snapshot is taken when the instance is destroyed. Defaults false (federal-safe). Override to true for dev/POC databases that you genuinely want to nuke without leaving an orphan snapshot behind. |
tags | map(string) | {} | no | Tags to apply to all resources |
Outputs
| Name | Description |
|---|---|
db_endpoint | Value: aws_db_instance.this.endpoint |
db_host | Value: aws_db_instance.this.address |
db_instance_arn | Value: aws_db_instance.this.arn |
db_name | Value: aws_db_instance.this.db_name |
db_port | Value: aws_db_instance.this.port |
security_group_id | Value: aws_security_group.rds.id |
Used by
| App | Pinned ref |
|---|---|
| BidBuddy | v1.0.0 |
| castle | v1.6.0 |
| dust | v1.1.0 |
| ginkgo | v1.3.0 |
| juniper | v1.1.0 |
| magnolia | v1.1.0 |
| oak | v1.1.0 |
| poppy | v1.1.0 |
| saplings | v1.3.0 |