Skip to content

GCP_HAS_ROLE

Copy page

Summary

Forestall ACL Alias GCP_HAS_ROLE
GCP Alias Entity Relation (Structural)
Affected Object Types Roles
Exploitation Certainty Certain

Description

GCP_HAS_ROLE is a structural edge representing that a GCP identity (user, group, or service account) holds an IAM role binding. It connects principals to their role assignments in the graph. A role binding is a triple of (principal, role, resource). GCP_HAS_ROLE captures the principal → role binding relationship.

Identification

gcloud CLI

# List all roles granted to a specific user at project level
PROJECT_ID="my-project"
USER_EMAIL="[email protected]"
gcloud projects get-iam-policy $PROJECT_ID --format=json | \
jq --arg user "user:$USER_EMAIL" '.bindings[] | select(.members[] | contains($user)) | .role'
# List all roles granted to a specific service account
gcloud projects get-iam-policy $PROJECT_ID --format=json | \
jq --arg sa "serviceAccount:$SA_EMAIL" '.bindings[] | select(.members[] | contains($sa)) | .role'
# List all direct bindings for a principal across org, folder, and project scope
ORG_ID=$(gcloud organizations list --format="value(name)" | head -1)
echo "=== Org level ===" && gcloud organizations get-iam-policy $ORG_ID --format=json | \
jq --arg user "user:$USER_EMAIL" '[.bindings[] | select(.members[] | contains($user)) | .role]'
echo "=== Project level ===" && gcloud projects get-iam-policy $PROJECT_ID --format=json | \
jq --arg user "user:$USER_EMAIL" '[.bindings[] | select(.members[] | contains($user)) | .role]'

Exploitation

GCP_HAS_ROLE is the starting point for all privilege analysis. Every attack path edge in the system is derived from role bindings surfaced by this edge.

Key risk patterns:

  • Over-assignment: Identities accumulating many role bindings over time, especially after project migrations or team changes.
  • Stale bindings: Former employees or deprecated service accounts retaining GCP_HAS_ROLE edges to privileged roles.
  • Cross-project service accounts: A service account from Project A holding roles in Project B creates cross-project attack paths.
  • Conditional bindings: GCP IAM supports conditions on bindings (e.g., time-based access). GCP_HAS_ROLE edges may reflect conditional bindings that are inactive outside their condition window.

Mitigation

  1. Enforce least privilege — remove role bindings that are no longer needed. Conduct periodic access reviews, especially after team changes or project migrations.
  2. Eliminate stale bindings — disable or delete service accounts and user accounts that are no longer active before removing their role bindings.
  3. Scope bindings narrowly — prefer project-level bindings over folder- or org-level to limit blast radius.
  4. Review cross-project service account assignments — a service account from Project A holding roles in Project B creates cross-project attack paths; document and minimize these.
  5. Audit conditional bindings — verify that time-based or condition-based bindings are still appropriate and tightly scoped.

Detection

Log Type Method Key Fields
Admin Activity SetIamPolicy New role binding added to any principal
gcloud logging read \
'protoPayload.methodName="SetIamPolicy"' \
--project=$PROJECT_ID \
--format="table(timestamp, protoPayload.authenticationInfo.principalEmail, protoPayload.serviceData.policyDelta.bindingDeltas)"

Alert on:

  • New privileged role bindings (roles/owner, roles/editor, admin roles) added to any identity.
  • Role bindings added at org or folder scope — these carry the highest blast radius.
  • Bindings added to external identities (Gmail accounts, federated identities outside the org domain).

References

Was this page helpful?

Thank you for your feedback.