---
title: "Workload Identity Federation"
description: "Connect your GCS or S3 buckets to Baponi without sharing secrets, using cross-project/cross-account trust."
url: https://baponi.ai/docs/guides/workload-identity-federation
lastUpdated: 2026-03-08
---
# Workload Identity Federation
## What is Workload Identity Federation?

Workload Identity Federation (WIF) lets Baponi access your cloud storage buckets without storing any secrets. Instead of sharing service account keys or access credentials, Baponi's cluster proves its identity to your cloud provider using short-lived OIDC tokens. Your cloud verifies the token and grants scoped access -- no keys to rotate, no secrets to store. The trust is cross-project (GCP) or cross-account (AWS), so your data stays in your environment while Baponi gets the minimum access it needs.

## Prerequisites

- A Baponi account with **admin** access
- **GCP**: A project with a GCS bucket and the `gcloud` CLI installed
- **AWS**: An account with an S3 bucket and the `aws` CLI installed

## Setup

1. **Get Baponi's cluster identity**

   In the Baponi console, go to **Settings > WIF Configuration**. Note the **OIDC issuer URL** and **audience** values. You will use these in the next steps.

2. **Create a Workload Identity Pool**

   ```bash
   gcloud iam workload-identity-pools create baponi-pool \
     --location="global" \
     --display-name="Baponi Code Execution"
   ```

3. **Add Baponi as a trusted OIDC provider**

   Replace `OIDC_ISSUER_URL` and `AUDIENCE` with the values from step 1.

   ```bash
   gcloud iam workload-identity-pools providers create-oidc baponi-provider \
     --workload-identity-pool="baponi-pool" \
     --location="global" \
     --issuer-uri="OIDC_ISSUER_URL" \
     --allowed-audiences="AUDIENCE" \
     --attribute-mapping="google.subject=assertion.sub"
   ```

4. **Create a service account for Baponi**

   ```bash
   gcloud iam service-accounts create baponi-storage \
     --display-name="Baponi Storage Access"
   ```

5. **Grant the service account access to your bucket**

   Replace `YOUR_BUCKET` with your GCS bucket name.

   ```bash
   gcloud storage buckets add-iam-policy-binding gs://YOUR_BUCKET \
     --member="serviceAccount:baponi-storage@YOUR_PROJECT.iam.gserviceaccount.com" \
     --role="roles/storage.objectUser"
   ```

6. **Allow Baponi to impersonate the service account**

   Replace `YOUR_PROJECT`, `YOUR_PROJECT_NUMBER`, `YOUR_NAMESPACE`, and `YOUR_SERVICE_ACCOUNT` with your values. For Baponi Cloud, use `baponi` for both namespace and service account. For self-hosted deployments, check the namespace and service account name from your Helm release: `kubectl get sa -n <namespace>`.

   ```bash
   gcloud iam service-accounts add-iam-policy-binding \
     baponi-storage@YOUR_PROJECT.iam.gserviceaccount.com \
     --role="roles/iam.workloadIdentityUser" \
     --member="principalSet://iam.googleapis.com/projects/YOUR_PROJECT_NUMBER/locations/global/workloadIdentityPools/baponi-pool/attribute.sub/system:serviceaccount:YOUR_NAMESPACE:YOUR_SERVICE_ACCOUNT"
   ```

7. **Configure in Baponi**

   Go to **Storage Connections**, click **New Connection**, select **GCS**, choose **Cross-Account WIF**, and enter the pool provider resource name and service account email.

1. **Get Baponi's cluster identity**

   In the Baponi console, go to **Settings > WIF Configuration**. Note the **OIDC issuer URL** and **audience** values. You will use these in the next steps.

2. **Create an OIDC identity provider in AWS**

   Replace `OIDC_ISSUER_URL` and `AUDIENCE` with your values. Get the OIDC issuer's TLS thumbprint first:

   ```bash
   # Extract the TLS certificate thumbprint from the OIDC issuer
   ISSUER_HOST=$(echo "OIDC_ISSUER_URL" | sed 's|https://||')
   THUMBPRINT=$(echo | openssl s_client -servername "$ISSUER_HOST" \
     -showcerts -connect "$ISSUER_HOST:443" 2>/dev/null \
     | openssl x509 -fingerprint -sha1 -noout \
     | sed 's/://g' | cut -d= -f2)
   echo "$THUMBPRINT"
   ```

   Then create the OIDC provider:

   ```bash
   aws iam create-open-id-connect-provider \
     --url "OIDC_ISSUER_URL" \
     --client-id-list "AUDIENCE" \
     --thumbprint-list "$THUMBPRINT"
   ```

3. **Create an IAM role with a trust policy**

   Create a file called `trust-policy.json` with the following content. Replace `YOUR_ACCOUNT_ID`, `OIDC_ISSUER_HOST`, and `AUDIENCE` with your values.

   ```json
   {
     "Version": "2012-10-17",
     "Statement": [{
       "Effect": "Allow",
       "Principal": {
         "Federated": "arn:aws:iam::YOUR_ACCOUNT_ID:oidc-provider/OIDC_ISSUER_HOST"
       },
       "Action": "sts:AssumeRoleWithWebIdentity",
       "Condition": {
         "StringEquals": {
           "OIDC_ISSUER_HOST:aud": "AUDIENCE",
           "OIDC_ISSUER_HOST:sub": "system:serviceaccount:YOUR_NAMESPACE:YOUR_SERVICE_ACCOUNT"
         }
       }
     }]
   }
   ```

   Then create the role:

   ```bash
   aws iam create-role \
     --role-name baponi-storage-access \
     --assume-role-policy-document file://trust-policy.json
   ```

4. **Attach S3 access policy**

   Replace `YOUR_BUCKET` with your S3 bucket name.

   ```bash
   aws iam put-role-policy \
     --role-name baponi-storage-access \
     --policy-name BaponiS3Access \
     --policy-document '{
       "Version": "2012-10-17",
       "Statement": [{
         "Effect": "Allow",
         "Action": [
           "s3:GetObject",
           "s3:PutObject",
           "s3:ListBucket",
           "s3:DeleteObject"
         ],
         "Resource": [
           "arn:aws:s3:::YOUR_BUCKET",
           "arn:aws:s3:::YOUR_BUCKET/*"
         ]
       }]
     }'
   ```

5. **Configure in Baponi**

   Go to **Storage Connections**, click **New Connection**, select **AWS S3**, choose **Cross-Account WIF**, and enter the IAM Role ARN.

## Verify the Connection

Run a quick test to confirm the connection works. Execute code in a Baponi sandbox that reads from or writes to your bucket:

```python

# List files in the mounted storage
files = os.listdir("/data")
print(f"Connected. Found {len(files)} files in /data")

# Write a test file
with open("/data/wif-test.txt", "w") as f:
    f.write("WIF connection verified.")

print("Write succeeded.")
```

If the execution completes without errors, WIF is configured correctly.

## Troubleshooting

Verify the WIF pool (GCP) or OIDC identity provider (AWS) trusts the correct OIDC issuer URL and audience. These must match the values shown in **Settings > WIF Configuration** exactly.

WIF authentication succeeded, but the service account (GCP) or IAM role (AWS) lacks the required bucket permissions. Check that `roles/storage.objectUser` (GCP) or the S3 policy (AWS) is attached and references the correct bucket.

The `allowed-audiences` in your WIF provider (GCP) or `client-id-list` in your OIDC provider (AWS) does not match the audience configured in Baponi. Copy the exact audience string from **Settings > WIF Configuration**.

The OIDC issuer URL does not match between Baponi and your cloud provider setup. Ensure you used the full issuer URL (including `https://`) when creating the WIF provider or OIDC identity provider.

## FAQ

**How long do tokens last?**
Default 1 hour. Kubernetes automatically rotates tokens at 80% of expiry -- no manual renewal needed.

**How do I revoke access?**
Delete the WIF pool provider (GCP) or remove the OIDC identity provider trust (AWS). Access is revoked immediately.

**What information does Baponi store?**
Only the WIF pool provider resource name (GCP) or IAM Role ARN (AWS). No secrets, no keys, no credentials.

**Can I audit token usage?**
Yes. GCP Cloud Audit Logs and AWS CloudTrail both log STS token exchanges, giving you full visibility into when and how tokens are used.