> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reducto.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# AWS

> Call Reducto from AWS with outbound identity federation tokens or Amazon EKS service account tokens instead of a stored API key.

AWS workloads can use either of two token sources:

* **AWS outbound identity federation**: an IAM role requests a signed JWT from AWS STS with `GetWebIdentityToken`. Works on EC2, ECS, Lambda and anywhere else the role has credentials.
* **Amazon EKS**: a pod uses a projected Kubernetes service account token issued by the cluster.

Reducto does not accept SigV4 signatures or STS access keys. It needs a JWT.

## AWS outbound identity federation

### Enable outbound federation

Enable outbound identity federation once per AWS account. See AWS's [getting started guide](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_outbound_getting_started.html).

```bash theme={null}
aws iam enable-outbound-web-identity-federation
```

The command returns your account's issuer URL. You enter it as the Reducto provider issuer.

Allow the workload's role to request tokens only for the Reducto audience, with a short lifetime:

```json theme={null}
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "sts:GetWebIdentityToken",
      "Resource": "*",
      "Condition": {
        "ForAllValues:StringEquals": {
          "sts:IdentityTokenAudience": "https://platform.reducto.ai"
        },
        "NumericLessThanEquals": {
          "sts:DurationSeconds": 300
        }
      }
    }
  ]
}
```

`GetWebIdentityToken` is not available on the global STS endpoint. Set a region so that the token request goes to a regional endpoint. The AWS CLI and the Node.js SDK read `AWS_REGION`. Boto3 reads `AWS_DEFAULT_REGION` and not `AWS_REGION`, so in Python set `AWS_DEFAULT_REGION` or pass `sts_client=boto3.client("sts", region_name="us-west-2")`.

### Get and inspect a token

```bash theme={null}
SUBJECT_TOKEN=$(aws sts get-web-identity-token \
  --audience "https://platform.reducto.ai" \
  --signing-algorithm ES384 \
  --duration-seconds 300 \
  --query WebIdentityToken --output text)
cut -d. -f2 <<< "$SUBJECT_TOKEN" | tr '_-' '/+' | base64 -d 2>/dev/null | jq .
```

```json theme={null}
{
  "iss": "https://3f8a1c2e-7b4d-4e9a-b6c5-0d1e2f3a4b5c.tokens.sts.global.api.aws",
  "aud": "https://platform.reducto.ai",
  "sub": "arn:aws:iam::123456789012:role/invoice-parser",
  "iat": 1793322245,
  "exp": 1793322545,
  "jti": "5b8e2d1f-9c3a-4f7e-a6b0-2d4c8e1f3a5b",
  "https://sts.amazonaws.com/": {
    "aws_account": "123456789012",
    "source_region": "us-west-2",
    "org_id": "o-a1b2c3d4e5",
    "principal_tags": {
      "environment": "production"
    }
  }
}
```

`sub` is the ARN of the role. AWS-specific claims sit in a nested object under `https://sts.amazonaws.com/`, and which ones appear depends on the session.

### Configure Reducto

In [Studio](https://studio.reducto.ai), open **Settings > Workload identity** and create a provider with the **AWS** preset:

| Field | Value |
| - | - |
| **Name** | `aws-prod` |
| **Issuer** | Your account's issuer URL, for example `https://3f8a1c2e-7b4d-4e9a-b6c5-0d1e2f3a4b5c.tokens.sts.global.api.aws` |
| **Audience** | `https://platform.reducto.ai` |
| **Key source** | OIDC discovery |

Add a mapping for the role:

| Key | Value |
| - | - |
| `sub` | `arn:aws:iam::123456789012:role/invoice-parser` |

To match a nested claim, add a transformation on the provider, then match the attribute. For example, add a transformation with `attribute` = `reducto.aws_environment` and `claim` = `["https://sts.amazonaws.com/", "principal_tags", "environment"]`. Then add the mapping condition `reducto.aws_environment` = `production`.

If the claim is missing from a token, the transformation fails and so does the exchange. Check a sample token first.

### Call Reducto

The AWS token provider needs `boto3` in Python or `@aws-sdk/client-sts` in Node.js. It uses the default AWS credential chain.

```python Python theme={null}
import os

from reducto import Reducto
from reducto.auth import aws_web_identity_token_provider

client = Reducto(
    workload_identity={
        "identity_provider_id": os.environ["REDUCTO_IDENTITY_PROVIDER_ID"],
        "provider": aws_web_identity_token_provider(),
    }
)

result = client.parse.run(input="https://cdn.reducto.ai/samples/fidelity-example.pdf")
print(result.result.chunks[0].content[:500])
```

```javascript Node.js theme={null}
import Reducto from "reductoai";
import { awsWebIdentityTokenProvider } from "reductoai/auth";

const client = new Reducto({
  workloadIdentity: {
    identityProviderId: process.env.REDUCTO_IDENTITY_PROVIDER_ID,
    provider: awsWebIdentityTokenProvider(),
  },
});

const result = await client.parse.run({
  input: "https://cdn.reducto.ai/samples/fidelity-example.pdf",
});
console.log(result.result.chunks[0].content.slice(0, 500));
```

```bash cURL theme={null}
SUBJECT_TOKEN=$(aws sts get-web-identity-token \
  --audience "https://platform.reducto.ai" \
  --signing-algorithm ES384 \
  --duration-seconds 300 \
  --query WebIdentityToken --output text)

ACCESS_TOKEN=$(jq -n \
  --arg subject_token "$SUBJECT_TOKEN" \
  --arg provider_id "$REDUCTO_IDENTITY_PROVIDER_ID" \
  '{
    grant_type: "urn:ietf:params:oauth:grant-type:token-exchange",
    subject_token_type: "urn:ietf:params:oauth:token-type:jwt",
    subject_token: $subject_token,
    identity_provider_id: $provider_id
  }' \
  | curl -sS --fail-with-body -X POST "https://platform.reducto.ai/oauth/token" \
      -H "Content-Type: application/json" -d @- \
  | jq -r .access_token)

curl -X POST "https://platform.reducto.ai/parse" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"input":"https://cdn.reducto.ai/samples/fidelity-example.pdf"}'
```

`aws_web_identity_token_provider(audience=..., signing_algorithm=..., duration_seconds=...)` in Python and `awsWebIdentityTokenProvider({ audience, signingAlgorithm, durationSeconds })` in Node.js set the request. The audience defaults to `https://platform.reducto.ai` and the signing algorithm to `RS256` (`ES384` is the other option). In Node.js, install the optional peer dependency `@aws-sdk/client-sts`.

A 300-second AWS token gives an access token of at most 300 seconds. The SDK requests a new AWS token for each exchange, so the short lifetime only means more frequent exchanges.

## Amazon EKS

EKS clusters publish a public OIDC issuer, so Reducto can use OIDC discovery.

Get the cluster's issuer:

```bash theme={null}
aws eks describe-cluster --name payments-prod --region us-west-2 \
  --query "cluster.identity.oidc.issuer" --output text
```

```text theme={null}
https://oidc.eks.us-west-2.amazonaws.com/id/8A1F2C3D4E5B6A7F8091A2B3C4D5E6F7
```

Create a service account and mount a projected token with the Reducto audience, as in the [Kubernetes guide](https://docs.reducto.ai/security/workload-identity-federation/kubernetes.md#set-up-the-cluster). EKS tokens use the same claims, with the EKS issuer:

```json theme={null}
{
  "iss": "https://oidc.eks.us-west-2.amazonaws.com/id/8A1F2C3D4E5B6A7F8091A2B3C4D5E6F7",
  "aud": ["https://platform.reducto.ai"],
  "sub": "system:serviceaccount:payments:reducto-client",
  "iat": 1793322245,
  "exp": 1793325845,
  "kubernetes.io": {
    "namespace": "payments",
    "serviceaccount": {
      "name": "reducto-client",
      "uid": "2d3e4f5a-6b7c-4d8e-9f0a-1b2c3d4e5f6a"
    }
  }
}
```

Create a provider with the **Amazon EKS** preset:

| Field | Value |
| - | - |
| **Name** | `eks-payments-prod` |
| **Issuer** | `https://oidc.eks.us-west-2.amazonaws.com/id/8A1F2C3D4E5B6A7F8091A2B3C4D5E6F7` |
| **Audience** | `https://platform.reducto.ai` |
| **Key source** | OIDC discovery |

Add a mapping with `sub` = `system:serviceaccount:payments:reducto-client`. Then use `k8s_service_account_token_provider("/var/run/secrets/reducto/token")` (Python) or `k8sServiceAccountTokenProvider("/var/run/secrets/reducto/token")` (Node.js), as shown in the [Kubernetes guide](https://docs.reducto.ai/security/workload-identity-federation/kubernetes.md#call-reducto-from-the-pod).

Do not use the IRSA token at `AWS_WEB_IDENTITY_TOKEN_FILE` for Reducto. Its audience is `sts.amazonaws.com`. Mount a separate projected token with the Reducto audience.

## AWS best practices

* Use one IAM role or one Kubernetes service account per workload, and match its exact ARN or `sub`.
* Restrict `sts:IdentityTokenAudience` and `sts:DurationSeconds` in IAM so roles can mint tokens only for Reducto, with short lifetimes.
* Add account or organization conditions through transformations when several accounts share an issuer setup.
* Read EKS projected tokens from the file on every exchange so rotated tokens are used.
