Summary
GCP Cloud Run's cloud_run_allow_unauthenticated default was flipped to false, but the companion ingress default still allows public traffic (INGRESS_TRAFFIC_ALL). The plan to flip both together was deferred because the supporting external HTTPS Load Balancer + Cloud Armor wasn't provisioned by the env. Cloud Armor is now wired in (enable_cloud_armor per tfvars, frontend.tf references the LB module) — time to revisit whether the ingress default can move.
Captured in: known_issues/19_tf_env_gcp.md ("MEDIUM: Cloud Run publicly reachable — RESOLVED (default flipped; ingress change deferred)").
Current behaviour
terraform/environments/gcp/variables.tf:229 — cloud_run_allow_unauthenticated defaults to false (auth required at IAM level), but the same file's ingress variable still defaults to INGRESS_TRAFFIC_ALL. A misconfigured deployment that grants roles/run.invoker to allUsers would still expose the service to the public internet.
The variable's godoc spells out the gap explicitly:
ingress default INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER because the supporting external HTTPS load balancer + Cloud Armor stack is not provisioned by this environment yet…
Cloud Armor is now provisioned: terraform/environments/gcp/frontend.tf:24 references enable_cloud_armor, and github-prod.tfvars/github-staging.tfvars both set enable_cloud_armor = true.
Expected behaviour
When the LB stack is fully wired (verify), flip the ingress default to INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER so Cloud Run can be reached only via the LB (and therefore via Cloud Armor's WAF rules). Frontend tfvars already setting enable_cloud_armor = true should serve as the gating signal.
Steps to verify the gap
gcloud run services describe <svc> --region <region> --format='value(spec.template.metadata.annotations[run.googleapis.com/ingress])'
# Today: "all" (or unset, which defaults to all)
# After fix: "internal-and-cloud-load-balancing"
curl https://<direct-cloud-run-url>/health
# Today: 200 (request reaches the service)
# After fix: 403 (only LB can reach it)
Proposed fix
- Audit the LB stack in
terraform/environments/gcp/frontend.tf and the underlying GCP module — confirm Serverless NEG references the Cloud Run service correctly and Cloud Armor is attached to the backend service.
- Flip
ingress default to INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER in terraform/environments/gcp/variables.tf:223-227.
- Override in
dev.tfvars (and the example) to keep dev easy to hit directly.
- Update the variable's godoc — remove the "deferred" language.
- Update README to reflect the new defaults.
Edge cases
- Internal Cloud Scheduler jobs that today hit the direct Cloud Run URL must move to the LB or use IAM-authed invocation.
- Blue/green: ensure LB health checks target the right revision.
- Existing prod deployments that don't override the new default will break — coordinate the flip with a release-note callout.
References
- File:
terraform/environments/gcp/variables.tf:223-244 (variable + godoc spelling out the deferred state).
- Frontend LB wiring:
terraform/environments/gcp/frontend.tf:24.
- Tfvars enabling Cloud Armor:
github-prod.tfvars:71, github-staging.tfvars:70.
- Known-issue doc:
known_issues/19_tf_env_gcp.md → "MEDIUM: Cloud Run publicly reachable".
Severity
Medium — defence-in-depth gap. cloud_run_allow_unauthenticated=false provides IAM-level auth today; flipping ingress adds a network-layer guard so a misconfigured IAM binding can't blow the door open.
Effort
Medium — flip + tfvar overrides + audit LB wiring + release-notes coordination.
Summary
GCP Cloud Run's
cloud_run_allow_unauthenticateddefault was flipped tofalse, but the companioningressdefault still allows public traffic (INGRESS_TRAFFIC_ALL). The plan to flip both together was deferred because the supporting external HTTPS Load Balancer + Cloud Armor wasn't provisioned by the env. Cloud Armor is now wired in (enable_cloud_armorper tfvars,frontend.tfreferences the LB module) — time to revisit whether the ingress default can move.Captured in:
known_issues/19_tf_env_gcp.md("MEDIUM: Cloud Run publicly reachable — RESOLVED (default flipped; ingress change deferred)").Current behaviour
terraform/environments/gcp/variables.tf:229—cloud_run_allow_unauthenticateddefaults tofalse(auth required at IAM level), but the same file'singressvariable still defaults toINGRESS_TRAFFIC_ALL. A misconfigured deployment that grantsroles/run.invokertoallUserswould still expose the service to the public internet.The variable's godoc spells out the gap explicitly:
Cloud Armor is now provisioned:
terraform/environments/gcp/frontend.tf:24referencesenable_cloud_armor, andgithub-prod.tfvars/github-staging.tfvarsboth setenable_cloud_armor = true.Expected behaviour
When the LB stack is fully wired (verify), flip the
ingressdefault toINGRESS_TRAFFIC_INTERNAL_LOAD_BALANCERso Cloud Run can be reached only via the LB (and therefore via Cloud Armor's WAF rules). Frontend tfvars already settingenable_cloud_armor = trueshould serve as the gating signal.Steps to verify the gap
Proposed fix
terraform/environments/gcp/frontend.tfand the underlying GCP module — confirm Serverless NEG references the Cloud Run service correctly and Cloud Armor is attached to the backend service.ingressdefault toINGRESS_TRAFFIC_INTERNAL_LOAD_BALANCERinterraform/environments/gcp/variables.tf:223-227.dev.tfvars(and the example) to keep dev easy to hit directly.Edge cases
References
terraform/environments/gcp/variables.tf:223-244(variable + godoc spelling out the deferred state).terraform/environments/gcp/frontend.tf:24.github-prod.tfvars:71,github-staging.tfvars:70.known_issues/19_tf_env_gcp.md→ "MEDIUM: Cloud Run publicly reachable".Severity
Medium — defence-in-depth gap.
cloud_run_allow_unauthenticated=falseprovides IAM-level auth today; flippingingressadds a network-layer guard so a misconfigured IAM binding can't blow the door open.Effort
Medium — flip + tfvar overrides + audit LB wiring + release-notes coordination.