Securely Call Cloud Run Service From Anywhere

Enabling authentication for your Cloud Run application is easy ‒ a single mouse click (or parameter in your CI/CD) without writing any code. Calling this application from another is less straightforward. It may be easy when both a caller and called applications are hosted under the same identity in Google Cloud. In the rest of cases, it requires acquiring an identity token.

A problem begins with documentation. Sometimes it isn’t clear whether the described token is an identity token or access token. While the first is good for invoking endpoints of user’s applications on Google Cloud, the second is good only for calling Google APIs.

Another challenge is with examples that demonstrate getting an identity token from a metadata server available in Google Cloud VMs and other managed environments such as GKE or Cloud Run. However this method would not work anywhere else.

The following method lets you call a private Cloud Run service regardless whether the calling code runs in Google Cloud or elsewhere. This code example is in Python. Please leave a comment if you need a code snippet in another programming language.

SCOPE = 'https://your-cloud-run-service-url.run.app'

# acquire application default credentials
creds, _ = google.auth.default()
if isinstance(creds, Scoped):
    # add Cloud Run service scope if credentials support scoping
    scopes = [SCOPE] if creds.scopes is None else [SCOPE] + list(creds.scopes)
    creds = creds.with_scopes(scopes)
# validate ID token in credentials
if hasattr(creds, "id_token") and creds.id_token:
    return creds.id_token
else:
    # refresh ID token if missing
    auth_req = Request()
    try:
        creds.refresh(auth_req)
    except RefreshError as e:
        # ignore if ID token is refreshed without access token
        if not "No access token in response" in str(e):
            raise
    if hasattr(creds, "id_token") and creds.id_token:
        return creds.id_token
    elif audience:
        return id_token.fetch_id_token(auth_req, SCOPE)

The google.auth.default() call intelligently searches for application default credentials in the local environment. Then the code uses found credentials to validate and, if needed, to refresh the identity token. If the refreshing fails to get a valid identity token, the code fetches a new identity token from the metadata server which stores the credentials of the attached service account. The last part works only when the application is deployed on Google Cloud.

The SCOPE constant is a Cloud Run service URL and is used for a claim that the token is used to prove identity to Cloud Run service. The URL used for the scope should be original URL that Cloud Run creates for the service and not one used for load balancing or with custom domains.

This powerful chain of discovery works with both user identities and service account identities. The code returns the acquired identity token which you can use as a bearer token in the Authentication header of HTTP requests to a Cloud Run service. For the full end-to-end demonstration go to devrel-demos Github repository.

To try this code on your local machine, you only need to run one command:

gcloud auth application-default login

This securely stores your user credentials in a well-known location where the google.auth.default() call can find them.

This post is mirrored to Medium.