fix(db): self-heal DATABASE_URL secret after Aurora password rotation#89
Open
elamaran11 wants to merge 1 commit into
Open
fix(db): self-heal DATABASE_URL secret after Aurora password rotation#89elamaran11 wants to merge 1 commit into
elamaran11 wants to merge 1 commit into
Conversation
Aurora's RDS-managed master user secret rotates automatically (7-day default), but the in-cluster accelbench-db secret is a static snapshot taken at terraform apply time. After each rotation the API can no longer authenticate (SASL 28P01) and crashloops, which surfaces in the UI as "Login service unavailable" (web is up, API is down). Add a self-contained hourly CronJob that re-reads the master secret, rebuilds DATABASE_URL (preserving host/port from the existing URL and swapping only the credentials), and — only when it changed — patches the secret and rollout-restarts the API. Idempotent no-op otherwise; no new cluster operators required. Changes: - helm/accelbench/templates/cronjob-db-rotation-sync.yaml: hourly CronJob (reuses the accelbench-api ServiceAccount / Pod Identity). - helm/accelbench/templates/db-rotation-sync-rbac.yaml: least-privilege Role/RoleBinding — get/patch only the accelbench-db secret and the accelbench-api deployment, namespaced. - helm/accelbench/values.yaml: dbRotationSync block (enabled, schedule, masterSecretArn, image, resources). - docker/Dockerfile.db-sync: aws-cli v2 (AL2 base) + kubectl v1.31.4 + jq, published as accelbench-tools:db-sync so it never collides with the API's TOOLS_IMAGE (accelbench-tools:latest). - terraform/main.tf: aws_iam_role_policy.api_db_master_secret_read grants the API role secretsmanager:GetSecretValue on the master secret ARN only.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Aurora's RDS-managed master user secret rotates automatically (7-day default). The in-cluster
accelbench-dbsecret, however, is a static snapshot taken atterraform applytime — nothing re-syncs it after a rotation.Result: after each rotation the API can no longer authenticate and crashloops with:
In the UI this shows up as "Login service unavailable" — the
webfrontend stays up, but theaccelbench-apibackend is down, so the login endpoint is unreachable. It recurs roughly weekly and today required a manual secret patch + API restart to recover.The README's documented fallback ("run
terraform applyto refresh the secret") does not currently work either — see Known limitation below.Fix
A self-contained hourly CronJob that keeps the secret in sync — no new cluster operators (no External Secrets Operator / CSI driver):
accelbench-apiPod Identity).DATABASE_URL, preserving the host/port/db path from the current URL and swapping only the credentials (URL-encoded withjq @uri). This avoids depending ondatabase.host, which is unset in theexistingSecretdeployment path.accelbench-dbsecret andkubectl rollout restarts the API. Otherwise it's a clean no-op — the API is never restarted unnecessarily.Changes
helm/accelbench/templates/cronjob-db-rotation-sync.yaml0 * * * *),concurrencyPolicy: Forbid, reuses theaccelbench-apiServiceAccount.helm/accelbench/templates/db-rotation-sync-rbac.yamlget/patchscoped byresourceNamesto only theaccelbench-dbsecret and theaccelbench-apideployment, namespaced.helm/accelbench/values.yamldbRotationSyncblock:enabled,schedule,masterSecretArn(required when enabled),image,resources.docker/Dockerfile.db-synckubectlv1.31.4 +jq. Published asaccelbench-tools:db-sync— a distinct tag so it never collides with the API'sTOOLS_IMAGE(accelbench-tools:latest).terraform/main.tfaws_iam_role_policy.api_db_master_secret_read— grants the API rolesecretsmanager:GetSecretValue/DescribeSecreton only the master secret ARN.Deployment notes
dbRotationSync.masterSecretArnto the Aurora RDS-managed master secret ARN (Terraform outputaurora_master_user_secret[0].secret_arn).podman build --platform linux/amd64 -f docker/Dockerfile.db-sync -t <registry>/accelbench-tools:db-sync . && podman push ....kubectl/awsbinaries during build on Apple Silicon — they crash under QEMU emulation. The Dockerfile only downloads them; verification happens at runtime on real amd64 nodes.Validation
Deployed to the live
accelbench-ekscluster and exercised end-to-end:accelbench-db, and restarted the API → API recovered,2/2 Running, no28P01.DATABASE_URL already current — no-op— confirms idempotency; the API is not restarted when nothing changed./login→200,/api/v1/status→{"error":"missing_token"}(expected — auth on).Known limitation
terraform plan/applycurrently fails repo-wide with an unrelated, pre-existing error interraform/modules/karpenter/main.tf(Unsupported \moved` across resource types—gavinbunney/kubectl1.19.0 doesn't supportmoved). Because of this, the Terraform IAM policy in this PR was applied out-of-band viaaws iam put-role-policyon the live cluster; the committedterraform/main.tf` change is the IaC record and will reconcile once that karpenter blocker is fixed (worth a separate PR).