# GCP - Federation Abuse

{{#include ../../../banners/hacktricks-training.md}}

## OIDC - Github Actions Abuse

### GCP

In order to give **access to the Github Actions** from a Github repo to a GCP **service account** the following steps are needed:

- **Create the Service Account** to access from github actions with the **desired permissions:**

```bash
projectId=FIXME
gcloud config set project $projectId

# Create the Service Account
gcloud iam service-accounts create "github-demo-sa"
saId="github-demo-sa@${projectId}.iam.gserviceaccount.com"

# Enable the IAM Credentials API
gcloud services enable iamcredentials.googleapis.com

# Give permissions to SA

gcloud projects add-iam-policy-binding $projectId \
    --member="serviceAccount:$saId" \
    --role="roles/iam.securityReviewer"
```

- Generate a **new workload identity pool**:

```bash
# Create a Workload Identity Pool
poolName=wi-pool

gcloud iam workload-identity-pools create $poolName \
  --location global \
  --display-name $poolName

poolId=$(gcloud iam workload-identity-pools describe $poolName \
  --location global \
  --format='get(name)')
```

- Generate a new **workload identity pool OIDC provider** that **trusts** github actions (by org/repo name in this scenario):

```bash
attributeMappingScope=repository # could be sub (GitHub repository and branch) or repository_owner (GitHub organization)

gcloud iam workload-identity-pools providers create-oidc $poolName \
  --location global \
  --workload-identity-pool $poolName \
  --display-name $poolName \
  --attribute-mapping "google.subject=assertion.${attributeMappingScope},attribute.actor=assertion.actor,attribute.aud=assertion.aud,attribute.repository=assertion.repository" \
  --issuer-uri "https://token.actions.githubusercontent.com"

providerId=$(gcloud iam workload-identity-pools providers describe $poolName \
  --location global \
  --workload-identity-pool $poolName \
  --format='get(name)')
```

- Finally, **allow the principal** from the provider to use a service principal:

```bash
gitHubRepoName="repo-org/repo-name"
gcloud iam service-accounts add-iam-policy-binding $saId \
  --role "roles/iam.workloadIdentityUser" \
  --member "principalSet://iam.googleapis.com/${poolId}/attribute.${attributeMappingScope}/${gitHubRepoName}"
```

> [!WARNING]
> Note how in the previous member we are specifying the **`org-name/repo-name`** as conditions to be able to access the service account (other params that makes it **more restrictive** like the branch could also be used).
>
> However it's also possible to **allow all github to access** the service account creating a provider such the following using a wildcard:

<pre class="language-bash"><code class="lang-bash"># Create a Workload Identity Pool
poolName=wi-pool2

gcloud iam workload-identity-pools create $poolName \
  --location global \
  --display-name $poolName

poolId=$(gcloud iam workload-identity-pools describe $poolName \
  --location global \
  --format='get(name)')

gcloud iam workload-identity-pools providers create-oidc "$poolName" \
  --project="$projectId" \
  --location="global" \
  --workload-identity-pool="$poolName" \
  --display-name="CTF provider" \
  --issuer-uri="https://token.actions.githubusercontent.com" \
  --attribute-mapping="google.subject=assertion.sub,\
attribute.actor=assertion.actor,\
attribute.repository=assertion.repository,\
attribute.aud=assertion.aud" \
  --attribute-condition="assertion.repository_owner!=''"

providerId=$(gcloud iam workload-identity-pools providers describe $poolName \
  --location global \
  --workload-identity-pool $poolName \
  --format='get(name)')

<strong># CHECK THE WILDCARD
</strong>gcloud iam service-accounts add-iam-policy-binding "${saId}" \
  --project="${projectId}" \
  --role="roles/iam.workloadIdentityUser" \
<strong>  --member="principalSet://iam.googleapis.com/${poolId}/*"
</strong></code></pre>

> [!WARNING]
> In this case anyone could access the service account from github actions, so it's important always to **check how the member is defined**.\
> It should be always something like this:
>
> `attribute.{custom_attribute}`:`principalSet://iam.googleapis.com/projects/{project}/locations/{location}/workloadIdentityPools/{pool}/attribute.{custom_attribute}/{value}`

### Github

Remember to change **`${providerId}`** and **`${saId}`** for their respective values:

```yaml
name: Check GCP action
on:
  workflow_dispatch:
  pull_request:
    branches:
      - main

permissions:
  id-token: write

jobs:
  Get_OIDC_ID_token:
    runs-on: ubuntu-latest
    steps:
      - id: "auth"
        name: "Authenticate to GCP"
        uses: "google-github-actions/auth@v2.1.3"
        with:
          create_credentials_file: "true"
          workload_identity_provider: "${providerId}" # In the providerId, the numerical project ID (12 digit number) should be used instead of the alphanumeric project ID. ex: projects/123123123123/locations/global/workloadIdentityPools/iam-lab-7-gh-pool/providers/iam-lab-7-gh-pool-oidc-provider'
          service_account: "${saId}" # <sa-name>@<proj-id>.iam.gserviceaccount.com
          activate_credentials_file: true
      - id: "gcloud"
        name: "gcloud"
        run: |-
          gcloud config set project <project-id>
          gcloud config set account '${saId}'
          gcloud auth login --brief --cred-file="${{ steps.auth.outputs.credentials_file_path }}"
          gcloud auth list
          gcloud projects list
          gcloud secrets list
```

{{#include ../../../banners/hacktricks-training.md}}



