Skip to content

GCP_PARENT

Copy page

Summary

Forestall ACL Alias GCP_PARENT
GCP Alias Entity Relation (Structural)
Affected Object Types Organizations, Organizational Units, Folders, Projects, Users, Groups, Roles, Devices, Service Accounts, Virtual Machines, KMS Keys, Workload Identity Pools, Workforce Identity Pools, Workload Providers, Workforce Providers, Principals
Exploitation Certainty Certain

Description

GCP_PARENT is the structural edge representing parent-to-child containment in the Google Cloud resource hierarchy and at the Google Workspace Customer root.

The Customer is the Google Workspace tenancy root, identified by a Customer ID (e.g. C0xxxxxxx), and is linked 1:1 to the GCP Organization that roots the resource hierarchy:

Customer (root)
├── Organization ← the linked GCP resource hierarchy root
│ ├── Folder ──► Folder ──► Project
│ ├── Project (top-level, no folder)
│ └── Workforce Identity Pool
│ ├── Workforce Provider
│ └── Principal
├── Organizational Unit (top-level only)
├── Group
├── User
├── Role (admin role definition)
└── Device

Projects are the leaf containers for the bulk of GCP resources:

Project
├── Service Account
├── Virtual Machine
├── KMS Key
└── Workload Identity Pool
├── Workload Provider
└── Principal

Workforce Identity Pools similarly contain Workforce Providers and federated Principals. Because one edge type spans every tier, the child and parent object types determine what the edge means in a given traversal. A GCP_PARENT from a Folder to a Project carries IAM inheritance, while one from an Identity Pool to a Provider identifies the trust configuration contained by that pool.

Why the edge matters for attack paths:

IAM bindings in GCP are inherited downward. A role granted at the organization, folder, or project level applies to every resource beneath it, at any depth. GCP_PARENT is the chain that traversal follows to resolve that scope, so it determines the blast radius of every scoped role binding:

  • An organization-scoped binding reaches every folder, project, and resource in the tenancy.
  • A folder-scoped binding reaches all nested folders and projects, regardless of depth.
  • A project-scoped binding reaches the service accounts, VMs, and keys inside that project. This is what makes project-level GCP_ACT_AS_SA fan out to every service account whose parent is that project.

For identity federation, GCP_PARENT also joins a Workload or Workforce Identity Pool to each Provider configured inside it. The Provider contains the issuer, audience, attribute mappings, and attribute conditions that decide which external identities the Pool trusts.

Identification

gcloud CLI

# --- Customer root (Workspace tenancy) ---
# (Access token should be authorized on scope: https://www.googleapis.com/auth/admin.directory.customer.readonly)
ACCESS_TOKEN="your-access-token"
curl -s \
-H "Authorization: Bearer $ACCESS_TOKEN" \
"https://admin.googleapis.com/admin/directory/v1/customers/my_customer" \
| jq '{customerId: .id, customerDomain: .customerDomain}'
# --- GCP resource hierarchy ---
# Top-level folders (direct children of the org)
ORG_ID=$(gcloud organizations list --format="value(name)" | head -1)
gcloud resource-manager folders list --organization=$ORG_ID \
--format="table(name, displayName, createTime)"
# Top-level projects (directly under the org, in no folder)
gcloud projects list \
--filter="parent.type=organization AND parent.id=$(echo $ORG_ID | cut -d/ -f2)" \
--format="table(projectId, name, projectNumber)"
# Subfolders and projects of a folder
FOLDER_ID="123456789"
gcloud resource-manager folders list --folder=$FOLDER_ID \
--format="table(name, displayName)"
gcloud projects list --filter="parent.id=$FOLDER_ID" \
--format="table(projectId, name, projectNumber)"
# --- Resources inside a project ---
PROJECT_ID="my-project"
gcloud iam service-accounts list --project=$PROJECT_ID \
--format="table(name, email, disabled)"
gcloud compute instances list --project=$PROJECT_ID \
--format="table(name, zone, status, serviceAccounts[0].email)"
# Full resource inventory for a project (all child object types at once)
gcloud asset search-all-resources \
--scope=projects/$PROJECT_ID \
--format="table(name, assetType, location)"
# --- Workspace Customer-root children ---
# Top-level OUs
# (Access token should be authorized on scope: https://www.googleapis.com/auth/admin.directory.orgunit.readonly)
curl -s \
-H "Authorization: Bearer $ACCESS_TOKEN" \
"https://admin.googleapis.com/admin/directory/v1/customer/my_customer/orgunits?type=children" \
| jq '.organizationUnits[] | {name: .name, path: .orgUnitPath}'
# Customer-scoped Users
# (Access token should be authorized on scope: https://www.googleapis.com/auth/admin.directory.user.readonly)
curl -s \
-H "Authorization: Bearer $ACCESS_TOKEN" \
"https://admin.googleapis.com/admin/directory/v1/users?customer=my_customer&maxResults=500" \
| jq '.users[] | {email: .primaryEmail, isAdmin: .isAdmin}'
# --- Identity Pool children ---
# Workload Providers contained in a Workload Identity Pool
POOL_ID="my-workload-pool"
gcloud iam workload-identity-pools providers list \
--workload-identity-pool=$POOL_ID --location=global --project=$PROJECT_ID \
--format="table(name, state, oidc.issuerUri, aws.accountId, attributeCondition)"
# Workforce Providers contained in a Workforce Identity Pool
WORKFORCE_POOL_ID="my-workforce-pool"
gcloud iam workforce-pools providers list \
--workforce-pool=$WORKFORCE_POOL_ID --location=global \
--format="table(name, state, oidc.issuerUri, attributeCondition)"

Exploitation

GCP_PARENT has no direct exploit — it is a structural edge. Its value to an attacker is as a reachability and blast-radius map, and each tier it spans carries a distinct consequence:

  • Organization — any binding at org scope reaches every resource in the tenancy. Roles such as roles/resourcemanager.organizationAdmin and roles/iam.securityAdmin create GCP_SET_ORG_IAMPOLICY against the org node, which is full control of the organization.
  • Folder — a folder-level binding applies to every nested folder and project without a separate grant on each. An attacker holding GCP_SET_FOLDER_IAMPOLICY controls all child projects at once. Where prod and non-prod share a folder with inherited admin bindings, a staging compromise pivots to production through that shared scope.
  • Project — the project is the primary blast radius for lateral movement. An identity with project-scoped roles/iam.serviceAccountUser gains GCP_ACT_AS_SA against every service account whose parent is that project, and project-scoped compute roles reach every VM in it.
  • Customer root — Customer-scoped Users, Groups, Roles, Devices, and top-level OUs reveal the Workspace identity surface connected to the GCP Organization. OU membership and policy inheritance are traversed separately through GCP_IN_OU.
  • Identity Pool — Providers and federated Principals hang off Workforce and Workload Identity Pools. The Provider’s issuer and attribute conditions determine who can cross the trust boundary, so enumerating Pool children reveals both existing federation paths and malicious Providers planted through GCP_CREATE_WIF_POOL. This is the precondition for GCP_FEDERATE_IDENTITY.

Two structural observations are worth recording during assessment:

  • Cross-boundary service accounts. A service account’s parent project is not the same as where it holds roles. An SA parented in Project A can hold bindings in Project B, so GCP_PARENT combined with GCP_HAS_ROLE exposes cross-project risk that neither edge shows on its own.
  • Hierarchy sprawl. Many projects parented directly to the organization rather than to folders indicates weak governance and makes consistent folder-level controls impossible to apply.

Mitigation

  1. Grant roles at the narrowest scope that works. Prefer project-level bindings over folder-level, and folder-level over organization-level. Every tier upward multiplies the number of resources the binding reaches through GCP_PARENT.
  2. Minimize organization-level bindings. Restrict roles/resourcemanager.organizationAdmin, roles/iam.securityAdmin, and roles/owner at org scope to break-glass accounts with just-in-time activation.
  3. Separate environments by folder. Keep production and non-production in different folders and never share high-privilege bindings between them.
  4. Do not co-locate high-privilege service accounts with general workloads. Place org-admin and CI/CD service accounts in dedicated admin projects, so a workload project compromise does not expose them.
  5. Organize projects into folders. Projects parented directly to the organization cannot be governed with folder-level controls; move them under appropriately scoped folders.
  6. Minimize Super Admin assignments. Super Admin is always Customer-scoped. Limit it to two or three break-glass accounts with hardware security keys and no day-to-day use.
  7. Audit every Pool’s Providers. Require narrowly scoped attribute conditions and alert on unknown issuers or Providers added to existing Pools.
  8. Bind specific federated subjects instead of whole Pools. Avoid broad pool-wide bindings when a Provider attribute can identify the intended repository, account, tenant, or group.
  9. Audit the hierarchy for inherited bindings regularly. Review folder- and org-level grants on a schedule, since these carry the largest blast radius of any assignment.

Detection

Log Type Method Key Fields
Admin Activity SetIamPolicy Binding added at org, folder, or project scope — note resource.type for the tier
Admin Activity CreateFolder MoveFolder DeleteFolder Folder structure changes that alter inheritance scope
Admin Activity CreateProject MoveProject Project created or reparented under a new container
Admin Activity CreateServiceAccount New service account parented to a project
Admin Activity *compute.instances.insert New VM parented to a project
Admin Activity (GWS) CREATE_ORG_UNIT MOVE_ORG_UNIT Top-level OU created or moved to or from the Customer root
Admin Activity CreateWorkloadIdentityPoolProvider Workload Provider added beneath a Pool
Admin Activity CreateWorkforcePoolProvider Workforce Provider added beneath a Pool
# Organization-scoped IAM changes (highest blast radius)
ORG_ID=$(gcloud organizations list --format="value(name)" | head -1)
gcloud logging read \
'protoPayload.methodName="SetIamPolicy" AND resource.type="organization"' \
--organization=$ORG_ID \
--format="table(timestamp, protoPayload.authenticationInfo.principalEmail, protoPayload.serviceData.policyDelta)"
# Folder-scoped IAM changes and hierarchy moves
gcloud logging read \
'protoPayload.methodName=~"SetIamPolicy|CreateFolder|MoveFolder|DeleteFolder|MoveProject"' \
--organization=$ORG_ID \
--format="table(timestamp, protoPayload.authenticationInfo.principalEmail, protoPayload.methodName, protoPayload.resourceName)"
# New children appearing in a project
PROJECT_ID="my-project"
gcloud logging read \
'protoPayload.methodName="google.iam.admin.v1.CreateServiceAccount" OR protoPayload.methodName=~"compute.instances.insert"' \
--project=$PROJECT_ID \
--format="table(timestamp, protoPayload.authenticationInfo.principalEmail, protoPayload.resourceName)"
# Workload Pool/Provider containment changes
gcloud logging read \
'log_id("cloudaudit.googleapis.com/activity")
AND protoPayload.serviceName="iam.googleapis.com"
AND (protoPayload.methodName:"CreateWorkloadIdentityPoolProvider"
OR protoPayload.methodName:"DeleteWorkloadIdentityPoolProvider")' \
--project=$PROJECT_ID --freshness=400d --limit=1000 \
--format="table(timestamp, protoPayload.authenticationInfo.principalEmail, protoPayload.methodName, protoPayload.resourceName)"

Alert on:

  • Privileged roles (roles/owner, roles/editor, org and folder admin roles) added at organization or folder scope by non-infrastructure accounts.
  • Projects or folders moved so that they inherit broader bindings than before.
  • New projects parented directly to the organization instead of a folder.
  • Service accounts or VMs created in sensitive projects, particularly VMs with high-privilege service accounts attached.
  • New top-level OUs created under the Customer root.
  • Providers created beneath existing Pools, especially with an unknown issuer or an overly broad or missing attributeCondition.

References

Was this page helpful?

Thank you for your feedback.