You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
sec(iac): flip dev/staging/prod to AWS_IAM + enable CloudFront OAC (runtime cut-over for #424) #16
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):
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"])
Run terraform apply -- this creates the CloudFront distribution, the OAC, and the Lambda permission in a single apply.
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).
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.
Activity
cristim commentedon Jul 28, 2026
Re-verified during the 2026-07-28 full IaC review. Reviewed commit
be11bdcb5; every reference below re-checked againstorigin/mainat3e9660d06.Status: still live, unchanged
All three AWS environments still ship
enable_cdn = false:terraform/environments/aws/github-dev.tfvars:74terraform/environments/aws/github-staging.tfvars:72terraform/environments/aws/github-prod.tfvars:73which derives
lambda_function_url_auth_type = "NONE"atterraform/environments/aws/compute.tf:25. Prod additionally carrieslambda_allowed_origins = ["https://prod-not-yet-deployed.invalid"](github-prod.tfvars:32) with aTODO(env-not-deployed)comment. That is a browser-only control and is not a mitigation for the missing IAM gate:curland 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-269createsaws_lambda_permission.function_url_cloudfrontwithprincipal = "cloudfront.amazonaws.com"andsource_arn = module.frontend[0].cloudfront_distribution_arn, gated onvar.enable_cdn. Since the auth type is derived from the same flag, flippingenable_cdn = truecreates 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 = falseedit in any tfvars file silently returns prod toauth_type = "NONE"with no plan-time signal, because the derivation is intentionally implicit.Suggest adding to the acceptance criteria a
preconditionorcheckblock interraform/environments/awsthat fails the plan whenenvironment == "prod"andenable_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:32derivescloud_run_allow_unauthenticated = !var.enable_cdn, andterraform/environments/gcp/github-prod.tfvarssetsenable_cdn = false(:78) pluscloud_run_ingress = "INGRESS_TRAFFIC_ALL"(:34). It also setsenable_cloud_armor = true(:79) whilefrontend.tf:7iscount = 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.