Module 8 · GCP IAM & Workload Identity Federation

Manish Garg
Manish Garg Associate of (ISC)² · RingSafe
Apr 27, 2026
3 min read
Read as

Last updated: April 29, 2026

100% Free

No signup. No paywall. No catch. One of our 10 most-requested practitioner modules — published in full so anyone can learn for free. We earn through consulting, not by gating knowledge.

See all 10 free modules →

Why this module exists. Every Indian SaaS that adopted GCP after 2022 inherited an IAM model fundamentally different from AWS. The pieces look similar — IAM, service accounts, roles — but the wiring is different and the attack paths are different.

Why this module exists. Every Indian SaaS that adopted GCP after 2022 inherited an IAM model fundamentally different from AWS. The pieces look similar — IAM, service accounts, roles — but the wiring is different and the attack paths are different. If you bring AWS muscle memory to GCP, you’ll either over-permission everything or miss the GCP-specific privilege-escalation paths.

How GCP IAM differs from AWS IAM

AWS GCP
Identity primitive IAM user, IAM role Google account, service account
Permission model Identity-based + resource-based policies IAM policy bound to a resource (project/folder/org)
Cross-account / cross-project access Trust policies + assume-role Direct grants — add a member to a project’s IAM
Inheritance None at the account level Org → Folder → Project → Resource (top inherits down)
Workload identity IAM role for service / IRSA Workload Identity / WIF — federated tokens

The GCP role hierarchy

Three role types:

  • Basic roles — Owner, Editor, Viewer. Project-wide. Wildly over-permissioned. Avoid in production.
  • Predefined roles — granular per-service (e.g., roles/storage.objectViewer). Use these.
  • Custom roles — pick exactly the permissions you need. Most secure; most operational overhead.

Service accounts — where most breaches live

A service account is both an identity and a resource. You grant roles to it (so it can do things), and you grant roles on it (so principals can use it).

The “use it” roles matter:

  • roles/iam.serviceAccountUser — attach this SA to a VM, GKE pod, Cloud Run service.
  • roles/iam.serviceAccountTokenCreator — generate access tokens AS this SA. This is the privilege-escalation primitive.
  • roles/iam.serviceAccountKeyAdmin — create persistent JSON keys. Long-lived credentials.

The classic GCP privilege-escalation chain

  1. Attacker compromises a low-priv user with roles/iam.serviceAccountTokenCreator on some service account.
  2. That service account has roles/owner on the project (common: an old “deploy bot” SA created in haste).
  3. Attacker generates an access token AS the SA: gcloud auth print-access-token --impersonate-service-account=deploy-bot@proj.iam.gserviceaccount.com
  4. Now operating as Owner. Game over.

Defender’s question: which low-priv users have iam.serviceAccountTokenCreator on which highly-privileged service accounts? Almost no enterprise has audited this.

Workload Identity Federation — the modern pattern

WIF lets external identities (GitHub Actions, AWS roles, OIDC providers) impersonate GCP service accounts without long-lived keys. The flow:

  1. External system (GitHub Actions runner) has an OIDC token.
  2. It exchanges the OIDC token at GCP’s STS for a short-lived GCP access token.
  3. The token impersonates a designated service account scoped to specific permissions.

Benefit: no JSON keys in CI, no rotation pain, scope tied to the OIDC claim (repository:owner/repo).

Risk: misconfigured WIF accepts overly broad OIDC claims. attribute_condition: assertion.repository_owner == 'mycompany' means any repo in the org can impersonate. attribute_condition: assertion.repository == 'mycompany/specific-repo' is what you actually want.

Try this yourself

# Audit who can impersonate what (run as a GCP admin)
gcloud asset search-iam-policy --scope=projects/MY-PROJECT 
  --query="policy:iam.serviceAccountTokenCreator"

# What roles does each SA have on the project?
gcloud projects get-iam-policy MY-PROJECT --format=json | 
  jq '.bindings[] | select(.members[] | startswith("serviceAccount:"))'

# Try impersonation
gcloud auth print-access-token 
  --impersonate-service-account=target-sa@MY-PROJECT.iam.gserviceaccount.com

# Use it
TOKEN=$(gcloud auth print-access-token --impersonate-service-account=...)
curl -H "Authorization: Bearer $TOKEN" 
  https://storage.googleapis.com/storage/v1/b/MY-BUCKET

Defender’s checklist

  • Eliminate basic roles. Especially Owner and Editor at project level. Replace with predefined or custom roles.
  • Disable service account key creation via Org Policy: iam.disableServiceAccountKeyCreation. Use WIF instead.
  • Audit serviceAccountTokenCreator across all SAs. Each grant is a privilege-escalation pivot.
  • WIF attribute conditions — pin to specific repos, branches, IdP subjects. Never blanket “trust this OIDC issuer.”
  • Detection: Cloud Audit Logs generateAccessToken entries — alert on impersonation chains where the principal isn’t expected.
  • Org-level constraints: use Organization Policy Service to enforce boundaries that no project admin can override.
🧠
Check your understanding

Module Quiz · 6 questions

Pass with 80%+ to mark this module complete. Unlimited retries. Each question shows an explanation.

Want this for your team?

Custom team training + practitioner advisory

Beyond the free academy — we run private workshops, vCISO advisory, and red-team exercises tailored to your stack. For Indian SMBs scaling past their first hire.

Book team training call Replies in 4 working hrs · India-only · Senior consultants