Authenticating end users of Cloud Run for Anthos services using Istio and Identity Platform

This tutorial shows how to authenticate end users of applications deployed to Cloud Run for Anthos using Istio authentication policies and Identity Platform. Using Istio to authenticate means that authentication logic doesn't need to be part of the application code. This separation lets different teams be responsible for application code and authentication policy, and authentication policies can apply across multiple applications or services.


Cloud Run for Anthos provides a developer-focused experience for deploying and serving applications and functions running on GKE. It offers development teams a serverless experience, supporting autoscaling based on demand, routing and traffic management for blue-green deployments, and more. Cloud Run for Anthos builds on the open source projects Istio and Knative, and it integrates with Google Cloud products such as Cloud Logging.

Istio can authenticate incoming requests by validating JSON Web Tokens (JWT) according to authentication policies. The authentication policies can apply to all services in a namespace, or to specific named services. A policy can include and exclude specific HTTP request paths, for example, to allow unauthenticated access to public website assets and health check endpoints. In this tutorial, the Istio ingress gateway enforces the authentication policy.

The following diagram shows the authentication flow that this tutorial is based on.

Istio authenticates incoming requests

This tutorial uses Identity Platform to sign in end users, but you can adapt the solution to other providers that support OpenID Connect, such as Google Sign-In, Firebase Authentication, third-party offerings such as Auth0, Gluu, Okta, Ping Identity, or your own deployment of an OpenID Connect implementation.


  • Create a GKE cluster with the Cloud Run add-on.
  • Set up Identity Platform.
  • Deploy a sample application that consists of a public frontend and backend API.
  • Add an authentication policy for the backend API.
  • Verify authentication.


This tutorial uses the following billable components of Google Cloud:

To generate a cost estimate based on your projected usage, use the pricing calculator. New Google Cloud users might be eligible for a free trial.

When you finish this tutorial, you can avoid continued billing by deleting the resources you created. For more information, see Cleaning up.

Before you begin

  1. Sign in to your Google Account, or if you don't have one, sign up for a new account.
  2. In the Google Cloud Console, go to the project selector page.

    Go to project selector

  3. Select or create a Google Cloud project.

  4. Make sure that billing is enabled for your Cloud project. Learn how to confirm that billing is enabled for your project.

  5. Enable the Cloud Build, Cloud Run, Container Analysis, and Google Kubernetes Engine APIs, and the Cloud APIs.


Initializing the environment

In this section, you set environment variables and gcloud defaults that you use later in the tutorial.

  1. In the Cloud Console, from the Select a project drop-down, select the project you want to use.

  2. Open Cloud Shell:

    GO TO Cloud Shell

    You use Cloud Shell to run all the commands in this tutorial.

  3. Define environment variables and gcloud defaults for the Compute Engine zone and GKE cluster name you want to use for this tutorial:

    gcloud config set compute/zone $ZONE
    gcloud config set run/cluster $CLUSTER
    gcloud config set run/cluster_location $ZONE

    You can change the zone and the cluster name to suit your needs.

Create GKE cluster with Cloud Run enabled

  • Create a GKE cluster with the Cloud Run add-on:

    gcloud beta container clusters create $CLUSTER \
        --addons HorizontalPodAutoscaling,HttpLoadBalancing,CloudRun \
        --enable-ip-alias \
        --machine-type n1-standard-2

Find the public IP address

Cloud Run for Anthos exposes external services on the public IP address of the Istio ingress gateway.

  1. Check the status of creating an external IP address for the istio-ingress Kubernetes Service:

    kubectl get services istio-ingress -n gke-system --watch

    Wait until the EXTERNAL-IP value changes from <pending> to an IP address. If you get a NotFound error, wait a minute and run the command again. To stop waiting, press Control+C.

  2. Create an environment variable to store the public IP address of the Istio ingress gateway:

    export EXTERNAL_IP=$(kubectl get services istio-ingress \
        --namespace gke-system \
        --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
  3. Display the public IP address of the Istio ingress gateway. You need this address later.

    echo $EXTERNAL_IP

Note: In this tutorial, you access the services using an IP address, and using unencrypted HTTP. For a production setup, we recommend that you do both of the following:

  • Create a DNS A record for your domain name and set its value to the public IP address of the Istio ingress gateway. If you do so, replace $EXTERNAL_IP in the rest of this tutorial with the domain name of the DNS A record. If you use Cloud DNS, follow the Quickstart guide. If you use another provider, refer to its documentation.
  • Enable HTTPS for Cloud Run for Anthos services.

Set up Identity Platform

  1. Leave Cloud Shell open and visit Google Cloud Marketplace to enable Identity Platform in a new web browser window.

    Go to Identity Platform on Google Cloud Marketplace

  2. From the Select a project drop-down, select the Google Cloud project where you want to set up Identity Platform. You can set up the GKE cluster and Identity Platform in separate Google Cloud projects. For simplicity, use the same project in this tutorial.

  3. Click Enable Identity Platform.

    You are now on the Identity Platform > Providers page in the Cloud Console.

  4. On the Providers page, click Add a provider.

  5. From the Select a provider drop-down, scroll down and select Email / Password. For your own application, you can choose the providers you want to enable.

  6. Ensure that Enabled is selected.

  7. Clear Allow passwordless login.

  8. Click Save.

  9. Navigate to the Identity Platform > Settings page.

  10. Click on the Security tab.

  11. Click Add domain. This opens the Add authorized domain dialog.

  12. In the Domain box, enter the public IP address of the Istio ingress gateway from the previous section ($EXTERNAL_IP).

  13. Click Add. This closes the dialog. The IP address you entered is in the Authorized Domains table.

  14. On the Identity Platform > Settings page, click Save.

Create a test user

  1. In the Cloud Console, navigate to the Identity Platform > Users page.
  2. Click Add user to add a test user for this tutorial. This opens the Add user dialog.
  3. In the Email box, enter the email address of an end user. For testing, this email address doesn't have to be real. For this tutorial, use
  4. In the Password box, enter a password for the test user. Remember this password, because you need it later.
  5. Click Add to finish adding the user. This closes the dialog and takes you back to the Identity Platform > Users page.

Create a sample application

Deploy a sample application that has two services. One service is a public frontend user interface; the other service is a backend API.

  1. In the Identity Platform > Users page, click the Application setup details link on the right side of the window. This opens the Configure your application dialog.

  2. Highlight and copy the value of apiKey to your clipboard (Control+C on Chrome OS/Linux/Windows, Cmd+C on macOS).

  3. Click Close to close the Configure your application dialog.

  4. In Cloud Shell, create an environment variable to store apiKey, where api-key is the apiKey from the Configure your application dialog:

    export AUTH_APIKEY=api-key
  5. Create an environment variable for authDomain:

    export AUTH_DOMAIN=$
  6. Clone the Cloud Run samples repository from GitHub:

    git clone
  7. Switch to the directory containing the files for this tutorial:

    cd cloud-run-samples/identity-platform/gke
  8. Substitute the Identity Platform variables in the frontend JavaScript file:

    envsubst < frontend/index.template.js > frontend/index.js

Deploy the sample application

  1. Use Cloud Build to create two container images for the sample application, one for the frontend and one for the backend:

    gcloud builds submit -t$GOOGLE_CLOUD_PROJECT/cloud-run-gke-auth-frontend frontend
    gcloud builds submit -t$GOOGLE_CLOUD_PROJECT/cloud-run-gke-auth-backend backend

    Cloud Build stores the images in Container Registry.

  2. In the GKE cluster, create two namespaces called public and api:

    kubectl create namespace public
    kubectl create namespace api
  3. Deploy the frontend container image to Cloud Run for Anthos as a service in the public namespace:

    gcloud run deploy frontend \
        --namespace public \
        --image$GOOGLE_CLOUD_PROJECT/cloud-run-gke-auth-frontend \
        --platform gke
  4. Deploy the backend container image to Cloud Run for Anthos as a service in the api namespace:

    gcloud run deploy backend \
        --namespace api \
        --image$GOOGLE_CLOUD_PROJECT/cloud-run-gke-auth-backend \
        --platform gke
  5. Create an Istio virtual service that routes requests by URI path:

    kubectl apply -f istio/virtualservice.yaml

    This virtual service routes requests where the URI path starts with /api/ to the backend API, and routes all other requests to the frontend user interface.

    kind: VirtualService
      name: cloud-run-gke-auth
      - gke-system-gateway.knative-serving.svc.cluster.local
      - "*"
      - match:
        - uri:
            prefix: "/api/"
          authority: backend.api.svc.cluster.local
        - destination:
            host: cluster-local-gateway.gke-system.svc.cluster.local
      - match:
        - uri:
            prefix: "/"
          authority: frontend.public.svc.cluster.local
        - destination:
            host: cluster-local-gateway.gke-system.svc.cluster.local
  6. Verify that unauthenticated requests to the backend API succeed:

    curl -si $EXTERNAL_IP/api/secure.json | head -n1

    If the output is not HTTP/1.1 200 OK, wait a minute and try again.

Add an Istio authentication policy

  1. Create an Istio authentication policy:

    envsubst < istio/authenticationpolicy.template.yaml | kubectl apply -f -
    kind: Policy
      name: api-origin-auth
      namespace: gke-system
      - name: istio-ingress
        - number: 80
        - number: 443
      - jwt:
          issuer: "$GOOGLE_CLOUD_PROJECT"
          jwksUri: ""
          - excluded_paths:
            - exact: /api/healthz
            - prefix: /api/
      principalBinding: USE_ORIGIN

    This policy authenticates requests where the URI path starts with /api/, except the path /api/healthz. Because of the routing rules in the Istio virtual service deployed in the previous section, this policy authenticates requests to the backend API.

  2. It can take a moment for the policy to take effect. Run the following command and wait until you see HTTP/1.1 401 Unauthorized printed to the console:

    while sleep 2; do
      curl -si $EXTERNAL_IP/api/secure.json | head -n1

    Initially, you might see the output alternate between HTTP/1.1 200 OK and HTTP/1.1 401 Unauthorized. This is due to eventual consistency in Istio and Envoy Proxy.

    When you see only HTTP/1.1 401 Unauthorized being printed to the console, press Control+C to stop waiting.

Test the solution

  1. Open a browser window to the address http://$EXTERNAL_IP/api/secure.json, where $EXTERNAL_IP is the public IP address of the Istio ingress gateway you found in the section Find the public IP address.

    This is a request directly to the backend API. The browser window shows Origin authentication failed because the request didn't include credentials that satisfied the Istio authentication policy.

  2. Open a browser window to the address $EXTERNAL_IP. You should see a sign-in form.

  3. Sign in as the test user you created in the section Create a test user.

    The page shows the test user email address and the text The secret message is: Hello World. It can take a moment for the message to appear.

    The browser fetches the message with an HTTP request to the backend API (/api/secure.json), using a token obtained from Identity Platform when signing in. Inspect the file frontend/index.js to view the implementation, and refer to the FirebaseUI library for further documentation.


If you run into problems with this tutorial, we recommend that you review these documents:

Clean up

To avoid incurring charges to your Google Cloud account for the resources used in this tutorial:

  1. In the Cloud Console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

Delete the resources

If you want to keep the Google Cloud project you used in this tutorial, delete the individual resources:

  1. Delete the GKE cluster:

    gcloud container clusters delete $CLUSTER --async --quiet
  2. Delete the sample application container images in Container Registry:

    gcloud container images delete$GOOGLE_CLOUD_PROJECT/cloud-run-gke-auth-frontend \
        --force-delete-tags --quiet
    gcloud container images delete$GOOGLE_CLOUD_PROJECT/cloud-run-gke-auth-backend \
        --force-delete-tags --quiet
  3. Delete the Email / Password identity provider in Identity Platform.

    1. In the Cloud Console, go to the Identity Platform > Providers page:


    2. Find the Email / Password identity provider in the table of providers and click .

    3. In the dialog that appears, click Delete to confirm.

  4. Delete the test user.

    1. Go to the Identity Platform > Users page:


    2. Find in the table of users and click .

    3. In the dialog that appears, click Delete to confirm.

  5. Delete the authorized domain.

    1. Go to the Identity Platform > Settings page:


    2. In the table of authorized domains, find the IP address you added in the section Set up Identity Platform ($EXTERNAL_IP) and click .

    3. Click Save.

What's next