GCP for DevOps — Service Accounts

3 minute read

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/editor by 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

Updated: