> 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_can_federate_identity.md).

# GCP\_CAN\_FEDERATE\_IDENTITY

## Summary

|                            |                                  |
| -------------------------- | -------------------------------- |
| **FSProtect ACL Alias**    | GCP\_CAN\_FEDERATE\_IDENTITY     |
| **GCP Alias**              | Persistence & Impersonation      |
| **Affected Object Types**  | Service Accounts                 |
| **Exploitation Certainty** | Certain                          |
| **Granting Roles**         | `roles/iam.workloadIdentityUser` |

## Description

`GCP_CAN_FEDERATE_IDENTITY` indicates that an external identity (e.g., an AWS IAM role, GitHub Actions workflow, or Azure AD managed identity) has been granted `roles/iam.workloadIdentityUser` on a GCP **Service Account** via a **Workload Identity Federation (WIF)** pool. This allows the external identity to exchange its native credential for a short-lived GCP access token that impersonates the target SA.

This edge represents an existing WIF bridge that can be **walked across** — an attacker who controls the external identity (e.g., compromises the AWS account, GitHub repository, or Azure tenant) can immediately impersonate the bound GCP service account without any GCP credentials.

**Key abuse scenarios:**

* Compromise the bound AWS role → exchange AWS STS credentials for GCP SA token.
* Exploit a GitHub Actions workflow in a repository bound to a WIF pool → run code that authenticates as the GCP SA.
* Supply-chain attack on a CI/CD pipeline with WIF binding → steal GCP access on every build.

## Identification

### gcloud CLI

```bash
# Find all WIF pool subjects bound to service accounts
PROJECT_ID="my-project"
for SA in $(gcloud iam service-accounts list --project=$PROJECT_ID --format="value(email)"); do
  POLICY=$(gcloud iam service-accounts get-iam-policy $SA --format=json 2>/dev/null)
  BINDINGS=$(echo $POLICY | jq '.bindings[] | select(.role == "roles/iam.workloadIdentityUser") | {sa: "'$SA'", members: .members}')
  if [ ! -z "$BINDINGS" ]; then
    echo $BINDINGS
  fi
done
```

```bash
# List WIF pools and their providers to understand the trust boundary
gcloud iam workload-identity-pools list --location=global --project=$PROJECT_ID \
  --format="table(name, state)"

for POOL in $(gcloud iam workload-identity-pools list --location=global --project=$PROJECT_ID --format="value(name)"); do
  POOL_ID=$(basename $POOL)
  gcloud iam workload-identity-pools providers list \
    --workload-identity-pool=$POOL_ID \
    --location=global \
    --project=$PROJECT_ID \
    --format="json"
done
```

### GCP Console

1. Open **GCP Console** → **IAM & Admin** → **Workload Identity Federation**.
2. For each pool, review the provider configuration (trusted issuer/account).
3. Open each SA → **Permissions** → check for `Workload Identity User` bindings containing pool subjects.

## Exploitation

The exploitation path depends on which external identity provider is trusted by the WIF pool binding. In all cases the attacker must first control or compromise the trusted external identity, then perform the STS token exchange below.

### GitHub OIDC-backed pool

```bash
# Run from a GitHub Actions workflow in the bound repository
PROJECT_NUMBER="123456789"
POOL_ID="github-pool"
PROVIDER_ID="github-provider"
TARGET_SA="high-priv@target-project.iam.gserviceaccount.com"

# Step 1: Request a GitHub OIDC token scoped to the WIF audience
GITHUB_TOKEN=$(curl -s \
  -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
  "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=//iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${POOL_ID}/providers/${PROVIDER_ID}" \
  | jq -r '.value')

# Step 2: Exchange the OIDC token for a GCP federated access token via STS
FEDERATED_TOKEN=$(curl -s -X POST \
  "https://sts.googleapis.com/v1/token" \
  -H "Content-Type: application/json" \
  -d "{
    \"grantType\": \"urn:ietf:params:oauth:grant-type:token-exchange\",
    \"audience\": \"//iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${POOL_ID}/providers/${PROVIDER_ID}\",
    \"requestedTokenType\": \"urn:ietf:params:oauth:token-type:access_token\",
    \"subjectTokenType\": \"urn:ietf:params:oauth:token-type:id_token\",
    \"subjectToken\": \"$GITHUB_TOKEN\"
  }" | jq -r '.access_token')

# Step 3: Generate a GCP access token for the bound SA
GCP_TOKEN=$(curl -s -X POST \
  -H "Authorization: Bearer $FEDERATED_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"scope": ["https://www.googleapis.com/auth/cloud-platform"]}' \
  "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/${TARGET_SA}:generateAccessToken" \
  | jq -r '.accessToken')

# Step 4: Use the SA token to access GCP resources
curl -H "Authorization: Bearer $GCP_TOKEN" \
  "https://cloudresourcemanager.googleapis.com/v1/projects"
```

### AWS-backed pool

```bash
# Run from an AWS EC2 instance or environment holding the trusted IAM role
TARGET_SA="high-priv@target-project.iam.gserviceaccount.com"

# Authenticate using a WIF credential configuration file
# (generated via: gcloud iam workload-identity-pools create-cred-config)
gcloud auth login --cred-file=/path/to/aws-wif-cred-config.json
gcloud auth print-access-token --impersonate-service-account=$TARGET_SA
```

**Compound path:** Compromise external identity trusted by WIF pool → exchange for GCP SA token → access all resources the SA can reach (Secret Manager, GCS, IAM) → impersonate further SAs via `generateAccessToken`.

**Persistence:** The WIF binding is permanent. Re-compromising any identity trusted by the same pool immediately restores GCP access without requiring IAM changes.

## Mitigation

1. **Audit all WIF bindings** on service accounts, especially privileged ones.
2. **Use narrow attribute conditions** to restrict which external subjects can federate:

   ```
   attribute.repository == 'your-org/your-exact-repo'
   ```
3. **Scope WIF bindings to specific subjects** rather than entire pools (`principalSet://.../*` is too broad).
4. **Monitor external identity providers for compromise** — if a GitHub repo or AWS account is compromised, all bound GCP SAs are at risk.
5. **Regularly review and rotate WIF pool configurations.**

## Detection

| Log Type    | Method                          | Key Fields                                                     |
| ----------- | ------------------------------- | -------------------------------------------------------------- |
| Data Access | `GenerateAccessToken` (via WIF) | `protoPayload.authenticationInfo.serviceAccountDelegationInfo` |

```bash
gcloud logging read \
  'protoPayload.authenticationInfo.principalEmail!="" AND protoPayload.authenticationInfo.serviceAccountDelegationInfo!=""' \
  --project=$PROJECT_ID \
  --format="table(timestamp, protoPayload.authenticationInfo.principalEmail, protoPayload.authenticationInfo.serviceAccountDelegationInfo)"
```

Alert on:

* Token exchanges from unexpected external subjects.
* WIF authentications from repositories or accounts not in an approved allowlist.
* Token generation for privileged SAs via WIF.

## References

* <https://cloud.google.com/iam/docs/workload-identity-federation>
* <https://cloud.google.com/iam/docs/best-practices-for-using-workload-identity-federation>
* <https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/configuring-openid-connect-in-google-cloud-platform>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.forestall.io/fsprotect/edges/gcp/gcp_can_federate_identity.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
