> For the complete documentation index, see [llms.txt](https://docs.warpstream.com/warpstream/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.warpstream.com/warpstream/kafka/advanced-agent-deployment-options/workload-identity-federation.md).

# Workload Identity Federation

By default, a WarpStream Agent authenticates to the control plane with a long-lived Agent Key (`aks_...`) that you provision and set via `WARPSTREAM_AGENT_KEY`. Long-lived secrets have to be distributed, rotated, and revoked out of band, and a leaked key is valid until you notice and rotate it.

**Workload Identity Federation** removes the static secret. Instead, the Agent proves its identity using a token minted by its own cloud platform (AWS or GCP) and exchanges it with the control plane for a **short-lived, cluster-scoped credential**. There is no static secret to store on the Agent, and access is tied to the cloud IAM identity the Agent already runs as.

### How it works

1. On startup, the Agent asks its cloud platform for a signed OIDC token identifying the workload:
   * **AWS** — the Agent calls STS [`GetWebIdentityToken`](https://docs.aws.amazon.com/STS/latest/APIReference/API_GetWebIdentityToken.html) using its ambient IAM role. The role's ARN ends up in the token's `sub` claim.
   * **GCP** — the Agent fetches an identity token from the [instance metadata server](https://cloud.google.com/compute/docs/instances/verifying-instance-identity). The workload's service account email ends up in the token's `email` claim.
2. The Agent exchanges that OIDC token with the WarpStream control plane. The requested audience is always your **Virtual Cluster ID** (`vci_...`).
3. The control plane looks up the **federation binding(s)** you configured on that Virtual Cluster and, for the first binding whose issuer and claim rules match the token, mints a short-lived Agent credential (a `wsa_` token) scoped to that cluster.
4. The Agent uses the `wsa_` token exactly like an Agent Key and refreshes it automatically in the background before it expires.

A binding never grants access on a valid signature alone — every configured claim rule must match, so only the specific IAM role or service account you name can authenticate.

### Supported identity providers

Workload Identity Federation currently supports the following token sources, selected with the `WARPSTREAM_AGENT_WORKLOAD_IDENTITY_TOKEN_SOURCE` Agent environment variable:

| Provider | `WARPSTREAM_AGENT_WORKLOAD_IDENTITY_TOKEN_SOURCE` | OIDC issuer                                |
| -------- | ------------------------------------------------- | ------------------------------------------ |
| AWS      | `aws`                                             | `https://<uuid>.tokens.sts.global.api.aws` |
| GCP      | `gcp`                                             | `https://accounts.google.com`              |

Support for additional providers will be added over time. [Reach out](https://www.warpstream.com/contact-us) if you need one that isn't listed yet.

### Before you begin

You will need:

* A Virtual Cluster (note its `vci_...` ID).
* Permission to create bindings on that cluster: a WarpStream **Application Key** for the API/Terraform, generated in the admin console. See [Secrets Overview](/warpstream/reference/secrets-overview.md).
* Agents running in a cloud environment with an identity you control — an AWS IAM role (for example an EKS IRSA / Pod Identity role) or a GCP service account.

Setup is three steps: prepare the cloud identity, create the federation binding, then point the Agent at Workload Identity.

## Step 1 — Prepare the cloud identity

{% tabs %}
{% tab title="AWS" %}
**1. Enable outbound identity federation on your AWS account.** This is a one-time, account-wide action that provisions your account's OIDC issuer URL. See [Getting started with outbound identity federation](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_outbound_getting_started.html).

{% code overflow="wrap" %}

```bash
aws iam enable-outbound-web-identity-federation
```

{% endcode %}

The response contains your account-specific **issuer URL**, which looks like `https://<uuid>.tokens.sts.global.api.aws`. You'll need it in Step 2. If you enabled the feature previously, retrieve the URL again at any time:

{% code overflow="wrap" %}

```bash
aws iam get-outbound-web-identity-federation-info
```

{% endcode %}

You can also find it in the IAM console under **Access management → Account settings → Outbound identity federation**.

**2. Grant the Agent's IAM role permission to mint tokens.** Attach a policy allowing `sts:GetWebIdentityToken` to the role your Agents run as. Restrict the audience to your Virtual Cluster ID so the role can only mint tokens for WarpStream:

{% code overflow="wrap" %}

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "MintWarpStreamWorkloadIdentityToken",
      "Effect": "Allow",
      "Action": "sts:GetWebIdentityToken",
      "Resource": "*",
      "Condition": {
        "ForAllValues:StringEquals": {
          "sts:IdentityTokenAudience": "vci_XXXXXXXXXX"
        },
        "NumericLessThanEquals": {
          "sts:DurationSeconds": "3600"
        }
      }
    }
  ]
}
```

{% endcode %}

To let one role authenticate to several WarpStream clusters, list each Virtual Cluster ID as an allowed audience:

{% code overflow="wrap" %}

```json
"ForAllValues:StringEquals": {
  "sts:IdentityTokenAudience": ["vci_YYYYYYYYYY", "vci_ZZZZZZZZZZ"]
}
```

{% endcode %}
{% endtab %}

{% tab title="GCP" %}
No extra IAM permissions are required — any workload can fetch its own identity token from the GCP metadata server.

Just make sure your Agents run **as the service account you intend to authorize**, and note that service account's email (for example `warp-agent@my-project.iam.gserviceaccount.com`). You'll use it in the binding's claim rule in Step 2.

* On GKE, associate the Agent's Kubernetes service account with the Google service account using [Workload Identity Federation for GKE](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity).
* On Compute Engine, this is the VM's attached service account.
  {% endtab %}
  {% endtabs %}

## Step 2 — Create the federation binding

A binding tells the control plane which OIDC issuer and claims to accept for a given Virtual Cluster. Create it with Terraform (recommended) or the API.

### Terraform

Use the [`warpstream_workload_identity_federation`](https://registry.terraform.io/providers/warpstreamlabs/warpstream/latest/docs/resources/workload_identity_federation) resource (provider `v2.7.10`+):

{% tabs %}
{% tab title="AWS" %}
{% code overflow="wrap" %}

```hcl
resource "warpstream_workload_identity_federation" "aws_agents" {
  virtual_cluster_id         = "vci_XXXXXXXXXX"
  name                       = "aws-agents"
  issuer_url                 = "https://<uuid>.tokens.sts.global.api.aws"
  read_only                  = false
  max_credential_ttl_seconds = 3600

  claim_match_rules = [
    {
      claim_path = "sub"
      # Replace with the ARN of the AWS IAM role your Agents are deployed with.
      expected_value = "arn:aws:iam::123456789012:role/warp-agent"
    },
  ]
}
```

{% endcode %}
{% endtab %}

{% tab title="GCP" %}
{% code overflow="wrap" %}

```hcl
resource "warpstream_workload_identity_federation" "gcp_agents" {
  virtual_cluster_id         = "vci_XXXXXXXXXX"
  name                       = "gcp-agents"
  issuer_url                 = "https://accounts.google.com"
  read_only                  = false
  max_credential_ttl_seconds = 3600

  claim_match_rules = [
    {
      claim_path = "email"
      # Replace with the email of the GCP service account your Agents are deployed with.
      expected_value = "warp-agent@my-project.iam.gserviceaccount.com"
    },
  ]
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

### API

Send a `POST` to `create_workload_identity_federation` with your Application Key in the `warpstream-api-key` header:

{% tabs %}
{% tab title="AWS" %}
{% code overflow="wrap" %}

```bash
curl https://api.warpstream.com/api/v1/create_workload_identity_federation \
  -H 'warpstream-api-key: XXXXXXXXXX' \
  -H 'Content-Type: application/json' \
  -d '{
    "virtual_cluster_id": "vci_XXXXXXXXXX",
    "name": "aws-agents",
    "issuer_url": "https://<uuid>.tokens.sts.global.api.aws",
    "read_only": false,
    "max_credential_ttl_seconds": 3600,
    "claim_match_rules": [
      { "claim_path": "sub", "expected_value": "arn:aws:iam::123456789012:role/warp-agent" }
    ]
  }'
```

{% endcode %}
{% endtab %}

{% tab title="GCP" %}
{% code overflow="wrap" %}

```bash
curl https://api.warpstream.com/api/v1/create_workload_identity_federation \
  -H 'warpstream-api-key: XXXXXXXXXX' \
  -H 'Content-Type: application/json' \
  -d '{
    "virtual_cluster_id": "vci_XXXXXXXXXX",
    "name": "gcp-agents",
    "issuer_url": "https://accounts.google.com",
    "read_only": false,
    "max_credential_ttl_seconds": 3600,
    "claim_match_rules": [
      { "claim_path": "email", "expected_value": "warp-agent@my-project.iam.gserviceaccount.com" }
    ]
  }'
```

{% endcode %}
{% endtab %}
{% endtabs %}

List the bindings on a cluster:

{% code overflow="wrap" %}

```bash
curl https://api.warpstream.com/api/v1/list_workload_identity_federations \
  -H 'warpstream-api-key: XXXXXXXXXX' \
  -H 'Content-Type: application/json' \
  -d '{"virtual_cluster_id": "vci_XXXXXXXXXX"}'
```

{% endcode %}

Delete a binding by its `wif_...` ID (from the list response):

{% code overflow="wrap" %}

```bash
curl https://api.warpstream.com/api/v1/delete_workload_identity_federation \
  -H 'warpstream-api-key: XXXXXXXXXX' \
  -H 'Content-Type: application/json' \
  -d '{"virtual_cluster_id": "vci_XXXXXXXXXX", "id": "wif_XXXXXXXXXX"}'
```

{% endcode %}

{% hint style="info" %}
You can create multiple bindings on one Virtual Cluster — for example, one per availability zone if each zone's Agents run as a different IAM role or service account. Binding names must be unique within a cluster. The control plane tries each binding and mints a credential for the first one whose claims match.
{% endhint %}

## Step 3 — Configure the Agent

Set the token source on the Agent and **remove the static Agent Key** — the two are mutually exclusive.

{% tabs %}
{% tab title="AWS" %}
{% code overflow="wrap" %}

```bash
WARPSTREAM_AGENT_WORKLOAD_IDENTITY_TOKEN_SOURCE=aws
```

{% endcode %}
{% endtab %}

{% tab title="GCP" %}
{% code overflow="wrap" %}

```bash
WARPSTREAM_AGENT_WORKLOAD_IDENTITY_TOKEN_SOURCE=gcp
```

{% endcode %}
{% endtab %}
{% endtabs %}

The equivalent command-line flag is `-workloadIdentityTokenSource aws` (or `gcp`). Do not also set `WARPSTREAM_AGENT_KEY`, `WARPSTREAM_AGENT_KEY_PATH`, or `WARPSTREAM_API_KEY`; the Agent will refuse to start if a static key is combined with a workload identity token source.

On startup the Agent exchanges a token per region and begins refreshing it automatically. If authentication fails, the Agent logs the exchange failure; the most common causes are a missing IAM permission (AWS), the wrong role/service-account identity in the claim rule, or the account's issuer URL not matching the binding.

## Reference

### Binding fields

| Field                        | Required | Description                                                                                                                                            |
| ---------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `virtual_cluster_id`         | yes      | The Virtual Cluster (`vci_...`) the binding grants access to.                                                                                          |
| `name`                       | yes      | Human-readable name, unique within the cluster (3–128 characters).                                                                                     |
| `issuer_url`                 | yes      | HTTPS URL of the OIDC issuer whose tokens this binding accepts (your AWS account issuer, or `https://accounts.google.com`).                            |
| `claim_match_rules`          | yes      | One or more rules; **all** must match. See below.                                                                                                      |
| `read_only`                  | no       | If `true`, the minted credential is read-only. Defaults to `false`.                                                                                    |
| `max_credential_ttl_seconds` | no       | Maximum lifetime of a minted credential, between `60` (1 minute) and `86400` (24 hours). Defaults to `3600`.                                           |
| `audience`                   | —        | Read-only. Always the Virtual Cluster ID; derived by the control plane and not configurable. This is the audience the Agent's OIDC token must request. |

Bindings are immutable — to change a binding, delete it and create a new one.

### Claim matching

Each rule is a `claim_path` / `expected_value` pair:

* **`claim_path`** is a dot-separated path into the token's claims (e.g. `sub`, `email`, or a nested `context.namespace`). If a single path segment itself contains a literal dot, wrap that segment in double quotes, e.g. `"kubernetes.io".namespace`.
* **`expected_value`** is matched **case-sensitively**. A single trailing `*` acts as a prefix wildcard (`arn:aws:iam::123456789012:role/warp-*`); a `*` anywhere else is treated literally.

All rules in a binding are ANDed together, and at least one rule is always required — a token is never accepted on a valid signature and audience alone.

### Common claims

| Cloud | `issuer_url`                               | Claim to match | Example value                                   |
| ----- | ------------------------------------------ | -------------- | ----------------------------------------------- |
| AWS   | `https://<uuid>.tokens.sts.global.api.aws` | `sub`          | `arn:aws:iam::123456789012:role/warp-agent`     |
| GCP   | `https://accounts.google.com`              | `email`        | `warp-agent@my-project.iam.gserviceaccount.com` |

For the full list of claims available in an AWS token, see [Understanding token claims](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_outbound.html).


---

# 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, and the optional `goal` query parameter:

```
GET https://docs.warpstream.com/warpstream/kafka/advanced-agent-deployment-options/workload-identity-federation.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
