GCP for DevOps — Service Accounts
Service Accounts
A service account is a special type of Google account intended for non-human users — applications, VMs, and CI/CD pipelines. Service accounts authenticate using keys or short-lived tokens instead of passwords.
Types of Service Accounts
┌─────────────────────────────────────────────────────────┐
│ Service Accounts │
├──────────────────┬──────────────────┬───────────────────┤
│ Default │ User-Managed │ Google-Managed │
│ (Auto-created) │ (You create) │ (GCP internal) │
├──────────────────┼──────────────────┼───────────────────┤
│ PROJECT_NUM │ my-sa@PROJECT │ service-PROJECT_ │
│ -compute@ │ .iam.gservice │ NUM@... │
│ developer. │ account.com │ │
│ gserviceaccount │ │ Used by GCP │
│ .com │ Best practice │ services internally│
│ │ for workloads │ │
│ ⚠️ Avoid using │ │ Do not modify │
└──────────────────┴──────────────────┴───────────────────┘
| Type | Email Format | Created By |
|---|---|---|
| Default Compute SA | PROJECT_NUMBER-compute@developer.gserviceaccount.com |
GCP (auto) |
| Default App Engine SA | PROJECT_ID@appspot.gserviceaccount.com |
GCP (auto) |
| User-managed | NAME@PROJECT_ID.iam.gserviceaccount.com |
You |
| Google-managed | service-PROJECT_NUMBER@*.iam.gserviceaccount.com |
GCP services |
⚠️ DevOps Best Practice: Create dedicated user-managed service accounts for each workload. Never use the default Compute Engine service account in production — it has
roles/editorby default.
Creating Service Accounts
# Create a service account
$ gcloud iam service-accounts create ci-deployer \
--display-name="CI/CD Deployer" \
--description="Used by Cloud Build to deploy to GKE"
Created service account [ci-deployer].
# Verify
$ gcloud iam service-accounts list --format="table(email,displayName)"
EMAIL DISPLAY_NAME
ci-deployer@my-project.iam.gserviceaccount.com CI/CD Deployer
123456789-compute@developer.gserviceaccount.com Compute Engine default
Granting Roles to Service Accounts
# Grant a role to the service account on a project
$ gcloud projects add-iam-policy-binding my-project \
--member="serviceAccount:ci-deployer@my-project.iam.gserviceaccount.com" \
--role="roles/container.developer"
Updated IAM policy for project [my-project].
bindings:
- members:
- serviceAccount:ci-deployer@my-project.iam.gserviceaccount.com
role: roles/container.developer
# Grant multiple roles (run for each role)
$ gcloud projects add-iam-policy-binding my-project \
--member="serviceAccount:ci-deployer@my-project.iam.gserviceaccount.com" \
--role="roles/storage.objectViewer"
$ gcloud projects add-iam-policy-binding my-project \
--member="serviceAccount:ci-deployer@my-project.iam.gserviceaccount.com" \
--role="roles/artifactregistry.writer"
Service Account Keys
Service account keys are long-lived credentials. Use them only when Workload Identity or attached service accounts are not possible.
# Create a key (generates a JSON file)
$ gcloud iam service-accounts keys create key.json \
--iam-account=ci-deployer@my-project.iam.gserviceaccount.com
created key [abc123def456] of type [json] as [key.json]
# List existing keys
$ gcloud iam service-accounts keys list \
--iam-account=ci-deployer@my-project.iam.gserviceaccount.com \
--format="table(name.basename(),validAfterTime,validBeforeTime)"
KEY_ID VALID_AFTER VALID_BEFORE
abc123def456 2026-03-30T00:00:00Z 2028-03-30T00:00:00Z
# Delete a key
$ gcloud iam service-accounts keys delete abc123def456 \
--iam-account=ci-deployer@my-project.iam.gserviceaccount.com
# Authenticate using a key (for external systems)
$ gcloud auth activate-service-account \
--key-file=key.json
⚠️ Security Warning: Service account keys are a security risk. They don’t expire automatically and can be leaked. Prefer Workload Identity, attached service accounts, or short-lived tokens.
Attached Service Accounts
The best way for GCP resources to authenticate is by attaching a service account.
# Create a VM with an attached service account
$ gcloud compute instances create build-server \
--zone=us-central1-a \
--service-account=ci-deployer@my-project.iam.gserviceaccount.com \
--scopes=cloud-platform
# Update an existing VM's service account (must stop first)
$ gcloud compute instances stop build-server --zone=us-central1-a
$ gcloud compute instances set-service-account build-server \
--zone=us-central1-a \
--service-account=ci-deployer@my-project.iam.gserviceaccount.com \
--scopes=cloud-platform
Service Account Impersonation
Impersonation lets a user or service account act as another service account without downloading keys.
# Impersonate a service account for a gcloud command
$ gcloud compute instances list \
--impersonate-service-account=ci-deployer@my-project.iam.gserviceaccount.com
WARNING: This command is using service account impersonation.
NAME ZONE MACHINE_TYPE STATUS
build-server us-central1-a e2-medium RUNNING
# Grant the impersonation permission
$ gcloud iam service-accounts add-iam-policy-binding \
ci-deployer@my-project.iam.gserviceaccount.com \
--member="user:alice@example.com" \
--role="roles/iam.serviceAccountTokenCreator"
Short-Lived Credentials
Generate tokens that expire automatically — more secure than keys.
# Generate an access token (expires in 1 hour by default)
$ gcloud auth print-access-token \
--impersonate-service-account=ci-deployer@my-project.iam.gserviceaccount.com
ya29.c.ElqBBw...truncated...
# Generate an ID token for calling Cloud Run / Cloud Functions
$ gcloud auth print-identity-token \
--impersonate-service-account=ci-deployer@my-project.iam.gserviceaccount.com \
--audiences="https://my-service-abc123-uc.a.run.app"
Authentication Method Comparison
| Method | Duration | Security | Use Case |
|---|---|---|---|
| Service account key (JSON) | Until deleted | ⚠️ Low — can be leaked | External CI/CD (non-GCP) |
| Attached service account | Session | ✅ High — no keys | VMs, GKE nodes, Cloud Run |
| Workload Identity | Session | ✅ High — no keys | GKE pods |
| Impersonation | 1 hour | ✅ High — auditable | Developer access, scripts |
| Workload Identity Federation | Session | ✅ High — no keys | AWS, Azure, GitHub Actions |
Common Mistakes
| Mistake | Why It’s Wrong | Fix |
|---|---|---|
| Using default SA in production | Has roles/editor — too broad |
Create dedicated SA with least-privilege |
| Downloading keys for GCP workloads | Keys can be leaked and don’t auto-expire | Use attached SA or Workload Identity |
| One SA for all workloads | Blast radius too large | One SA per workload / microservice |
| Not rotating keys | Old keys accumulate risk | Set org policy to limit key lifetime |
Granting roles/iam.serviceAccountAdmin |
Can create keys for any SA | Use roles/iam.serviceAccountUser instead |
Quick Reference
| Command | Description |
|---|---|
gcloud iam service-accounts create NAME |
Create a service account |
gcloud iam service-accounts list |
List service accounts |
gcloud iam service-accounts keys create FILE --iam-account=SA |
Create a key |
gcloud iam service-accounts keys list --iam-account=SA |
List keys |
gcloud iam service-accounts add-iam-policy-binding SA --member=M --role=R |
Grant role on SA |
gcloud auth activate-service-account --key-file=FILE |
Authenticate with key |
gcloud auth print-access-token --impersonate-service-account=SA |
Get short-lived token |
Next → IAM Policies