Cloud Run ingress 'Requires Authentication' — 401 when invoked
curl to the Cloud Run URL returns 401 Unauthorized
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)'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.invokerMake 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.
curl -i https://<SERVICE>-<HASH>-<REGION>.run.app/Confirm the 401 with no credentials
gcloud run services get-iam-policy <SERVICE> --region <REGION> --format=jsonRead current invoker bindings
gcloud run services add-iam-policy-binding <SERVICE> --region <REGION> --member=allUsers --role=roles/run.invokerAllow public invocation (or bind specific SAs otherwise)
curl -i https://<SERVICE>-<HASH>-<REGION>.run.app/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.
Related runbooks
Same stack, same failure family — worth a skim.
gcloud run services describe shows latest revision in state not serving
Role was just granted but calls still fail with Permission Denied
Commands marked READ CHANGE DESTRUCTIVE — never run DESTRUCTIVE commands against production data you cannot restore. Copy → verify → execute.