GCP IAM misconfig
TL;DR: GCP IAM bindings — primitive roles, custom roles with stray
*Update/actAspermissions, and bindings at folder/org scope — are the canonical escalation surface; Rhino’s privesc catalog enumerates ~40 known single-permission-to-owner paths.
What it is
GCP IAM grants are tuples of (principal, role, resource) attached as bindings at a resource node. Roles are bundles of permissions; permissions ending in .set, .create, .update, .actAs are the dangerous ones because they let you pivot to identities or attach yourself to higher-privilege bindings. The “primitive roles” — Owner, Editor, Viewer — are project-wide superpowers; Editor in particular includes iam.serviceAccountKeys.create on every project SA, an instant privesc to any SA in the project.
Preconditions / where it applies
- Foothold principal (user, service account, or workload-identity-bound identity).
- That principal holds at least one permission from Rhino’s catalog (e.g.
iam.serviceAccounts.actAs,iam.roles.update,cloudfunctions.functions.create,deploymentmanager.deployments.create). - Target project/folder/org has higher-priv SAs to pivot to.
Technique
Enumerate your effective permissions:
1
2
3
4
5
gcloud projects get-iam-policy $PROJECT --format=json \
| jq '.bindings[] | select(.members[] | contains("'$ME'"))'
gcloud iam roles describe roles/editor # see what Editor actually grants
# what can I do here?
gcloud asset search-all-iam-policies --scope=projects/$PROJECT --query='policy:'$ME
Known single-permission privesc paths (Rhino catalog highlights):
iam.serviceAccountKeys.createon any SA → mint a JSON key for that SA, auth as it.1 2
gcloud iam service-accounts keys create k.json --iam-account=admin-sa@proj.iam.gserviceaccount.com gcloud auth activate-service-account --key-file=k.json
iam.serviceAccounts.getAccessToken/iam.serviceAccounts.signJwt→ mint OAuth/ID tokens for the target SA without a key.1
gcloud auth print-access-token --impersonate-service-account=admin-sa@...
iam.serviceAccounts.actAs+cloudfunctions.functions.create→ deploy a function running as the target SA; invoke it to exfil its token.iam.serviceAccounts.actAs+compute.instances.create→ launch a VM with the SA attached; SSH in; query gcp-metadata-server for the token.deploymentmanager.deployments.create→ DM runs as the Google APIs SA which has heavy permissions; deploy a template that grants you Owner.iam.roles.updateon a role you hold → add*permissions to your own role.cloudbuild.builds.create→ builds run as the Cloud Build SA which has Editor by default; build a step that exfils its token.orgpolicy.policy.set→ relax org policies that block SA key creation in other projects, then chain.
Owner-via-Editor: Editor on a project + any one SA in that project → SA-key → impersonate → use that SA’s grants on other projects.
Chain with gcp-service-account-enum for target selection and gcp-metadata-server for credential extraction inside compute.
Detection and defence
- Cloud Audit Logs (Admin Activity): alert on
SetIamPolicy,CreateServiceAccountKey,GenerateAccessToken,deployments.insert. - Disable SA key creation via org policy
iam.disableServiceAccountKeyCreation. - Replace primitive roles (Owner/Editor/Viewer) with custom least-priv roles; never grant Editor at project scope.
- Use Workload Identity Federation instead of SA keys for external workloads.
- Run IAM Recommender — it surfaces over-privileged grants based on 90-day usage.
- Tag and inventory all SAs; auto-disable unused SAs and rotate keys aggressively.
References
- Rhino Security — GCP IAM Privesc — privesc catalog
- HackTricks Cloud — GCP privesc — abuse paths
- Google — IAM best practices — hardening guidance
See also: gke-workload-identity-abuse, gcp-cloud-build-trigger-abuse, gcp-service-account-enum, gcp-metadata-server