From a522fa8e6aae5b692fb36caf21c797cbb64f846a Mon Sep 17 00:00:00 2001 From: Ariel Rolfo Date: Mon, 29 Jun 2026 15:27:47 -0300 Subject: [PATCH] fix(infra): stop Terraform clobbering app secret on every apply The app runtime secret (ctdl-xtra//app) is managed out-of-band in Secrets Manager via the "Update app env vars" workflow, but aws_secretsmanager_secret_version.app rewrote the whole blob from local.app_secret_values on every apply. That regenerated random_password.encryption_key, changing ENCRYPTION_KEY and orphaning all data already encrypted under the previous key (caused the prod DB-secret decryption failures). Add lifecycle { ignore_changes = [secret_string] } to all three envs so Terraform seeds the secret on first creation only and never overwrites runtime values afterward. Co-Authored-By: Claude Opus 4.8 --- infra/terraform/envs/production/app-deps.tf | 10 ++++++++++ infra/terraform/envs/sandbox/app-deps.tf | 10 ++++++++++ infra/terraform/envs/test/app-deps.tf | 10 ++++++++++ 3 files changed, 30 insertions(+) diff --git a/infra/terraform/envs/production/app-deps.tf b/infra/terraform/envs/production/app-deps.tf index 94ce594..2b98c81 100644 --- a/infra/terraform/envs/production/app-deps.tf +++ b/infra/terraform/envs/production/app-deps.tf @@ -275,4 +275,14 @@ resource "aws_secretsmanager_secret" "app" { resource "aws_secretsmanager_secret_version" "app" { secret_id = aws_secretsmanager_secret.app.id secret_string = jsonencode(local.app_secret_values) + + # Terraform only *seeds* this secret on first creation. Runtime values + # (notably ENCRYPTION_KEY, plus anything set via the "Update app env vars" + # workflow) are managed out-of-band in Secrets Manager and must survive + # later applies. Without this, every apply rewrites the blob from + # local.app_secret_values — regenerating ENCRYPTION_KEY and orphaning all + # data already encrypted under the previous key. + lifecycle { + ignore_changes = [secret_string] + } } diff --git a/infra/terraform/envs/sandbox/app-deps.tf b/infra/terraform/envs/sandbox/app-deps.tf index 44db515..8bd103d 100644 --- a/infra/terraform/envs/sandbox/app-deps.tf +++ b/infra/terraform/envs/sandbox/app-deps.tf @@ -277,4 +277,14 @@ resource "aws_secretsmanager_secret" "app" { resource "aws_secretsmanager_secret_version" "app" { secret_id = aws_secretsmanager_secret.app.id secret_string = jsonencode(local.app_secret_values) + + # Terraform only *seeds* this secret on first creation. Runtime values + # (notably ENCRYPTION_KEY, plus anything set via the "Update app env vars" + # workflow) are managed out-of-band in Secrets Manager and must survive + # later applies. Without this, every apply rewrites the blob from + # local.app_secret_values — regenerating ENCRYPTION_KEY and orphaning all + # data already encrypted under the previous key. + lifecycle { + ignore_changes = [secret_string] + } } diff --git a/infra/terraform/envs/test/app-deps.tf b/infra/terraform/envs/test/app-deps.tf index 2dc4ad0..29d26d6 100644 --- a/infra/terraform/envs/test/app-deps.tf +++ b/infra/terraform/envs/test/app-deps.tf @@ -277,4 +277,14 @@ resource "aws_secretsmanager_secret" "app" { resource "aws_secretsmanager_secret_version" "app" { secret_id = aws_secretsmanager_secret.app.id secret_string = jsonencode(local.app_secret_values) + + # Terraform only *seeds* this secret on first creation. Runtime values + # (notably ENCRYPTION_KEY, plus anything set via the "Update app env vars" + # workflow) are managed out-of-band in Secrets Manager and must survive + # later applies. Without this, every apply rewrites the blob from + # local.app_secret_values — regenerating ENCRYPTION_KEY and orphaning all + # data already encrypted under the previous key. + lifecycle { + ignore_changes = [secret_string] + } }