litellm/terraform/litellm/aws/rds.tf
Yassin Kortam 5bc523a09f
feat(terraform/aws): make VPC, Aurora, and Redis optional (#36676)
Adds vpc_id/public_subnet_ids/private_subnet_ids to deploy into existing
networking, plus create_database/database_url and create_redis/redis_url to
use existing data stores or none at all. Defaults keep today's module-owned
behavior.

A container reads a secret by ARN, which gives Terraform no edge to the
_version that writes the value. The managed-Aurora path hid that behind the
cluster create; the bring-your-own path has nothing slow in between, so the
migration, the bootstrap, and both services now depend on the versions
explicitly.

Supplied private subnets must cover two AZs whenever Aurora or ElastiCache is
module-created, since both subnet groups require it, and a check block warns
when a Redis-less stack can run more than one gateway process, because per-key
rate limits are counted per process without Redis.
2026-08-12 15:27:13 -07:00

102 lines
4 KiB
HCL

# Aurora Postgres cluster with one writer + one reader instance, IAM
# database authentication enabled. Skipped entirely when
# create_database = false, in which case the stack either talks to the
# database named by var.database_url or runs without one.
#
# Important: enabling IAM auth on the cluster does not by itself grant any
# Postgres user the ability to log in with an IAM token. After the first
# apply, connect as the master user (password lives in Secrets Manager —
# see `master_user_secret_arn` in outputs) and run, once:
#
# CREATE USER {var.db_username};
# GRANT rds_iam TO {var.db_username};
# GRANT ALL PRIVILEGES ON DATABASE {var.db_name} TO {var.db_username};
# GRANT ALL ON SCHEMA public TO {var.db_username};
#
# After that, the gateway/backend/migration tasks (which authenticate as
# `{var.db_username}` via IAM-signed tokens) can connect. The master user
# itself is a superuser and Postgres refuses to grant `rds_iam` to
# superusers — keep it for break-glass only.
resource "aws_db_subnet_group" "this" {
count = var.create_database ? 1 : 0
name = "${local.name}-db"
subnet_ids = local.private_subnet_ids
tags = local.tags
}
resource "aws_rds_cluster_parameter_group" "this" {
count = var.create_database ? 1 : 0
name = "${local.name}-cluster-pg"
family = "aurora-postgresql${split(".", var.db_engine_version)[0]}"
description = "LiteLLM Aurora Postgres cluster parameters."
tags = local.tags
}
resource "aws_rds_cluster" "this" {
count = var.create_database ? 1 : 0
cluster_identifier = local.name
engine = "aurora-postgresql"
engine_mode = "provisioned"
engine_version = var.db_engine_version
database_name = var.db_name
master_username = var.db_master_username
master_password = random_password.db_master_password[0].result
db_subnet_group_name = aws_db_subnet_group.this[0].name
vpc_security_group_ids = [aws_security_group.rds[0].id]
db_cluster_parameter_group_name = aws_rds_cluster_parameter_group.this[0].name
iam_database_authentication_enabled = true
storage_encrypted = true
apply_immediately = true
# Final-snapshot guard. With the safe default (skip_final_snapshot = false),
# `terraform destroy` takes a snapshot named `<cluster>-final-<short-sha>`
# before dropping the cluster. The short SHA disambiguates repeated
# destroy/recreate cycles so each snapshot has a unique name.
skip_final_snapshot = var.skip_final_snapshot
final_snapshot_identifier = var.skip_final_snapshot ? null : "${local.name}-final-${substr(md5(local.name), 0, 8)}"
backup_retention_period = 7
preferred_backup_window = "07:00-09:00"
tags = local.tags
}
resource "aws_rds_cluster_instance" "writer" {
count = var.create_database ? 1 : 0
identifier = "${local.name}-writer"
cluster_identifier = aws_rds_cluster.this[0].id
instance_class = var.db_instance_class
engine = aws_rds_cluster.this[0].engine
engine_version = aws_rds_cluster.this[0].engine_version
publicly_accessible = false
performance_insights_enabled = true
# Promotion tier 0 — first in line during failover, so this instance stays
# the writer unless it goes unhealthy.
promotion_tier = 0
tags = local.tags
}
resource "aws_rds_cluster_instance" "reader" {
count = var.create_database ? 1 : 0
identifier = "${local.name}-reader"
cluster_identifier = aws_rds_cluster.this[0].id
instance_class = var.db_instance_class
engine = aws_rds_cluster.this[0].engine
engine_version = aws_rds_cluster.this[0].engine_version
publicly_accessible = false
performance_insights_enabled = true
# Higher promotion tier — won't be picked as writer during a failover
# unless the writer instance itself is gone.
promotion_tier = 15
tags = local.tags
}