Skip to content

fix(infra): make prod RDS reachable from the lambdas - #292

Merged
nourshoreibah merged 2 commits into
mainfrom
worktree-fix-rds-public-access
Jul 29, 2026
Merged

fix(infra): make prod RDS reachable from the lambdas#292
nourshoreibah merged 2 commits into
mainfrom
worktree-fix-rds-public-access

Conversation

@nourshoreibah

Copy link
Copy Markdown
Collaborator

Problem

GET /auth/me from the frontend hung for ~30s and returned nothing. Root cause was not application logic — nothing in the deployed stack has ever been able to reach the production database. That is also why prod had no schema until it was applied by hand.

Three defects, all required for one request to work

1. The lambdas had no route to the database. aws_db_instance.branch_rds never set publicly_accessible, so it defaulted to false and its endpoint only resolved to a private address inside the default VPC. The six lambdas have no vpc_config and run outside any VPC. Fixed with publicly_accessible = true.

The stronger fix is putting the lambdas in the VPC. Rejected on cost: a VPC lambda with no internet route can't reach Cognito, which all six do on cold start (aws-jwt-verify JWKS fetch), so it needs a NAT gateway ($33/mo) or a cognito-idp interface endpoint ($7/mo). Consciously traded away for $0.

2. TLS was disabled but mandatory. rds.force_ssl = 1 on default.postgres17, while all six db.ts hardcoded ssl: false — Postgres would have rejected these connections even once routable, with no pg_hba.conf entry for host ..., no encryption. Enabled in production only; local docker-compose Postgres has no TLS.

Worth noting this was masked: manual psql worked because psql defaults to sslmode=prefer and silently negotiated TLS.

3. Failures hung instead of erroring. pg had no connectionTimeoutMillis. A blackholed SYN never gets an RST, so the pool waited forever, turning a network fault into a 30s function timeout with nothing logged. Set to 5s, well inside API Gateway's 29s integration ceiling.

Security change

Replaces the VPC default security group on the instance — which allowed all protocols from 0.0.0.0/0 — with branch-rds-sg scoped to 5432. This was survivable while the instance was unreachable; it would not be now that the endpoint is public.

The rule is still 0.0.0.0/0 on 5432, and that is deliberate rather than lazy: AWS publishes no Lambda egress ranges (there is no LAMBDA tag in ip-ranges.json), and non-VPC lambdas egress from the region's EC2 pool — 83 CIDR blocks, ~4.4M addresses in us-east-2, i.e. every EC2 instance of every AWS customer in Ohio. No narrower CIDR would still admit our own lambdas. The master password is therefore the real control.

Also adds prevent_destroy: skip_final_snapshot = true means any replacement (e.g. an innocuous-looking db_subnet_group_name edit) would silently destroy the database with no backup.

Verification

  • terraform validate passes; terraform fmt -check clean.
  • All six lambdas typecheck clean (tsc --noEmit) after installing workspace deps and building shared/lambda-auth.
  • Not yet verified end-to-end against deployed infra — needs terraform apply and a lambda deploy, then GET /auth/me should return the admin user with isAdmin: true.

Follow-ups (not in this PR)

  • Rotate the master password. It is weak and was readable from plaintext lambda env vars.
  • Pin the RDS CA bundle so TLS is authenticated, not just encrypted (currently rejectUnauthorized: false). Needs a shared package so the PEM isn't copied six times.
  • Add a mechanism that applies db_setup.sql to prod — nothing in CI ever has (lambda-tests.yml and regenerate-db-types.yaml both target localhost).
  • Consider collapsing the six identical db.ts files into a shared/lambda-db package.

🤖 Generated with Claude Code

nourshoreibah and others added 2 commits July 28, 2026 20:34
GET /auth/me and every other DB-backed endpoint hung for ~30s and returned
nothing. Nothing in the deployed stack could reach the production database.

Three independent defects, all of which had to be fixed for a single request
to work:

1. aws_db_instance.branch_rds never set publicly_accessible, so it defaulted
   to false and its endpoint only resolved privately inside the default VPC.
   The six lambdas have no vpc_config and run outside any VPC, so they had no
   route to it. Set publicly_accessible = true.

   The stronger fix is moving the lambdas into the VPC, but a VPC lambda with
   no internet route cannot reach Cognito -- which all six do on cold start to
   verify JWTs -- so it requires a NAT gateway (~$33/mo) or a cognito-idp
   interface endpoint (~$7/mo). Deliberately traded away.

2. rds.force_ssl = 1 on the default.postgres17 parameter group, but all six
   db.ts hardcoded ssl: false, so Postgres would have rejected the connections
   even once routable. Enable TLS in production only, since local
   docker-compose Postgres has no TLS.

3. pg had no connectionTimeoutMillis. A blackholed SYN never gets an RST, so
   the pool waited forever and turned a network fault into a 30s function
   timeout with nothing logged -- which is why this presented as a hang rather
   than an error. Set to 5s, well inside API Gateway's 29s ceiling.

Also replaces the VPC default security group on the instance, which allowed
all protocols from 0.0.0.0/0, with branch-rds-sg scoped to 5432. This matters
more now the endpoint is public. It is still open to the internet, because AWS
publishes no Lambda egress ranges (no LAMBDA tag in ip-ranges.json; non-VPC
lambdas egress from the region's ~4.4M-address EC2 pool), so no narrower CIDR
would admit them. The master password is therefore the real control.

Adds prevent_destroy, since skip_final_snapshot = true means any replacement
would destroy the database with no backup.

Follow-ups, not in this PR: rotate the master password, pin the RDS CA bundle
so TLS is authenticated rather than only encrypted, and add a mechanism that
applies db_setup.sql to prod (nothing in CI ever has).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
  - Auto-formatted .tf files with terraform fmt
  - Updated README.md with terraform-docs

  Co-authored-by: nourshoreibah <nourshoreibah@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

Terraform Plan 📖 infrastructure/aws

Terraform Initialization ⚙️success

Terraform Validation 🤖success

Terraform Plan 📖success

Show Plan
data.archive_file.lambda_placeholder: Reading...
data.archive_file.lambda_placeholder: Read complete after 0s [id=96878a51e358033297a32b882fd5223cc95fb8a7]
aws_iam_role.lambda_role: Refreshing state... [id=branch-lambda-role]
aws_api_gateway_rest_api.branch_api: Refreshing state... [id=2apxzxb0r8]
aws_cloudfront_origin_access_control.frontend: Refreshing state... [id=E2T090T8V5CDLN]
aws_s3_bucket.reports_bucket: Refreshing state... [id=c4c-branch-generated-reports20251030194253425700000001]
data.aws_vpc.default: Reading...
aws_cloudfront_function.rewrite_index: Refreshing state... [id=branch-frontend-rewrite-index]
data.aws_caller_identity.current: Reading...
aws_iam_openid_connect_provider.github: Refreshing state... [id=arn:aws:iam::489881683177:oidc-provider/token.actions.githubusercontent.com]
aws_cognito_user_pool.branch_user_pool: Refreshing state... [id=us-east-2_CxTueqe6g]
data.aws_caller_identity.current: Read complete after 0s [id=489881683177]
aws_s3_bucket.frontend: Refreshing state... [id=branch-frontend-489881683177]
aws_s3_bucket.lambda_deployments: Refreshing state... [id=branch-lambda-deployments-489881683177]
data.infisical_secrets.github_folder: Reading...
data.infisical_secrets.rds_folder: Reading...
data.aws_iam_policy_document.ci_apply_assume: Reading...
data.aws_iam_policy_document.ci_apply_assume: Read complete after 0s [id=813913]
data.aws_iam_policy_document.ci_preview_assume: Reading...
data.aws_iam_policy_document.ci_preview_assume: Read complete after 0s [id=282080688]
data.aws_iam_policy_document.ci_plan_assume: Reading...
data.aws_iam_policy_document.ci_plan_assume: Read complete after 0s [id=3057813384]
aws_api_gateway_gateway_response.cors["DEFAULT_5XX"]: Refreshing state... [id=aggr-2apxzxb0r8-DEFAULT_5XX]
data.infisical_secrets.github_folder: Read complete after 0s
aws_api_gateway_gateway_response.cors["DEFAULT_4XX"]: Refreshing state... [id=aggr-2apxzxb0r8-DEFAULT_4XX]
aws_api_gateway_resource.lambda_resources["expenditures"]: Refreshing state... [id=6sdj3w]
aws_api_gateway_resource.lambda_resources["users"]: Refreshing state... [id=0dkbds]
aws_api_gateway_resource.lambda_resources["auth"]: Refreshing state... [id=u8unad]
aws_api_gateway_resource.lambda_resources["projects"]: Refreshing state... [id=chhy2i]
aws_api_gateway_resource.lambda_resources["donors"]: Refreshing state... [id=hybur2]
aws_api_gateway_resource.lambda_resources["reports"]: Refreshing state... [id=wsnfk2]
aws_iam_role.ci_apply: Refreshing state... [id=branch-ci-apply]
aws_iam_role.ci_preview: Refreshing state... [id=branch-ci-preview]
aws_iam_role.ci_plan: Refreshing state... [id=branch-ci-plan]
aws_cognito_user_pool_client.branch_client: Refreshing state... [id=570i6ocj0882qu0ditm4vrr60f]
data.aws_vpc.default: Read complete after 1s [id=vpc-0a9ccfb59c8918ce9]
aws_iam_role_policy_attachment.lambda_basic: Refreshing state... [id=branch-lambda-role/arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole]
aws_iam_role_policy.lambda_cognito_admin: Refreshing state... [id=branch-lambda-role:branch-lambda-cognito-admin]
aws_api_gateway_resource.lambda_proxy["reports"]: Refreshing state... [id=elsvn3]
aws_api_gateway_resource.lambda_proxy["users"]: Refreshing state... [id=4sjlu3]
aws_api_gateway_resource.lambda_proxy["expenditures"]: Refreshing state... [id=14khv0]
aws_api_gateway_resource.lambda_proxy["donors"]: Refreshing state... [id=xkazax]
aws_api_gateway_resource.lambda_proxy["projects"]: Refreshing state... [id=kmwcxq]
aws_api_gateway_resource.lambda_proxy["auth"]: Refreshing state... [id=srhf9j]
aws_api_gateway_method.lambda_methods["users-DELETE"]: Refreshing state... [id=agm-2apxzxb0r8-0dkbds-DELETE]
data.infisical_secrets.rds_folder: Read complete after 1s
aws_api_gateway_method.lambda_methods["donors-GET"]: Refreshing state... [id=agm-2apxzxb0r8-hybur2-GET]
aws_api_gateway_method.lambda_methods["expenditures-OPTIONS"]: Refreshing state... [id=agm-2apxzxb0r8-6sdj3w-OPTIONS]
aws_api_gateway_method.lambda_methods["donors-OPTIONS"]: Refreshing state... [id=agm-2apxzxb0r8-hybur2-OPTIONS]
aws_api_gateway_method.lambda_methods["auth-OPTIONS"]: Refreshing state... [id=agm-2apxzxb0r8-u8unad-OPTIONS]
aws_api_gateway_method.lambda_methods["expenditures-GET"]: Refreshing state... [id=agm-2apxzxb0r8-6sdj3w-GET]
aws_api_gateway_method.lambda_methods["reports-OPTIONS"]: Refreshing state... [id=agm-2apxzxb0r8-wsnfk2-OPTIONS]
aws_api_gateway_method.lambda_methods["projects-POST"]: Refreshing state... [id=agm-2apxzxb0r8-chhy2i-POST]
aws_api_gateway_method.lambda_methods["expenditures-PATCH"]: Refreshing state... [id=agm-2apxzxb0r8-6sdj3w-PATCH]
aws_api_gateway_method.lambda_methods["expenditures-POST"]: Refreshing state... [id=agm-2apxzxb0r8-6sdj3w-POST]
aws_api_gateway_method.lambda_methods["reports-GET"]: Refreshing state... [id=agm-2apxzxb0r8-wsnfk2-GET]
aws_api_gateway_method.lambda_methods["auth-POST"]: Refreshing state... [id=agm-2apxzxb0r8-u8unad-POST]
aws_api_gateway_method.lambda_methods["users-POST"]: Refreshing state... [id=agm-2apxzxb0r8-0dkbds-POST]
aws_api_gateway_method.lambda_methods["users-GET"]: Refreshing state... [id=agm-2apxzxb0r8-0dkbds-GET]
aws_api_gateway_method.lambda_methods["projects-OPTIONS"]: Refreshing state... [id=agm-2apxzxb0r8-chhy2i-OPTIONS]
aws_api_gateway_method.lambda_methods["users-OPTIONS"]: Refreshing state... [id=agm-2apxzxb0r8-0dkbds-OPTIONS]
aws_api_gateway_method.lambda_methods["projects-GET"]: Refreshing state... [id=agm-2apxzxb0r8-chhy2i-GET]
aws_api_gateway_method.lambda_methods["auth-GET"]: Refreshing state... [id=agm-2apxzxb0r8-u8unad-GET]
aws_api_gateway_method.lambda_methods["users-PATCH"]: Refreshing state... [id=agm-2apxzxb0r8-0dkbds-PATCH]
aws_s3_bucket_public_access_block.reports_bucket_public_access: Refreshing state... [id=c4c-branch-generated-reports20251030194253425700000001]
aws_iam_role_policy_attachment.ci_apply_admin: Refreshing state... [id=branch-ci-apply/arn:aws:iam::aws:policy/AdministratorAccess]
aws_api_gateway_method.lambda_proxy_any["auth"]: Refreshing state... [id=agm-2apxzxb0r8-srhf9j-ANY]
aws_s3_bucket_public_access_block.frontend: Refreshing state... [id=branch-frontend-489881683177]
aws_api_gateway_method.lambda_proxy_any["reports"]: Refreshing state... [id=agm-2apxzxb0r8-elsvn3-ANY]
aws_api_gateway_method.lambda_proxy_any["donors"]: Refreshing state... [id=agm-2apxzxb0r8-xkazax-ANY]
aws_api_gateway_method.lambda_proxy_any["expenditures"]: Refreshing state... [id=agm-2apxzxb0r8-14khv0-ANY]
aws_api_gateway_method.lambda_proxy_any["users"]: Refreshing state... [id=agm-2apxzxb0r8-4sjlu3-ANY]
aws_api_gateway_method.lambda_proxy_any["projects"]: Refreshing state... [id=agm-2apxzxb0r8-kmwcxq-ANY]
aws_iam_role_policy.ci_preview: Refreshing state... [id=branch-ci-preview:preview-env]
aws_iam_role_policy_attachment.ci_plan_readonly: Refreshing state... [id=branch-ci-plan/arn:aws:iam::aws:policy/ReadOnlyAccess]
aws_iam_role_policy.ci_plan_state_lock: Refreshing state... [id=branch-ci-plan:tfstate-lock]
aws_cloudfront_distribution.frontend: Refreshing state... [id=E37FDHRYNZNF4R]
aws_db_instance.branch_rds: Refreshing state... [id=db-AMMYFTORW6XJGRELV7WQZCNHQI]
aws_s3_bucket_server_side_encryption_configuration.lambda_deployments: Refreshing state... [id=branch-lambda-deployments-489881683177]
aws_s3_bucket_versioning.lambda_deployments: Refreshing state... [id=branch-lambda-deployments-489881683177]
aws_s3_object.lambda_placeholder["expenditures"]: Refreshing state... [id=branch-lambda-deployments-489881683177/expenditures/initial.zip]
aws_s3_object.lambda_placeholder["projects"]: Refreshing state... [id=branch-lambda-deployments-489881683177/projects/initial.zip]
aws_s3_object.lambda_placeholder["reports"]: Refreshing state... [id=branch-lambda-deployments-489881683177/reports/initial.zip]
aws_s3_object.lambda_placeholder["users"]: Refreshing state... [id=branch-lambda-deployments-489881683177/users/initial.zip]
aws_s3_object.lambda_placeholder["auth"]: Refreshing state... [id=branch-lambda-deployments-489881683177/auth/initial.zip]
aws_s3_object.lambda_placeholder["donors"]: Refreshing state... [id=branch-lambda-deployments-489881683177/donors/initial.zip]
aws_s3_bucket_policy.reports_bucket_policy: Refreshing state... [id=c4c-branch-generated-reports20251030194253425700000001]
aws_lambda_function.functions["reports"]: Refreshing state... [id=branch-reports]
aws_lambda_function.functions["users"]: Refreshing state... [id=branch-users]
data.aws_iam_policy_document.frontend_bucket: Reading...
aws_lambda_function.functions["projects"]: Refreshing state... [id=branch-projects]
aws_lambda_function.functions["expenditures"]: Refreshing state... [id=branch-expenditures]
aws_lambda_function.functions["donors"]: Refreshing state... [id=branch-donors]
aws_lambda_function.functions["auth"]: Refreshing state... [id=branch-auth]
data.aws_iam_policy_document.frontend_bucket: Read complete after 1s [id=1471335443]
aws_s3_bucket_policy.frontend: Refreshing state... [id=branch-frontend-489881683177]
aws_lambda_permission.api_gateway_permissions["auth"]: Refreshing state... [id=AllowAPIGatewayInvoke]
aws_lambda_permission.api_gateway_permissions["projects"]: Refreshing state... [id=AllowAPIGatewayInvoke]
aws_lambda_permission.api_gateway_permissions["expenditures"]: Refreshing state... [id=AllowAPIGatewayInvoke]
aws_lambda_permission.api_gateway_permissions["reports"]: Refreshing state... [id=AllowAPIGatewayInvoke]
aws_lambda_permission.api_gateway_permissions["users"]: Refreshing state... [id=AllowAPIGatewayInvoke]
aws_lambda_permission.api_gateway_permissions["donors"]: Refreshing state... [id=AllowAPIGatewayInvoke]
aws_api_gateway_integration.lambda_integrations["users-OPTIONS"]: Refreshing state... [id=agi-2apxzxb0r8-0dkbds-OPTIONS]
aws_api_gateway_integration.lambda_integrations["users-GET"]: Refreshing state... [id=agi-2apxzxb0r8-0dkbds-GET]
aws_api_gateway_integration.lambda_proxy_integrations["users"]: Refreshing state... [id=agi-2apxzxb0r8-4sjlu3-ANY]
aws_api_gateway_integration.lambda_proxy_integrations["auth"]: Refreshing state... [id=agi-2apxzxb0r8-srhf9j-ANY]
aws_api_gateway_integration.lambda_proxy_integrations["expenditures"]: Refreshing state... [id=agi-2apxzxb0r8-14khv0-ANY]
aws_api_gateway_integration.lambda_proxy_integrations["donors"]: Refreshing state... [id=agi-2apxzxb0r8-xkazax-ANY]
aws_api_gateway_integration.lambda_proxy_integrations["projects"]: Refreshing state... [id=agi-2apxzxb0r8-kmwcxq-ANY]
aws_api_gateway_integration.lambda_proxy_integrations["reports"]: Refreshing state... [id=agi-2apxzxb0r8-elsvn3-ANY]
aws_api_gateway_integration.lambda_integrations["users-PATCH"]: Refreshing state... [id=agi-2apxzxb0r8-0dkbds-PATCH]
aws_api_gateway_integration.lambda_integrations["projects-POST"]: Refreshing state... [id=agi-2apxzxb0r8-chhy2i-POST]
aws_api_gateway_integration.lambda_integrations["expenditures-POST"]: Refreshing state... [id=agi-2apxzxb0r8-6sdj3w-POST]
aws_api_gateway_integration.lambda_integrations["reports-OPTIONS"]: Refreshing state... [id=agi-2apxzxb0r8-wsnfk2-OPTIONS]
aws_api_gateway_integration.lambda_integrations["projects-GET"]: Refreshing state... [id=agi-2apxzxb0r8-chhy2i-GET]
aws_api_gateway_integration.lambda_integrations["auth-GET"]: Refreshing state... [id=agi-2apxzxb0r8-u8unad-GET]
aws_api_gateway_integration.lambda_integrations["reports-GET"]: Refreshing state... [id=agi-2apxzxb0r8-wsnfk2-GET]
aws_api_gateway_integration.lambda_integrations["expenditures-GET"]: Refreshing state... [id=agi-2apxzxb0r8-6sdj3w-GET]
aws_api_gateway_integration.lambda_integrations["donors-GET"]: Refreshing state... [id=agi-2apxzxb0r8-hybur2-GET]
aws_api_gateway_integration.lambda_integrations["users-DELETE"]: Refreshing state... [id=agi-2apxzxb0r8-0dkbds-DELETE]
aws_api_gateway_integration.lambda_integrations["users-POST"]: Refreshing state... [id=agi-2apxzxb0r8-0dkbds-POST]
aws_api_gateway_integration.lambda_integrations["expenditures-OPTIONS"]: Refreshing state... [id=agi-2apxzxb0r8-6sdj3w-OPTIONS]
aws_api_gateway_integration.lambda_integrations["auth-OPTIONS"]: Refreshing state... [id=agi-2apxzxb0r8-u8unad-OPTIONS]
aws_api_gateway_integration.lambda_integrations["expenditures-PATCH"]: Refreshing state... [id=agi-2apxzxb0r8-6sdj3w-PATCH]
aws_api_gateway_integration.lambda_integrations["projects-OPTIONS"]: Refreshing state... [id=agi-2apxzxb0r8-chhy2i-OPTIONS]
aws_api_gateway_integration.lambda_integrations["donors-OPTIONS"]: Refreshing state... [id=agi-2apxzxb0r8-hybur2-OPTIONS]
aws_api_gateway_integration.lambda_integrations["auth-POST"]: Refreshing state... [id=agi-2apxzxb0r8-u8unad-POST]
aws_api_gateway_deployment.branch_deployment: Refreshing state... [id=od3a3y]
aws_api_gateway_stage.branch_stage: Refreshing state... [id=ags-2apxzxb0r8-prod]

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  + create
  ~ update in-place

Terraform will perform the following actions:

  # aws_api_gateway_gateway_response.cors["DEFAULT_4XX"] will be updated in-place
  ~ resource "aws_api_gateway_gateway_response" "cors" {
        id                  = "aggr-2apxzxb0r8-DEFAULT_4XX"
      ~ response_templates  = {
          - "application/json" = "{\"message\":$context.error.messageString}" -> null
        }
        # (5 unchanged attributes hidden)
    }

  # aws_api_gateway_gateway_response.cors["DEFAULT_5XX"] will be updated in-place
  ~ resource "aws_api_gateway_gateway_response" "cors" {
        id                  = "aggr-2apxzxb0r8-DEFAULT_5XX"
      ~ response_templates  = {
          - "application/json" = "{\"message\":$context.error.messageString}" -> null
        }
        # (5 unchanged attributes hidden)
    }

  # aws_db_instance.branch_rds will be updated in-place
  ~ resource "aws_db_instance" "branch_rds" {
        id                                    = "db-AMMYFTORW6XJGRELV7WQZCNHQI"
      ~ publicly_accessible                   = false -> true
        tags                                  = {}
      ~ vpc_security_group_ids                = [
          - "sg-0b5ecb5d819f09f87",
        ] -> (known after apply)
        # (71 unchanged attributes hidden)
    }

  # aws_security_group.rds will be created
  + resource "aws_security_group" "rds" {
      + arn                    = (known after apply)
      + description            = "branch_rds: postgres from anywhere (lambdas run outside the VPC)"
      + egress                 = (known after apply)
      + id                     = (known after apply)
      + ingress                = (known after apply)
      + name                   = "branch-rds-sg"
      + name_prefix            = (known after apply)
      + owner_id               = (known after apply)
      + region                 = "us-east-2"
      + revoke_rules_on_delete = false
      + tags                   = {
          + "ManagedBy" = "terraform"
          + "Name"      = "branch-rds-sg"
        }
      + tags_all               = {
          + "ManagedBy" = "terraform"
          + "Name"      = "branch-rds-sg"
        }
      + vpc_id                 = "vpc-0a9ccfb59c8918ce9"
    }

  # aws_vpc_security_group_egress_rule.rds_all will be created
  + resource "aws_vpc_security_group_egress_rule" "rds_all" {
      + arn                    = (known after apply)
      + cidr_ipv4              = "0.0.0.0/0"
      + id                     = (known after apply)
      + ip_protocol            = "-1"
      + region                 = "us-east-2"
      + security_group_id      = (known after apply)
      + security_group_rule_id = (known after apply)
      + tags_all               = {}
    }

  # aws_vpc_security_group_ingress_rule.rds_postgres will be created
  + resource "aws_vpc_security_group_ingress_rule" "rds_postgres" {
      + arn                    = (known after apply)
      + cidr_ipv4              = "0.0.0.0/0"
      + description            = "Postgres from anywhere; lambda egress IPs are not enumerable"
      + from_port              = 5432
      + id                     = (known after apply)
      + ip_protocol            = "tcp"
      + region                 = "us-east-2"
      + security_group_id      = (known after apply)
      + security_group_rule_id = (known after apply)
      + tags_all               = {}
      + to_port                = 5432
    }

Plan: 3 to add, 3 to change, 0 to destroy.

─────────────────────────────────────────────────────────────────────────────

Saved the plan to: tfplan

To perform exactly these actions, run the following command to apply:
    terraform apply "tfplan"

Pushed by: @nourshoreibah, Action: pull_request

@nourshoreibah nourshoreibah added the no-review The PR review bot won't run label Jul 29, 2026
@nourshoreibah
nourshoreibah marked this pull request as ready for review July 29, 2026 02:52
@nourshoreibah
nourshoreibah merged commit 88736a0 into main Jul 29, 2026
19 checks passed
@nourshoreibah
nourshoreibah deleted the worktree-fix-rds-public-access branch July 29, 2026 02:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-review The PR review bot won't run

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant