GKE Service Account Setup guideline
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
  1. Your pod runs with a KSA
  2. KSA is annotated with GSA email
  3. GKE’s Workload Identity maps KSA to GSA
  4. 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

RolePurpose
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:

  1. Workload Identity is enabled on the GKE cluster
  2. KSA has the correct annotation
  3. GSA has the correct IAM bindings
  4. Pod is using the correct serviceAccountName
  5. Namespace matches in the IAM binding

Issue: Permission denied errors

Check:

  1. GSA has the necessary IAM roles
  2. IAM policy propagation (can take up to 7 minutes)
  3. 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

  1. Principle of Least Privilege: Grant only necessary permissions to each service
  2. Separate Service Accounts: Use different KSAs/GSAs for different services
  3. Environment Isolation: Use separate service accounts for dev/staging/production
  4. Regular Audits: Review IAM permissions periodically
  5. Monitoring: Set up alerts for authentication/authorization failures
  6. Documentation: Keep service account mappings documented

Additional Resources