How to Configure GKE Workload Identity for Secure Authentication

GKE Workload Identity maps a Kubernetes Service Account (KSA) to a Google IAM Service Account (GSA) so that pods authenticate to Google Cloud APIs using short-lived OAuth tokens instead of long-lived JSON keys.

You can configure GKE Workload Identity to eliminate static service-account keys and enforce zero-trust authentication for workloads running on GKE. According to the google/skills repository, the golden-path GKE configuration enforces Workload Identity by default as a Day-0 security requirement. This guide walks through the exact cluster settings, IAM bindings, and hardened pod manifest patterns found in the repository's source files, including cross-references from skills/cloud/gke-basics/SKILL.md and skills/cloud/google-cloud-recipe-auth/SKILL.md.

Prerequisites: Enable Workload Identity on the Cluster

Before you map identities, the cluster must expose the Workload Identity federation layer. The reference file skills/cloud/gke-basics/references/gke-security.md specifies two required settings:

  • workloadIdentityConfig.workloadPool — Set this to <PROJECT_ID>.svc.id.goog. This pool name establishes the identity namespace that GKE uses to federate Kubernetes tokens to Google Cloud.
  • nodeConfig.workloadMetadataConfig.mode — Set this to GKE_METADATA. This blocks the legacy Compute Engine metadata server on the node and forces pods to use the GKE metadata server, which enforces Workload Identity checks.

Step-by-Step Instructions

1. Create a Google Service Account

Create the GSA that your pods will impersonate. This account should be dedicated to a specific workload or application boundary.

gcloud iam service-accounts create my-gsa \
  --project $PROJECT_ID \
  --display-name "Workload Identity SA"

2. Grant Cloud IAM Roles to the GSA

Authorize the GSA to access Google Cloud resources. The example below grants read-only access to Cloud Storage; replace the role with the least-privilege roles your workload requires.

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member "serviceAccount:my-gsa@$PROJECT_ID.iam.gserviceaccount.com" \
  --role "roles/storage.objectViewer"

3. Create a Kubernetes Service Account

Create the KSA in the target namespace. The pod will run with this identity, and GKE will map it to the GSA you created in step 1.

kubectl create namespace my-app
kubectl create serviceaccount my-ksa --namespace my-app

4. Bind the KSA to the GSA

Grant the roles/iam.workloadIdentityUser role on the GSA to the KSA member. This binding is the critical trust link that permits the GKE metadata server to exchange Kubernetes tokens for Google Cloud tokens.

gcloud iam service-accounts add-iam-policy-binding \
  my-gsa@$PROJECT_ID.iam.gserviceaccount.com \
  --role roles/iam.workloadIdentityUser \
  --member "serviceAccount:$PROJECT_ID.svc.id.goog[my-app/my-ksa]"

5. Annotate the KSA

Apply the iam.gke.io/gcp-service-account annotation to the KSA. GKE reads this annotation to know which GSA the pod should impersonate.

kubectl annotate serviceaccount my-ksa \
  --namespace my-app \
  iam.gke.io/gcp-service-account=my-gsa@$PROJECT_ID.iam.gserviceaccount.com

6. Deploy a Hardened Pod

Use a manifest that references the KSA, disables unnecessary token automount, and applies strict security contexts. The example below follows the pattern from skills/cloud/gke-basics/assets/workload-identity-pod.yaml and includes the iam.gke.io/gke-metadata-server-enabled node selector to ensure the pod schedules on nodes that support Workload Identity.

apiVersion: v1
kind: Pod
metadata:
  name: workload-identity-test
  namespace: my-app
spec:
  serviceAccountName: my-ksa
  automountServiceAccountToken: false
  containers:
  - name: test
    image: gcr.io/google.com/cloudsdktool/cloud-sdk:slim
    command: ["sleep", "infinity"]
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities:
        drop: ["ALL"]
  nodeSelector:
    iam.gke.io/gke-metadata-server-enabled: "true"
  securityContext:
    runAsNonRoot: true
    runAsUser: 65532
    seccompProfile:
      type: RuntimeDefault

7. Verify Authentication Inside the Pod

Exec into the running pod and run gcloud auth list. When Workload Identity is configured correctly, the output shows the GSA email instead of the node’s default service account.

kubectl exec -it workload-identity-test -n my-app -- \
  gcloud auth list --format="value(account)"

# Expected output: my-gsa@$PROJECT_ID.iam.gserviceaccount.com

Summary

  • You configure GKE Workload Identity by mapping a Kubernetes Service Account to a Google IAM Service Account through the roles/iam.workloadIdentityUser binding and the iam.gke.io/gcp-service-account annotation.
  • The cluster must define workloadIdentityConfig.workloadPool and use nodeConfig.workloadMetadataConfig.mode: GKE_METADATA to enable federation and block legacy metadata access, as documented in skills/cloud/gke-basics/references/gke-security.md.
  • The pod manifest should reference the KSA, use strict security contexts, and select nodes with the iam.gke.io/gke-metadata-server-enabled: "true" label.
  • Successful verification shows the GSA email from inside the pod, confirming that no local service-account keys are present.

Frequently Asked Questions

What is GKE Workload Identity?

GKE Workload Identity is an authentication mechanism that lets a Kubernetes Service Account impersonate a Google IAM Service Account. As implemented in the google/skills repository, GKE automatically exchanges the pod's short-lived Kubernetes token for a Google-signed OAuth 2.0 access token, removing the need to store long-lived JSON keys inside the cluster.

Why does the repository set nodeConfig.workloadMetadataConfig.mode to GKE_METADATA?

The skills/cloud/gke-basics/references/gke-security.md file sets this mode to block access to the legacy Compute Engine metadata server on nodes. This forces pods to use the GKE metadata server, which enforces Workload Identity checks and prevents pods from accidentally inheriting the underlying node's default credentials.

How is the KSA-to-GSA mapping established?

The mapping requires two distinct actions. First, you bind the Google Service Account by granting roles/iam.workloadIdentityUser to the member serviceAccount:$PROJECT_ID.svc.id.goog[NAMESPACE/KSA]. Second, you annotate the Kubernetes Service Account with iam.gke.io/gcp-service-account=GSA_EMAIL. GKE reads this annotation to determine which Google identity to issue at runtime.

How can I verify that a pod is using Workload Identity instead of node credentials?

Run gcloud auth list inside the pod. If Workload Identity is active, the output returns the GSA email. If the pod returns the node’s default Compute Engine service account or no account, confirm that the KSA annotation, IAM binding, and node metadata mode are set correctly.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →