Cloud IAM, Service Accounts & Credential Delegation

Master GCP Cloud IAM bindings, Primitive vs Predefined roles, Service Account security, and eliminating exported JSON keys with Service Account Impersonation.

intermediate 22 min lesson hands-on task included

In Cloud IAM, access control is expressed as an explicit rule: WHO (Identity) can do WHAT (Roles) on WHICH (Resource).

Understanding how GCP structures Cloud IAM roles and non-human Service Accounts is critical to preventing credential leaks and privilege escalation.


Topic 1: The Anatomy of an IAM Policy Binding

CLOUD IAM POLICY BINDING = MEMBER + ROLE + CONDITION PRINCIPALS (WHO) • User Account (Google Workspace) • Service Account (non-human) • Google Group (recommended) • Cloud Identity Domain • allAuthenticatedUsers / allUsers + ROLE (WHAT PERMISSIONS) • Primitive: Owner / Editor / Viewer (Avoid in Prod — overly broad) • Predefined: storage.objectAdmin (Google maintained, scoped by product) • Custom: Custom permissions array = IAM POLICY Bindings Array: role: "roles/storage.admin" members: [ "serviceAccount:sa@..." ] IAM EVALUATION ORDER & SERVICE ACCOUNT IMPERSONATION 1. User authenticates gcloud auth login / ADC 2. Service Account Impersonation roles/iam.serviceAccountTokenCreator 3. Short-lived OAuth2 Token No long-lived JSON keys exported! SECURITY WARNING: DEFAULT SERVICE ACCOUNTS Compute Engine default SA has Editor role by default. Always disable automatic role assignment and create dedicated SAs!
GCP Cloud IAM binding anatomy: Policy = Members + Roles + Conditions. Short-lived tokens via Service Account Impersonation replace static JSON key files.

An IAM Policy is a collection of bindings. Each binding maps one or more Principals (Members) to exactly one Role:

  1. Principals (Members):
    • Google Account: An individual user email (dev@company.com).
    • Service Account: A special non-human account used by applications or GCE VMs (sa-payment@project.iam.gserviceaccount.com).
    • Google Group: A managed group of Google accounts (devs@company.com). Best Practice: Assign roles to Groups rather than individual emails!
    • Domain / Cloud Identity: All accounts in a Google Workspace domain.
    • Special Identifiers: allAuthenticatedUsers (anyone with a valid Google account worldwide) and allUsers (public internet access).

Topic 2: Primitive vs. Predefined vs. Custom Roles

GCP categorizes roles into three distinct tiers:

Role CategoryScopeExamplesProduction Recommendation
Primitive RolesProject-wideroles/viewer, roles/editor, roles/ownerNEVER in production — editor contains thousands of permissions across all GCP products
Predefined RolesFine-grained per serviceroles/storage.objectAdmin, roles/pubsub.publisherPREFERRED — Maintained by Google, follows least privilege per service
Custom RolesUser-defined permissionsCustom array of gcp.service.verb permissionsUse when predefined roles are still too permissive for compliance
# Bad Practice: Granting primitive Editor role
gcloud projects add-iam-policy-binding my-project-id \
  --member="user:engineer@company.com" \
  --role="roles/editor"  # DO NOT DO THIS IN PROD!

# Good Practice: Granting a Predefined Least-Privilege Role
gcloud projects add-iam-policy-binding my-project-id \
  --member="group:backend-team@company.com" \
  --role="roles/storage.objectViewer"

Topic 3: Service Accounts & The Trap of Default Service Accounts

Service accounts represent non-human workloads (applications, GCE VMs, GKE pods, Cloud Functions).

The Default Service Account Trap: When you enable the Compute Engine API in a new project, GCP automatically creates the Compute Engine Default Service Account (PROJECT_NUMBER-compute@developer.gserviceaccount.com) and automatically grants it the primitive roles/editor role!

If an attacker compromises a GCE VM running with this default service account, they gain full Editor rights across your entire GCP project.

Remediation Steps:

  1. Disable automatic default service account role grants at the Organization level (iam.automaticIamGrantsForDefaultServiceAccounts).
  2. Create dedicated, workload-specific service accounts for every service.
  3. Grant only the exact predefined roles required by that specific service.

Topic 4: Key Security: Service Account Impersonation vs. Key Files

Historically, developers downloaded .json private key files to authenticate local code or CI/CD pipelines. These keys are a major security vulnerability: they do not expire automatically and frequently leak in git repositories.

Modern Security Standard: Service Account Impersonation: Instead of creating static key files, authorized users or CI/CD workers trade their identity for a short-lived OAuth2 access token (valid for 1 hour) by impersonating the target service account:

# Grant an engineer permission to impersonate a service account
gcloud iam service-accounts add-iam-policy-binding \
  sa-deployment@my-project-id.iam.gserviceaccount.com \
  --member="user:lead-dev@company.com" \
  --role="roles/iam.serviceAccountTokenCreator"

# Local CLI or CI script uses short-lived impersonation token (NO JSON KEY NEEDED)
gcloud auth print-access-token \
  --impersonate-service-account=sa-deployment@my-project-id.iam.gserviceaccount.com

Common mistake: Downloading a service-account key because impersonation looked like extra work. The key never expires, is copied into a laptop and a CI variable, and appears in the audit log as the service account rather than as the person using it. Impersonation and Workload Identity Federation give you short-lived credentials and a real caller identity — and there is almost always a path to one of them.