fix: Aurora Serverless v2 bootstrap for free-tier AWS accounts (Guide 5) - #42
Open
prodm93 wants to merge 1 commit into
Open
fix: Aurora Serverless v2 bootstrap for free-tier AWS accounts (Guide 5)#42prodm93 wants to merge 1 commit into
prodm93 wants to merge 1 commit into
Conversation
…ier support Free-tier AWS accounts (post March 2026) cannot create Aurora clusters via Terraform because hashicorp/aws does not support WithExpressConfiguration. Replaces the three incomplete shell scripts in bootstrap/ with idempotent Python scripts that create the cluster via boto3 and feed the ARN back into Terraform via bootstrap.auto.tfvars.json. Also makes the tenacity dependency explicit in backend/database and adds retry on DatabaseErrorException in rds_execute for password propagation delay.
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.
Summary
On March 25, 2026, AWS launched Aurora PostgreSQL Express Configuration and simultaneously restricted free-tier accounts to that creation path only. Guide 5's
aws_rds_clusterresource callsCreateDBClusterwithoutWithExpressConfiguration=True; free-tier accounts get backInvalidParameterCombination: Free Tier accounts must use Express Configuration. Thehashicorp/awsprovider does not support the flag (tracking issue filed March 26, 2026). The blocker is architectural:--with-express-configurationcreates a cluster and a writer instance in a single API call, which does not fit Terraform's one-resource-per-state model.This PR replaces the three incomplete shell scripts in
bootstrap/with two idempotent Python scripts that handle the full cluster lifecycle via boto3, then write the cluster ARN back into Terraform viabootstrap.auto.tfvars.json(auto-loaded by Terraform; no manual editing). All downstream modules are unchanged: Guide 6 and Guide 7 read the sameterraform/5_database/outputs as before.Design tension: cluster state lives outside Terraform
The Aurora cluster is not in Terraform state. That is the necessary consequence of the provider limitation. The mitigation is
aurora_cluster_arnwithdefault = ""invariables.tf, which lets the firstterraform applyrun before the cluster exists to create the Secrets Manager secret and IAM role.setup_aurora_express.pythen creates the cluster, writesbootstrap.auto.tfvars.json, and runs a secondterraform applyto record the ARN in outputs. Downstream modules pick it up fromterraform outputexactly as before.One IAM scope change to disclose: the
rds-dataactions inaws_iam_role_policywere previously scoped to the cluster ARN. Since the ARN does not exist at first-apply time, the policy now uses"*"forrds-dataactions. Thesecretsmanager:GetSecretValueaction remains scoped to the specific secret ARN, so the Lambda role can only authenticate against the correct credentials.terraform destroyin5_database/deletes the secret and IAM role but not the cluster, which is not in state. The destroy script handles this; the student instructions call it out explicitly.Notable design decisions
enable_http_endpoint()vsmodify_db_cluster(enable_http_endpoint=True). TheEnableHttpEndpointparameter onmodify_db_clusterapplies only to Serverless v1. On Serverless v2 it silently does nothing. The setup script uses the dedicatedenable_http_endpoint()operation, which is the correct call for Serverless v2 and Express clusters.Typed exception on
modify_db_clusterretry. Afterenable_http_endpoint(), the cluster can briefly rejectmodify_db_clusterwithInvalidDBClusterStateFaulteven after the availability waiter returns. The retry uses tenacityRetryingonrds.exceptions.InvalidDBClusterStateFault(the typed boto3 exception) with exponential backoff. Each retry re-runs the availability waiter before attempting the modify.DatabaseErrorExceptionguard inrds_execute. Aftermodify_db_cluster(MasterUserPassword=...), PostgreSQL can take 30 to 60 seconds to accept the new credential after the cluster reports "available". The Data API returnsDatabaseErrorExceptionwith "password authentication failed" during that window.DatabaseErrorExceptionalso wraps genuine SQL errors, so the retry predicate checks the error message against a known-transient phrase list before retrying. Genuine SQL errors still raise immediately.Secret ARN is not touched by the destroy script. Guide 6 Lambda functions reference the secret ARN in their environment variables. Destroying and recreating the secret would change the ARN and break those functions without a re-deploy. The destroy/setup cycle rebuilds only the cluster.
What is unchanged
DataAPIClientinbackend/database/src/client.pyalready carried tenacity retry onexecute()andbegin_transaction()for auto-pause resume (DatabaseResumingException,BadRequestException: Communications link failure). This PR addstenacitytobackend/database/pyproject.tomlto make that dependency explicit; the retry logic itself is not new.Guide 6 and Guide 7 Terraform modules, all Lambda function code, the database schema, and the Secrets Manager secret ARN are untouched.
Known limitations
terraform destroydoes not destroy the cluster. Students must rundestroy_aurora_express.pybeforeterraform destroyto avoid an orphaned cluster.Scaling (
min_capacity,max_capacity) is no longer a Terraform variable. It is configured as constants at the top ofsetup_aurora_express.py.Future path
When
hashicorp/awsaddsWithExpressConfigurationsupport: reintroduceaws_rds_cluster, restoremin_capacityandmax_capacityas Terraform variables, deletebootstrap.auto.tfvars.json, and retire the bootstrap scripts. No downstream migration required.Files changed
bootstrap/setup_aurora_express.py(new): 7-step idempotent cluster setup.bootstrap/destroy_aurora_express.py(new): cluster teardown with confirmation prompt.bootstrap/pyproject.toml(new): uv project;boto3,tenacity.bootstrap/create_express_cluster.sh,destroy_express_cluster.sh,wait_for_cluster.sh: deleted.terraform/5_database/main.tf: removedaws_rds_cluster;rds-datapolicy scoped to"*".terraform/5_database/variables.tf: removedmin_capacity,max_capacity;aurora_cluster_arngetsdefault = "".terraform/5_database/outputs.tf: outputs read fromvar.aurora_cluster_arn.terraform/5_database/terraform.tfvars.example: simplified.backend/database/pyproject.toml: addedtenacity>=9.1.2.backend/database/src/client.py: tenacity dependency now explicit; retry logic unchanged.Test plan
cd bootstrap && uv run setup_aurora_express.pycompletes all 7 steps cleanlysetup_aurora_express.pyon an existing cluster: idempotent, no errors, no duplicate resources createdcd terraform/5_database && terraform outputreturns correctaurora_cluster_arn,aurora_secret_arn,lambda_role_arnafter setupcd backend/database && uv run test_data_api.pypasses against the bootstrapped clusteruv run run_migrations.py && uv run seed_data.py && uv run verify_database.pyall passMOCK_LAMBDAS=true) pass unchangedcd bootstrap && uv run destroy_aurora_express.py: cluster deleted,bootstrap.auto.tfvars.jsonremoved,terraform output aurora_cluster_arnreturns""setup_aurora_express.pyafter destroy: cluster recreated cleanly, same secret ARN preserved