Secure Cloud Run with Pomerium
Protect an existing Cloud Run service by putting a standard Pomerium route in front of it. A Cloud Run service is just an HTTPS endpoint, so you secure it like any other upstream: point a route's to at the service URL and let Pomerium handle login and authorization. Where you can, keep the service private and let Pomerium send the signed Google authorization header Cloud Run expects.
Prerequisites
- A running Pomerium cluster. See the quickstart if you do not have one yet.
- A deployed Cloud Run service. Note its
*.run.appURL, which is the address Google assigns to the service. gcloudor IAM access to grantroles/run.invokeron that service.
Recommended: lock the service to Pomerium with serverless authentication
The most robust option is to keep the Cloud Run service private and have Pomerium send a signed Google authorization header on each request. Keep roles/run.invoker off allUsers, grant it to the service account Pomerium runs as, then enable serverless authentication on the route:
routes:
- from: https://hello.your-domain.example
to: https://hello-abcdef-uc.a.run.app
enable_google_cloud_serverless_authentication: true
policy:
- allow:
and:
- domain:
is: your-company.example
The from value is the hostname users visit; the to value is the Cloud Run service's *.run.app URL. With the service private, only Pomerium's service account can invoke it, so requests cannot bypass Pomerium's policy.
When Pomerium runs in GCP it picks up the ambient service account credentials automatically. To supply credentials explicitly, set the Google Cloud Serverless Authentication Service Account. See the Enable Google Cloud Serverless Authentication route reference for details.
This pattern also works for other GCP serverless products that accept the same authorization header, such as Cloud Functions and App Engine.
enable_google_cloud_serverless_authentication is a Core and Enterprise route setting. The Kubernetes Ingress Controller does not support it.
Alternative: a service that allows unauthenticated invocations
If the Cloud Run service already permits unauthenticated invocations, point a route at it like any other HTTPS upstream:
routes:
- from: https://hello.your-domain.example
to: https://hello-abcdef-uc.a.run.app
policy:
- allow:
and:
- domain:
is: your-company.example
See the from and to route references for the full set of options.
A Cloud Run service open to allUsers stays reachable on its public *.run.app URL, so anyone who learns that URL can bypass Pomerium's policy entirely. Prefer the serverless authentication approach above, or otherwise ensure the service is only reachable through Pomerium.
Verify the setup
Browse to your from hostname, for example https://hello.your-domain.example. You should be sent through your identity provider's login and then land on the Cloud Run service. Requesting the *.run.app URL directly should fail when the service is private. To confirm the deny path, sign in as a user your policy excludes and open the from hostname. Pomerium should deny access, so no authorization header is signed and the request never reaches Cloud Run.
Common failure modes
403 Forbiddenfrom Cloud Run after you sign in through Pomerium. Pomerium reached the service but Google rejected the call. Confirm the route hasenable_google_cloud_serverless_authentication: trueand that the service account Pomerium runs as holdsroles/run.invokeron that service. IAM grants can take a few minutes to propagate, so give a fresh grant time before retrying.- Direct
*.run.apprequests still succeed. The service still allows unauthenticated invocations, so the public Cloud Run URL bypasses Pomerium. Removerun.invokerfromallUsersand rely on the serverless authentication route above. could not find default credentialsor a similar auth error in Pomerium's logs. Pomerium isn't running on GCP and has no ambient service account. Set the Google Cloud Serverless Authentication Service Account explicitly.
Security considerations
- Keep the service private. The strongest control is removing
run.invokerfromallUsersand granting it only to Pomerium's service account, so the*.run.appURL cannot be invoked around Pomerium's policy. - Grant least privilege. Give Pomerium's service account only
roles/run.invokeron the specific services it fronts, not a broader project-wide role. - Scope the route policy. Cloud Run authorizes Pomerium's service account; Pomerium policy decides which signed-in users can use the route.
Pass identity to your application
If your service is not on GCP, or you want it to read the end user's identity rather than rely on the GCP authorization header, enable pass identity headers on the route. Pomerium then forwards the authenticated user's identity to the upstream. See getting the user's identity for how to consume it.
Next steps
- Routes reference for the full route configuration surface.
- Quickstart to stand up Pomerium if you have not already.
- Getting the user's identity to consume identity in your application.