By Jun Nguyen4 min read855 words
GKE Service Account Setup guideline
Technology
GCP
GKE
Overview
This document provides a reference guide for understanding and implementing GKE and Kubernetes Service Accounts for a service.
In this article, we will call it a
reporting service
GKE (Google Kubernetes Engine)
GKE is Google Cloud’s managed Kubernetes service that:
- Hosts and manages your containerized applications (like your NestJS reporting service)
- Handles cluster infrastructure, scaling, and updates
- Integrates with other GCP services (Cloud Logging, Monitoring, IAM, etc.)
KSA (Kubernetes Service Account)
A Kubernetes Service Account is an identity used by pods to:
- Authenticate with the Kubernetes API server
- Access cluster resources
- Most importantly: Integrate with GCP services via Workload Identity
Key Concepts for Your Service
1. Workload Identity (Recommended GCP Pattern)
Links Kubernetes Service Accounts (KSA) to Google Service Accounts (GSA):
# Example KSA configuration apiVersion: v1 kind: ServiceAccount metadata: name: reporting-service-ksa namespace: production annotations: iam.gke.io/gcp-service-account: reporting-service@project-id.iam.gserviceaccount.com
2. Why You Need KSA
For your reporting service to access GCP resources:
- Pub/Sub: Publishing alerts
- Secret Manager: Accessing secrets
- Cloud SQL: Database connections
- Cloud Storage: File storage
- Logging/Monitoring: Observability
3. How It Works
Pod → KSA → Workload Identity → GSA → GCP Service Access
- Your pod runs with a KSA
- KSA is annotated with GSA email
- GKE’s Workload Identity maps KSA to GSA
- Pod can now access GCP services with GSA permissions
Setup Steps
Step 1: Create Google Service Account (GSA)
gcloud iam service-accounts create reporting-service \ --display-name="Reporting Service"
Step 2: Grant GSA Permissions
# Example: Grant Pub/Sub publisher role gcloud projects add-iam-policy-binding PROJECT_ID \ --member="serviceAccount:reporting-service@PROJECT_ID.iam.gserviceaccount.com" \ --role="roles/pubsub.publisher" # Add additional roles as needed: # - roles/secretmanager.secretAccessor (for Secret Manager) # - roles/cloudsql.client (for Cloud SQL) # - roles/logging.logWriter (for Cloud Logging)
Step 3: Bind KSA to GSA
gcloud iam service-accounts add-iam-policy-binding \ service_name@PROJECT_ID.iam.gserviceaccount.com \ --role roles/iam.workloadIdentityUser \ --member "serviceAccount:PROJECT_ID.svc.id.goog[NAMESPACE/KSA_NAME]"
Replace:
- PROJECT_ID: Your GCP project ID
- NAMESPACE: Your Kubernetes namespace (e.g.,production,staging)
- KSA_NAME: Your Kubernetes service account name (e.g.,reporting-service-ksa)
Step 4: Create Kubernetes Service Account
apiVersion: v1 kind: ServiceAccount metadata: name: service-ksa namespace: production annotations: iam.gke.io/gcp-service-account: reporting-service@PROJECT_ID.iam.gserviceaccount.com
Step 5: Reference KSA in Deployment
apiVersion: apps/v1 kind: Deployment metadata: name: reporting-service namespace: production spec: replicas: 3 selector: matchLabels: app: reporting-service template: metadata: labels: app: reporting-service spec: serviceAccountName: reporting-service-ksa # Reference the KSA containers: - name: reporting-service image: gcr.io/PROJECT_ID/reporting-service:latest ports: - containerPort: 3000 env: - name: NODE_ENV value: "production" resources: requests: memory: "256Mi" cpu: "250m" limits: memory: "512Mi" cpu: "500m"
Benefits of Workload Identity
- ✅ No credential files in containers
- ✅ Automatic credential rotation
- ✅ Fine-grained access control per service
- ✅ Follows GCP security best practices
- ✅ Simplified secret management
- ✅ Better audit trails
Verification
Verify Workload Identity Setup
# Check if KSA exists kubectl get serviceaccount reporting-service-ksa -n production # Check KSA annotation kubectl describe serviceaccount reporting-service-ksa -n production # Check GSA IAM bindings gcloud iam service-accounts get-iam-policy \ reporting-service@PROJECT_ID.iam.gserviceaccount.com
Test from Inside a Pod
# Exec into a running pod kubectl exec -it <pod-name> -n <namespace_name> -- /bin/sh # Check if credentials are available curl -H "Metadata-Flavor: Google" \ http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/email
Common IAM Roles for Microservices
| Role | Purpose |
|---|---|
roles/pubsub.publisher | Publish messages to Pub/Sub |
roles/pubsub.subscriber | Subscribe to Pub/Sub topics |
roles/secretmanager.secretAccessor | Access secrets from Secret Manager |
roles/cloudsql.client | Connect to Cloud SQL databases |
roles/storage.objectViewer | Read from Cloud Storage |
roles/storage.objectCreator | Write to Cloud Storage |
roles/logging.logWriter | Write logs to Cloud Logging |
roles/monitoring.metricWriter | Write metrics to Cloud Monitoring |
Troubleshooting
Issue: Pod cannot access GCP services
Check:
- Workload Identity is enabled on the GKE cluster
- KSA has the correct annotation
- GSA has the correct IAM bindings
- Pod is using the correct serviceAccountName
- Namespace matches in the IAM binding
Issue: Permission denied errors
Check:
- GSA has the necessary IAM roles
- IAM policy propagation (can take up to 7 minutes)
- Resource-level permissions (e.g., Pub/Sub topic-specific permissions)
Enable Workload Identity on Existing Cluster
gcloud container clusters update CLUSTER_NAME \ --workload-pool=PROJECT_ID.svc.id.goog
Best Practices
- Principle of Least Privilege: Grant only necessary permissions to each service
- Separate Service Accounts: Use different KSAs/GSAs for different services
- Environment Isolation: Use separate service accounts for dev/staging/production
- Regular Audits: Review IAM permissions periodically
- Monitoring: Set up alerts for authentication/authorization failures
- Documentation: Keep service account mappings documented