Claude-skill-registry gcp-gke-workload-identity
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/gcp-gke-workload-identity" ~/.claude/skills/majiayu000-claude-skill-registry-gcp-gke-workload-identity && rm -rf "$T"
skills/data/gcp-gke-workload-identity/SKILL.mdGKE 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
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
) is required.iam.gserviceaccount.com
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)
CLI with appropriate IAM permissionsgcloud
access to the clusterkubectl- KSA and GSA created in their respective systems
- IAM role:
to create IAM bindingsroles/iam.securityAdmin
See Also
- gcp-gke-cluster-setup - Ensure Workload Identity is enabled
- gcp-gke-troubleshooting - Diagnose Workload Identity issues
- gcp-pubsub - Configure Pub/Sub integration