mediumFoundationSymptom-first#cloud run#auth#401#ingress#iam

Cloud Run ingress 'Requires Authentication' — 401 when invoked

curl to the Cloud Run URL returns 401 Unauthorized

Likely source:configurationsecurity

Focused incident mode — strips away everything but this runbook.

Symptoms

  • curl to the Cloud Run URL returns 401 Unauthorized
  • Downstream clients get 'The request is missing a valid API key' or 'Unauthenticated'
  • App works from the console proxy but not from external clients
  • Invokers in another project get 403/401 despite the URL being public

Cloud Run services are 'require authentication' by default. Decide per-service whether anonymous or authenticated SA invocation is correct — do not blanket-grant allUsers to everything.

Evidence to grab

Collect these artifacts before you change anything — they prove (or rule out) each cause.

  • Service URL and config

    gcloud run services describe <SERVICE> --region <REGION> --format='value(status.url)'
  • IAM policy on the service

    gcloud run services get-iam-policy <SERVICE> --region <REGION> --format=json

Diagnostic flow

Run the steps in order, marking each claim confirmed or refuted. The evidence you gather feeds the ranked causes below.

Guided decision tree is ready.

Steps with commands, expected output, and pass/fail branches.

Ranked root causes

Evidence checklist

  • curl without credentials returns 401
  • IAM policy has no allUsers invoker binding
  • Caller should not need a signed request

Confirm before fixing

gcloud run services get-iam-policy <SERVICE> --region <REGION> --flatten='bindings[].members' --filter='bindings.role=roles/run.invoker' --format='table(bindings.role,bindings.members)'
READ

List invoker members

Expected: allUsers present only if public access is configured

Fix

gcloud run services add-iam-policy-binding <SERVICE> --region <REGION> --member=allUsers --role=roles/run.invoker
CHANGE

Make the service publicly invocable (if that is intended)

Expected: Updated IAM policy for service [<SERVICE>].

Resolution runbook

Apply from top to bottom after the cause is confirmed. Review every command before running it — risk tags are shown on each.

1
curl -i https://<SERVICE>-<HASH>-<REGION>.run.app/
READ

Confirm the 401 with no credentials

2
gcloud run services get-iam-policy <SERVICE> --region <REGION> --format=json
READ

Read current invoker bindings

3
gcloud run services add-iam-policy-binding <SERVICE> --region <REGION> --member=allUsers --role=roles/run.invoker
CHANGE

Allow public invocation (or bind specific SAs otherwise)

4
curl -i https://<SERVICE>-<HASH>-<REGION>.run.app/
READ

Retest and confirm it no longer 401s

Expected: HTTP 200 from the service

Prevention

  • Set a default IAM policy for run.invoker per environment.
  • Document which services are public vs internal in the service specs.
  • Use the API key workflow for public, unauthenticated services.
  • Restrict ingress to VPC for internal services.

Commands marked READ CHANGE DESTRUCTIVE — never run DESTRUCTIVE commands against production data you cannot restore. Copy → verify → execute.