> For the complete documentation index, see [llms.txt](https://docs.forestall.io/fsprotect/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.forestall.io/fsprotect/edges/gcp/gcp_has_role.md).

# GCP\_HAS\_ROLE

## Summary

|                            |                              |
| -------------------------- | ---------------------------- |
| **FSProtect 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

```bash
# List all roles granted to a specific user at project level
PROJECT_ID="my-project"
USER_EMAIL="user@example.com"
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
SA_EMAIL="my-sa@my-project.iam.gserviceaccount.com"
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]'
```

### GCP Console

1. Open **GCP Console** → **IAM & Admin** → **IAM**.
2. Each row in the IAM table represents a `GCP_HAS_ROLE` edge between the listed principal and the shown role.
3. Use the **Principal** filter to view all roles held by a specific identity.
4. The **Inheritance** tag indicates bindings from parent scope resources.

## 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 |

```bash
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

* <https://cloud.google.com/iam/docs/overview>
* <https://cloud.google.com/iam/docs/policies>
* <https://cloud.google.com/iam/docs/conditions-overview>
