Skip to content

sec(iac): flip dev/staging/prod to AWS_IAM + enable CloudFront OAC (runtime cut-over for #424) #16

Open

Description

@cristim

Context

PR LeanerCloud/cloud-commitments-cli#574 added the Terraform infrastructure for authorization_type = "AWS_IAM" on the Lambda Function URL:

  • aws_cloudfront_origin_access_control (type=lambda, sigv4) in the frontend module
  • aws_lambda_permission.function_url_cloudfront at the environment layer (scoped to the specific distribution ARN)
  • Module default changed to "AWS_IAM"

All three env tfvars retain "NONE" with a TODO(LeanerCloud/cloud-commitments-cli#424) comment because flipping to "AWS_IAM" without a CloudFront OAC in place would make the Function URL return HTTP 403 on all requests.

What this issue tracks

The runtime cut-over: deploying CloudFront in front of each Lambda environment and flipping the auth type.

Steps per environment

For each of dev, staging, prod (in that order):

  1. In the env's github-*.tfvars:
    • Set enable_cdn = true
    • Set lambda_function_url_auth_type = "AWS_IAM"
    • Update lambda_allowed_origins from the raw Lambda Function URL to the CloudFront domain (e.g. ["https://app.example.com"])
  2. Run terraform apply -- this creates the CloudFront distribution, the OAC, and the Lambda permission in a single apply.
  3. Verify: hit the CloudFront URL, confirm requests reach Lambda and return 200. Confirm a direct request to the Lambda Function URL returns 403.

Notes

  • The frontend client.ts is already OAC-ready (uses X-Authorization, sends x-amz-content-sha256 on mutating requests).
  • Staging and prod tfvars use .invalid placeholder origins -- update to real domains before applying.
  • The dev Lambda Function URL is https://33pz7pombdqwu3bdlxp4lqxyra0bsriy.lambda-url.us-east-1.on.aws (from the current github-dev.tfvars).

Closes LeanerCloud/cloud-commitments-cli#424

Activity

  1. added
    pr-createdA PR has been opened for this issue (dedup guard for the auto-PR loop)
    on Jun 7, 2026
  2. cristim commented on Jul 28, 2026

    @cristim
    MemberAuthor

    Re-verified during the 2026-07-28 full IaC review. Reviewed commit be11bdcb5; every reference below re-checked against origin/main at 3e9660d06.

    Status: still live, unchanged

    All three AWS environments still ship enable_cdn = false:

    • terraform/environments/aws/github-dev.tfvars:74
    • terraform/environments/aws/github-staging.tfvars:72
    • terraform/environments/aws/github-prod.tfvars:73

    which derives lambda_function_url_auth_type = "NONE" at terraform/environments/aws/compute.tf:25. Prod additionally carries lambda_allowed_origins = ["https://prod-not-yet-deployed.invalid"] (github-prod.tfvars:32) with a TODO(env-not-deployed) comment. That is a browser-only control and is not a mitigation for the missing IAM gate: curl and any non-browser client ignore CORS entirely.

    One correction to the record: the resource-based policy this cut-over needs does already exist at the environment layer. terraform/environments/aws/compute.tf:262-269 creates aws_lambda_permission.function_url_cloudfront with principal = "cloudfront.amazonaws.com" and source_arn = module.frontend[0].cloudfront_distribution_arn, gated on var.enable_cdn. Since the auth type is derived from the same flag, flipping enable_cdn = true creates the distribution, the OAC, and the permission in one apply, exactly as step 2 of this issue describes. So the cut-over should be mechanically clean.

    One gap this issue does not currently close

    The plan as written is a manual per-environment checklist with no regression guard. After the cut-over, a single enable_cdn = false edit in any tfvars file silently returns prod to auth_type = "NONE" with no plan-time signal, because the derivation is intentionally implicit.

    Suggest adding to the acceptance criteria a precondition or check block in terraform/environments/aws that fails the plan when environment == "prod" and enable_cdn == false. That converts the fix from a one-time action into an invariant.

    GCP has the same defect and is not covered here

    terraform/environments/gcp/compute.tf:32 derives cloud_run_allow_unauthenticated = !var.enable_cdn, and terraform/environments/gcp/github-prod.tfvars sets enable_cdn = false (:78) plus cloud_run_ingress = "INGRESS_TRAFFIC_ALL" (:34). It also sets enable_cloud_armor = true (:79) while frontend.tf:7 is count = var.enable_cdn ? 1 : 0, so the WAF is provisioned outside every request path and an operator reading the tfvars is misled about what protects the API.

    Filed separately from this review so the GCP cut-over and the inert-WAF problem get their own tracking, rather than being folded into this AWS-scoped issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions