This tutorial demonstrates using Istio to authorize access to the services that you deploy on Cloud Run for Anthos.
Cloud Run provides a developer-focused experience for deploying and serving apps and functions. Cloud Run runs services either in a fully managed environment, or in a Google Kubernetes Engine (GKE) cluster, called Cloud Run for Anthos.
The developer experience is the same in both environments, but the capabilities of the underlying platforms differ.
Cloud Run for Anthos doesn't use Identity and Access Management (IAM) to grant permissions to invoke services. Instead, you use Istio to implement authentication and authorization. In this tutorial, you use Istio authentication and authorization policies to help you to secure a Cloud Run for Anthos sample service.
The authentication and authorization policies specify which identities (IAM service accounts and users) can invoke the sample service.
In this tutorial, you implement authentication and authorization for clients running outside the GKE cluster.
Objectives
- Create a GKE cluster with Cloud Run enabled.
- Deploy a sample service to Cloud Run for Anthos.
- Create an IAM service account.
- Create an Istio authentication policy.
- Create an Istio authorization policy.
- Test the solution.
Costs
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
-
Sign in to your Google Account.
If you don't already have one, sign up for a new account.
-
In the Google Cloud Console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Cloud project. Learn how to confirm that billing is enabled for your project.
- Enable the Google Kubernetes Engine API, the Cloud Run API, and the
Cloud APIs.
Enable the APIs - In the Cloud Console, go to Cloud Shell.
Go to Cloud Shell
At the bottom of the Cloud Console, a Cloud Shell session opens and displays a command-line prompt. Cloud Shell is a shell environment with the Cloud SDK already installed, including thegcloud
command-line tool, and with values already set for your current project. It can take a few seconds for the session to initialize. You use Cloud Shell to run all the commands in this tutorial.
Setting up the environment
Define an environment variables and
gcloud
tool default for the Compute Engine zone that you want to use for this tutorial:ZONE=us-central1-f gcloud config set compute/zone $ZONE
You can change the zone.
Create a GKE cluster with the Cloud Run add-on:
CLUSTER=cloud-run-gke-invoker-tutorial gcloud beta container clusters create $CLUSTER \ --addons HorizontalPodAutoscaling,HttpLoadBalancing,CloudRun \ --enable-ip-alias \ --enable-stackdriver-kubernetes \ --machine-type e2-standard-2 \ --release-channel regular
This tutorial requires GKE version 1.15.11-gke.9 and later, 1.16.8-gke.7 and later, or 1.17.4-gke.5 and later. New GKE clusters that use the
regular
release channel meet the version constraints.
Deploying a sample service
In Cloud Shell, create a namespace called
tutorial
in the GKE cluster:kubectl create namespace tutorial
You can change the name of the namespace.
Deploy a service called
sample
to Cloud Run for Anthos in thetutorial
namespace:gcloud run deploy sample \ --cluster $CLUSTER \ --cluster-location $ZONE \ --namespace tutorial \ --image gcr.io/knative-samples/simple-api \ --platform gke
This command creates a Knative Serving service object.
Cloud Run for Anthos exposes services on the external IP address of the Istio ingress gateway. Retrieve the external IP address and store it in an environment variable called
EXTERNAL_IP
and a file calledexternal-ip.txt
:export EXTERNAL_IP=$(./get-external-ip.sh | tee external-ip.txt) echo $EXTERNAL_IP
Verify that the sample service responds with
HTTP/1.1 200 OK
:curl -siH "Host: sample.tutorial.example.com" $EXTERNAL_IP | head -n1
Creating a service account
Create an IAM service account that you grant access to the sample service in a later step. Store the service account email address in an environment variable:
export SERVICE_ACCOUNT_EMAIL=$(gcloud iam service-accounts create \ cloudrun-gke-invoker-tutorial \ --display-name "Cloud Run for Anthos authorization tutorial service account" \ --format "value(email)")
This tutorial uses the service account name
cloudrun-gke-invoker-tutorial
. You can change the name.
Configuring Istio authentication and authorization
Create an Istio authentication policy:
kubectl apply -f authenticationpolicy.yaml
This authentication policy validates JSON Web Tokens (JWTs) in the
Authorization
header of incoming requests to thehttp2
andhttps
ports of the Istio ingress gateway. To satisfy the policy, the JWTs must be Google-issued and signed OpenID Connect (OIDC) ID tokens. For more information about ID token validation, see the Google Identity Platform documentation.The attribute
originIsOptional: true
means that the authentication policy accepts requests even if they do not contain a JWT that satisfies the specified constraints. The purpose of this authentication policy is to make attributes of the JWT available to the authorization policy that you create in the next step. The authorization policy decides whether to accept or reject requests.Create an Istio authorization policy called
invoke-tutorial
:envsubst < authorizationpolicy-invoker.tmpl.yaml | kubectl apply -f -
This authorization policy provides access to all workloads with hostnames that match
*.tutorial.example.com
, using any HTTP method and any URL path, to all requests that include a JWT issued and signed by Google (https://accounts.google.com
) to the service account identified by$SERVICE_ACCOUNT_EMAIL
with an audience (aud
) claim ofhttp://example.com
.If you change the Cloud Run for Anthos default domain, in your own environment, adjust the value of the
hosts
field to match your domain.It can take a moment for the authentication and authorization policies to take effect. Run the following command and wait until you see
HTTP/1.1 403 Forbidden
in the output:while sleep 2; do curl -siH "Host: sample.tutorial.example.com" $EXTERNAL_IP | head -n1 done
At first, you might see the output alternate between
HTTP/1.1 200 OK
andHTTP/1.1 403 Forbidden
because policy changes in Envoy and Istio are eventually consistent.When you see
HTTP/1.1 403 Forbidden
repeatedly, pressCtrl+C
to stop waiting.
Accessing the service
The authentication and authorization policies that you created require Google-issued and signed ID tokens. You can obtain tokens several different ways. The following lists four options in order of recommendation:
- If you're accessing the protected service from a Compute Engine instance, a GKE cluster, or another environment where you have access to the metadata server, use the Compute Engine metadata server.
- If it's available for your programming language, use a Google authentication client library.
- If you can't use a Google authentication client library, use the IAM Service Account Credentials API directly.
- If you want to test your service interactively, such as during
implementation,
use the
gcloud
command-line tool.
Use the Compute Engine metadata server
In Cloud Shell, create a Compute Engine instance (VM) and attach the service account you previously created:
VM=cloudrun-gke-invoker-tutorial-vm gcloud compute instances create $VM \ --scopes cloud-platform \ --service-account $SERVICE_ACCOUNT_EMAIL
This tutorial uses the instance name
cloudrun-gke-invoker-tutorial-vm
. You can change the name.Copy the file containing the public IP address of the Istio ingress gateway to the VM:
gcloud compute scp external-ip.txt $VM:~
Connect to the VM by using SSH:
gcloud compute ssh $VM
While in the SSH session, obtain an ID token from the Compute Engine metadata server:
ID_TOKEN=$(curl -s -H Metadata-Flavor:Google \ --data-urlencode format=full \ --data-urlencode audience=http://example.com \ http://metadata/computeMetadata/v1/instance/service-accounts/default/identity)
Send a request with the ID token to the sample Cloud Run for Anthos service:
curl -s -w"\n" -H "Host: sample.tutorial.example.com" \ -H "Authorization: Bearer $ID_TOKEN" $(cat external-ip.txt)
The output is:
OK
Leave the SSH session:
exit
Use a client library
The Google authentication client libraries for
Python,
Java,
Go,
and
Node.js
let you obtain ID tokens using convenient APIs. To use the Python
library and the IDTokenCredentials
class, follow these steps:
In Cloud Shell, create and download service account credentials:
gcloud iam service-accounts keys create service-account.json \ --iam-account $SERVICE_ACCOUNT_EMAIL
Create a Python virtual environment:
virtualenv -p python3 .venv
Activate the Python virtual environment for this terminal session:
source .venv/bin/activate
Install the dependencies:
pip install -r requirements.txt
Obtain an ID token and send a request to the sample Cloud Run for Anthos service:
python id_token_request.py http://$EXTERNAL_IP http://example.com \ Host:sample.tutorial.example.com
The output is:
OK
The Identity-Aware Proxy documentation has sample code that demonstrates how to obtain Google-issued ID tokens using other programming languages.
Using the IAM Service Account Credentials API
If there is no Google authentication client library available for your programming language with the ability to create ID tokens, you can use the IAM Service Account Credentials API directly:
Create a custom IAM role with permission to create ID tokens for service accounts:
gcloud iam roles create serviceAccountIdTokenCreator \ --project $GOOGLE_CLOUD_PROJECT \ --description "Impersonate service accounts to create OpenID Connect ID tokens" \ --permissions "iam.serviceAccounts.getOpenIdToken" \ --stage GA \ --title "Service Account ID Token Creator"
You can use the predefined Service Account Token Creator role (
iam.serviceAccountTokenCreator
) instead of creating a custom role, but this role provides extra permissions that aren't needed to create ID tokens with the Service Account Credentials API.Create a policy binding to grant yourself the custom role on the service account you previously created:
gcloud iam service-accounts add-iam-policy-binding $SERVICE_ACCOUNT_EMAIL \ --member user:$(gcloud config get-value account) \ --role projects/$GOOGLE_CLOUD_PROJECT/roles/serviceAccountIdTokenCreator
It can take a moment for the policy binding to take effect. The following command checks if the policy binding is in effect every five seconds. It will stop checking and return you to the terminal prompt when the policy binding is in effect:
status_code="" while [ "$status_code" != "200" ] ; do sleep 5 echo "Checking permissions" status_code=$(curl -s -w "%{http_code}" -o /dev/null -X POST \ -H "Authorization: Bearer $(gcloud auth print-access-token)" \ --data-urlencode audience=http://example.com \ --data-urlencode includeEmail=true \ "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/${SERVICE_ACCOUNT_EMAIL}:generateIdToken") done
Use the
generateIdToken
method of the IAM Service Account Credentials API to generate an ID token for the service account:ID_TOKEN=$(curl -s -X POST \ -H "Authorization: Bearer $(gcloud auth print-access-token)" \ --data-urlencode audience=http://example.com \ --data-urlencode includeEmail=true \ "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/${SERVICE_ACCOUNT_EMAIL}:generateIdToken" | jq -r '.token')
Send a request with the ID token to the sample Cloud Run for Anthos service:
curl -s -w"\n" -H "Host: sample.tutorial.example.com" \ -H "Authorization: Bearer $ID_TOKEN" $EXTERNAL_IP
The output is:
OK
Use the gcloud
command-line tool
To obtain Google-issued ID tokens, you can use the gcloud
command-line tool.
These tokens identify yourself or a service account, which can be useful for
testing services interactively.
Grant yourself the predefined Service Account Token Creator role on the service account you previously created:
gcloud iam service-accounts add-iam-policy-binding $SERVICE_ACCOUNT_EMAIL \ --member user:$(gcloud config get-value account) \ --role roles/iam.serviceAccountTokenCreator
It can take a moment for the policy binding to take effect. The following command checks if the policy binding is in effect every five seconds. It will stop checking and return you to the terminal prompt when the policy binding is in effect:
status_code="" while [ "$status_code" != "200" ] ; do sleep 3 echo "Checking permissions" status_code=$(curl -s -w "%{http_code}" -o /dev/null -X POST \ -H "Authorization: Bearer $(gcloud auth print-access-token)" \ -H "Content-Type: application/json" \ -d '{"payload": "{}"}' \ "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/${SERVICE_ACCOUNT_EMAIL}:signJwt") done
Impersonate the service account and obtain an ID token:
ID_TOKEN=$(gcloud auth print-identity-token \ --audiences http://example.com \ --impersonate-service-account $SERVICE_ACCOUNT_EMAIL \ --include-email)
Send a request with the ID token to the sample Cloud Run for Anthos service:
curl -s -w"\n" -H "Host: sample.tutorial.example.com" \ -H "Authorization: Bearer $ID_TOKEN" $EXTERNAL_IP
The output is:
OK
Cleaning up
To avoid incurring charges to your Google Cloud account for the resources used in this tutorial, either delete the project that contains the resources, or keep the project and delete the individual resources.
Delete the project
- In the Cloud Console, go to the Manage resources page.
- In the project list, select the project that you want to delete, and then click Delete.
- 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:
Delete the GKE cluster:
gcloud container clusters delete $CLUSTER --async --quiet
Delete the service account:
gcloud iam service-accounts delete $SERVICE_ACCOUNT_EMAIL --quiet
Delete the service account credentials file:
rm -f service-account.json
Delete the Compute Engine instance:
gcloud compute instances delete $VM --quiet
What's next
- Learn how to deploy internal services using Cloud Run for Anthos.
- Learn how to authenticate end users of Cloud Run for Anthos services using Istio and Identity Platform.
- If you want to create a website with interactive sign-in for users in your organization, see Google Sign-In for websites.
- Learn how to use a custom domain for services deployed to Cloud Run.
- Enable HTTPS on a Cloud Run for Anthos cluster.
- Read Cloud Run how-to guides.
- Try out other Google Cloud features for yourself. Have a look at our tutorials.