SuperAPI AI Directory

gcp-gke-workload-identity

Security & auditing

View repository

Updated 10-15 20:34

About this skill

GKE Workload Identity

Purpose

Workload Identity enables GKE pods to authenticate to Google Cloud services without managing service account keys. Pods use short-lived, automatically rotated credentials based on IAM bindings between Kubernetes and GCP service accounts.

When to Use

Use this skill when you need to:

  • Set up secure authentication from GKE pods to GCP services (Pub/Sub, Cloud SQL, Secret Manager)
  • Eliminate service account key management and rotation
  • Implement least privilege access with IAM bindings
  • Authenticate Spring Boot applications to Google Cloud APIs
  • Reduce security blast radius by avoiding static credentials
  • Enable Cloud SQL Proxy or Pub/Sub client libraries to authenticate automatically

Trigger phrases: "set up Workload Identity", "GKE authentication", "pod to GCP service auth", "keyless authentication", "Cloud SQL IAM auth"

Table of Contents

  • Purpose
  • When to Use
  • Quick Start
  • Instructions
    • Step 1: Create Google Cloud Service Account
    • Step 2: Create Kubernetes Service Account with Annotation
    • Step 3: Bind KSA to GSA
    • Step 4: Grant Service Account Required IAM Roles
    • Step 5: Update Deployment to Use Service Account
    • Step 6: Verify Workload Identity Configuration
  • Examples
  • Requirements
  • See Also

Quick Start

Three simple steps to enable Workload Identity for your application:

# 1. Create Kubernetes Service Account
kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-runtime
  namespace: wtr-supplier-charges
  annotations:
    iam.gke.io/gcp-service-account: app-runtime@project.iam.gserviceaccount.com
EOF

# 2. Bind GSA to KSA (one-time setup)
gcloud iam service-accounts add-iam-policy-binding \
  app-runtime@project.iam.gserviceaccount.com \
  --role=roles/iam.workloadIdentityUser \
  --member="serviceAccount:project.svc.id.goog[wtr-supplier-charges/app-runtime]"

# 3. Use in deployment
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: supplier-charges-hub
spec:
  template:
    spec:
      serviceAccountName: app-runtime
      containers:
      - name: app
        image: ...
EOF

Spring Boot automatically detects and uses the pod's credentials (no code changes needed).

Instructions

Step 1: Create Google Cloud Service Account

Create a service account for your application in the GCP project:

# Create service account
gcloud iam service-accounts create app-runtime \
  --project=ecp-wtr-supplier-charges-labs \
  --display-name="Supplier Charges Hub Runtime"

# Verify creation
gcloud iam service-accounts list --project=ecp-wtr-supplier-charges-labs

Naming Convention: Use {app}-runtime for clarity. For Supplier Charges Hub: app-runtime@ecp-wtr-supplier-charges-labs.iam.gserviceaccount.com

Step 2: Create Kubernetes Service Account with Annotation

Create a Kubernetes Service Account (KSA) in your namespace with the annotation linking it to the GSA:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-runtime
  namespace: wtr-supplier-charges
  annotations:
    iam.gke.io/gcp-service-account: app-runtime@ecp-wtr-supplier-charges-labs.iam.gserviceaccount.com

Apply it:

kubectl apply -f service-account.yaml

Key Points:

  • KSA name can differ from GSA name, but matching helps clarity
  • Namespace must be correct in annotation
  • The full GSA email (with .iam.gserviceaccount.com) is required

Step 3: Bind KSA to GSA (One-Time IAM Setup)

Create the IAM binding that allows the KSA to impersonate the GSA:

gcloud iam service-accounts add-iam-policy-binding \
  app-runtime@ecp-wtr-supplier-charges-labs.iam.gserviceaccount.com \
  --role=roles/iam.workloadIdentityUser \
  --member="serviceAccount:ecp-wtr-supplier-charges-labs.svc.id.goog[wtr-supplier-charges/app-runtime]"

Syntax: project.svc.id.goog[namespace/ksa-name] is the principal that gets the role.

Verify:

gcloud iam service-accounts get-iam-policy \
  app-runtime@ecp-wtr-supplier-charges-labs.iam.gserviceaccount.com

Step 4: Grant Service Account Required IAM Roles

Give the service account permissions to access the resources your application needs:

# For Pub/Sub publishing
gcloud projects add-iam-policy-binding ecp-wtr-supplier-charges-labs \
  --member="serviceAccount:app-runtime@ecp-wtr-supplier-charges-labs.iam.gserviceaccount.com" \
  --role="roles/pubsub.publisher"

# For Pub/Sub subscribing
gcloud projects add-iam-policy-binding ecp-wtr-supplier-charges-labs \
  --member="serviceAccount:app-runtime@ecp-wtr-supplier-charges-labs.iam.gserviceaccount.com" \
  --role="roles/pubsub.subscriber"

# For Cloud SQL connections
gcloud projects add-iam-policy-binding ecp-wtr-supplier-charges-labs \
  --member="serviceAccount:app-runtime@ecp-wtr-supplier-charges-labs.iam.gserviceaccount.com" \
  --role="roles/cloudsql.client"

# For Secret Manager access
gcloud projects add-iam-policy-binding ecp-wtr-supplier-charges-labs \
  --member="serviceAccount:app-runtime@ecp-wtr-supplier-charges-labs.iam.gserviceaccount.com" \
  --role="roles/secretmanager.secretAccessor"

Step 5: Update Deployment to Use Service Account

Specify the KSA in your deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: supplier-charges-hub
  namespace: wtr-supplier-charges
spec:
  template:
    spec:
      serviceAccountName: app-runtime  # Use the KSA
      containers:
      - name: supplier-charges-hub-container
        image: europe-west2-docker.pkg.dev/.../supplier-charges-hub:latest
        # No credential configuration needed!
      - name: cloud-sql-proxy
        image: gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.11.4
        # Cloud SQL Proxy also uses pod's credentials

Step 6: Verify Workload Identity Configuration

Test that the pod can access GCP services:

# Get a pod
POD_NAME=$(kubectl get pods -n wtr-supplier-charges -o name | head -1)

# Check the pod's Workload Identity binding
kubectl describe pod $POD_NAME -n wtr-supplier-charges | grep -A 5 "Annotations"

# Test access to Pub/Sub
kubectl exec $POD_NAME -n wtr-supplier-charges -- \
  gcloud pubsub topics list --project=ecp-wtr-supplier-charges-labs

# Test access to Cloud SQL
kubectl exec $POD_NAME -c cloud-sql-proxy -n wtr-supplier-charges -- \
  cloud-sql-proxy --version

Examples

Example 1: Complete Workload Identity Setup for Pub/Sub

#!/bin/bash
# Full setup for Supplier Charges Hub with Pub/Sub access

PROJECT_ID="ecp-wtr-supplier-charges-labs"
GSA_NAME="app-runtime"
GSA_EMAIL="${GSA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"
NAMESPACE="wtr-supplier-charges"
KSA_NAME="app-runtime"

# Step 1: Create Google Cloud Service Account
gcloud iam service-accounts create $GSA_NAME \
  --project=$PROJECT_ID \
  --display-name="Supplier Charges Hub Runtime"

# Step 2: Grant IAM roles for Pub/Sub
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$GSA_EMAIL" \
  --role="roles/pubsub.publisher"

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$GSA_EMAIL" \
  --role="roles/pubsub.subscriber"

# Step 3: Create Kubernetes Service Account
kubectl create serviceaccount $KSA_NAME -n $NAMESPACE --dry-run=client -o yaml | \
  kubectl annotate -f - \
    iam.gke.io/gcp-service-account=$GSA_EMAIL \
    --overwrite \
    --local \
  | kubectl apply -f -

# Step 4: Bind KSA to GSA
gcloud iam service-accounts add-iam-policy-binding $GSA_EMAIL \
  --role=roles/iam.workloadIdentityUser \
  --member="serviceAccount:${PROJECT_ID}.svc.id.goog[${NAMESPACE}/${KSA_NAME}]"

# Verify
echo "Workload Identity setup complete!"
gcloud iam service-accounts get-iam-policy $GSA_EMAIL

Example 2: Spring Boot Application Using Workload Identity

// No special configuration needed!
// Spring Cloud GCP automatically detects pod credentials

@Service
public class SupplierChargesPublisher {

    @Autowired
    private PubSubTemplate pubSubTemplate;

    public void publishCharge(SupplierCharge charge) {
        // Credentials come from Workload Identity automatically
        pubSubTemplate.publish("supplier-charges-topic",
            objectMapper.writeValueAsString(charge));
    }
}

// For Cloud SQL, IAM authentication is used:
// JDBC URL: jdbc:postgresql://localhost:5432/supplier_charges_hub
// Username: app-runtime@project.iam (GSA email)
// Cloud SQL Proxy handles IAM auth automatically

Example 3: Verify Workload Identity is Working

#!/bin/bash
# Test script to verify Workload Identity

POD=$(kubectl get pods -n wtr-supplier-charges -o jsonpath='{.items[0].metadata.name}')
NAMESPACE="wtr-supplier-charges"

echo "Testing Workload Identity for pod: $POD"

# Check the bound service account
echo ""
echo "=== Service Account Binding ==="
kubectl get pod $POD -n $NAMESPACE -o jsonpath='{.spec.serviceAccountName}'
echo ""

# Check pod annotations
echo ""
echo "=== Pod Workload Identity Annotation ==="
kubectl get pod $POD -n $NAMESPACE -o jsonpath='{.metadata.annotations.iam\.gke\.io/gcp-service-account}'
echo ""

# Test Pub/Sub access
echo ""
echo "=== Testing Pub/Sub Access ==="
kubectl exec $POD -n $NAMESPACE -- \
  gcloud pubsub topics list --project=ecp-wtr-supplier-charges-labs || \
  echo "Pub/Sub access test failed!"

# Test Cloud SQL connection
echo ""
echo "=== Testing Cloud SQL Proxy ==="
kubectl exec $POD -c cloud-sql-proxy -n $NAMESPACE -- \
  nc -zv localhost 5432 || \
  echo "Cloud SQL Proxy connection test failed!"

echo ""
echo "Workload Identity verification complete!"

Requirements

  • GKE cluster with Workload Identity enabled (enabled by default in Autopilot)
  • gcloud CLI with appropriate IAM permissions
  • kubectl access to the cluster
  • KSA and GSA created in their respective systems
  • IAM role: roles/iam.securityAdmin to create IAM bindings

See Also