Use workload identity with Google Cloud

Workload identity enables you to assign distinct, fine-grained identities and authorization for each application in your cluster. Workload identity is the recommended way for applications running within GKE on Azure to access Google Cloud services. For more information, see Workload identity.

This topic describes how to use workload identity to connect to Google Cloud services from your workloads.

Configure a Google Cloud service account

In this section, you create a Google Cloud service account (GSA) with limited permissions to access Google Cloud services.

Get your workload identity pool and provider

To configure workload identity, you must have the values for your cluster's identity provider URI and workload identity pools.

  1. Determine the workload identity pool for your cluster:

    All GKE clusters have an identity provider created in the workload identity pool PROJECT_ID.svc.id.goog. To get your cluster's identity pool name, use the Google Cloud CLI:

    gcloud container azure clusters describe CLUSTER_NAME \
        --location=GOOGLE_CLOUD_LOCATION \
        --format='value(workloadIdentityConfig.workloadPool)'
    

    Replace the following:

    • CLUSTER_NAME with the name of your cluster.
    • GOOGLE_CLOUD_LOCATION with the name of the Google Cloud location that manages your cluster

    The output includes the name of your cluster's identity pool. Save this value. You'll need it later.

  2. Determine the identity provider for your cluster.

    To find your cluster's identity provider name, use the Google Cloud CLI:

    gcloud container azure clusters describe CLUSTER_NAME \
        --location=GOOGLE_CLOUD_LOCATION \
        --format='value(workloadIdentityConfig.identityProvider)'
    

    Replace the following:

    • CLUSTER_NAME
    • GOOGLE_CLOUD_LOCATION

    The output includes the name of your cluster's identity provider. Save this value. You'll need it later.

Create a Google Cloud service account

To create a Google Cloud service account (GSA), grant permissions to it, and add an IAM policy binding to the GSA, do these steps:

  1. Create the GSA with the Google Cloud CLI:

    gcloud iam service-accounts create GSA_NAME --project=PROJECT_ID
    

    Replace the following:

    • GSA_NAME: the name of the GSA for your application.
    • PROJECT_ID: the GSA's Google Cloud project.
  2. Add an IAM binding to allow the GSA to access services.

    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member serviceAccount:GSA_NAME@PROJECT_ID.iam.gserviceaccount.com \
        --role IAM_ROLE
    

    Replace the following:

    • GSA_NAME: the name of the GSA for your application
    • PROJECT_ID: the project ID for the GSA
    • IAM_ROLE: the IAM role to grant to the GSA

    In this example, we will use the role roles/compute.viewer, which allows read-only access to compute services:

    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member serviceAccount:GSA_NAME@PROJECT_ID.iam.gserviceaccount.com \
        --role roles/compute.viewer
    
  3. Grant permissions for your Kubernetes service account (KSA) to impersonate the GSA. You do this by adding an IAM policy binding with the role roles/iam.workloadIdentityUser:

    gcloud iam service-accounts add-iam-policy-binding GSA_NAME@PROJECT_ID.iam.gserviceaccount.com \
        --member serviceAccount:PROJECT_ID.svc.id.goog[NAMESPACE//KSA_NAME] \
        --role roles/iam.workloadIdentityUser
    

    Replace the following:

    • GSA_NAME
    • PROJECT_ID
    • NAMESPACE: the Kubernetes Namespace for the application
    • KSA_NAME: the KSA to use for the application

Deploy a sample application

In this section, you deploy a sample application that accesses the Compute Engine API. To Use this sample, your service account must have the roles/compute.viewer IAM role granted to it. To deploy the sample application, follow these steps:

  1. Copy the following manifest into a file named workload-identity-sample.yaml:

    apiVersion: v1
    kind: Namespace
    metadata:
      name: NAMESPACE
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: KSA_NAME
      namespace: NAMESPACE
    automountServiceAccountToken: false
    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: cloud-sdk-config
      namespace: NAMESPACE
    data:
      config: |
        {
          "type": "external_account",
          "audience": "identitynamespace:PROJECT_ID.svc.id.goog:IDENTITY_PROVIDER",
          "service_account_impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/GSA_NAME@PROJECT_ID.iam.gserviceaccount.com:generateAccessToken",
          "subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
          "token_url": "https://sts.googleapis.com/v1/token",
          "credential_source": {
            "file": "/var/run/secrets/tokens/gcp-ksa/token"
          }
        }
    ---
    apiVersion: v1
    kind: Pod
    metadata:
      name: cloud-sdk-example
      namespace: NAMESPACE
    spec:
      serviceAccount: KSA_NAME
      containers:
      - name: cloud-sdk
        image: gcr.io/google.com/cloudsdktool/cloud-sdk:latest
        command:
        - /bin/bash
        - -c
        - 'set -eu -o pipefail; while true; do gcloud compute zones list --filter="name ~ us-central1-*"; sleep 5; done'
        env:
        - name: CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE
          value: /var/run/secrets/tokens/gcp-ksa/google-application-credentials.json
        - name: CLOUDSDK_CORE_PROJECT
          value: PROJECT_ID
        volumeMounts:
        - name: gcp-ksa
          mountPath: /var/run/secrets/tokens/gcp-ksa
          readOnly: true
      volumes:
      - name: gcp-ksa
        projected:
          defaultMode: 420
          sources:
          - serviceAccountToken:
              audience: PROJECT_ID.svc.id.goog
              expirationSeconds: 86400
              path: token
          - configMap:
              name: cloud-sdk-config
              optional: false
              items:
              - key: config
                path: google-application-credentials.json
    

    Replace the following:

    • PROJECT_ID
    • NAMESPACE
    • KSA_NAME
    • GSA_NAME
    • IDENTITY_PROVIDER with the name of the identity provider for your cluster.
  2. Apply the manifest to your cluster

    kubectl apply -f workload-identity-sample.yaml
    
  3. Verify the sample application is working, check the Pod's logs:

    kubectl logs -f cloud-sdk-example -n NAMESPACE
    

    Replace the following:

    • NAMESPACE

    If the Pod is successful in accessing the Google Cloud compute API, you will see output that looks similar to this:

    NAME           REGION       STATUS  NEXT_MAINTENANCE  TURNDOWN_DATE
    us-central1-c  us-central1  UP
    us-central1-a  us-central1  UP
    us-central1-f  us-central1  UP
    us-central1-b  us-central1  UP
    

Cleaning up

  1. Delete the sample application

    kubectl delete -f manifest.yaml
    
  2. Remove the IAM policy binding from the Google Cloud service account

    gcloud iam service-accounts remove-iam-policy-binding \
        GSA_NAME@PROJECT_ID.iam.gserviceaccount.com \
        --member serviceAccount:PROJECT_ID.svc.id.goog[NAMESPACE//KSA_NAME] \
        roles/iam.workloadIdentityUser
    

    Replace the following:

    • GSA_NAME
    • PROJECT_ID
    • NAMESPACE
    • KSA_NAME
  3. Remove the IAM policy binding from the project

    gcloud projects remove-iam-policy-binding PROJECT_ID \
        --member serviceAccount:GSA_NAME@PROJECT_ID.iam.gserviceaccount.com \
        --role roles/compute.viewer
    

    Replace the following:

    • GSA_NAME
    • PROJECT_ID
  4. Delete the Google Cloud service account

    gcloud iam service-accounts delete \
       GSA_NAME@PROJECT_ID.iam.gserviceaccount.com
    

    Replace the following:

    • GSA_NAME
    • PROJECT_ID

What's next