> ## Documentation Index
> Fetch the complete documentation index at: https://test-8862363a-tembo-update-free-byok-chatgpt-copy.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# AWS

> Give your agents access to any AWS service via OIDC web identity federation — no static credentials required.

<Frame>
  <img src="https://mintcdn.com/test-8862363a-tembo-update-free-byok-chatgpt-copy/JEx-9S7rjWsVyvf2/images/integrations/aws.png?fit=max&auto=format&n=JEx-9S7rjWsVyvf2&q=85&s=a0f6470ef97d2a29d6655a89c6f339a1" alt="AWS" width="2560" height="1440" data-path="images/integrations/aws.png" />
</Frame>

Tembo acts as an OIDC identity provider. Your agents receive short-lived STS credentials that expire automatically — no AWS access keys are ever stored in Tembo.

Connecting an account takes two things: an OIDC provider and an IAM role in your AWS account. You can let Tembo's CloudFormation template create both, or create them yourself with your own tooling.

## What agents can do

Once connected, agents have access to the [AWS Agent Toolkit](https://github.com/awslabs/mcp/tree/main/src/aws-api) — AWS's official MCP service covering 15,000+ APIs across every AWS service:

* **`call_aws`** — execute any authenticated AWS API call
* **`suggest_aws_commands`** — translate natural language to AWS API calls
* **`run_script`** — run Python code with AWS API access in a sandboxed environment
* **`search_documentation` / `read_documentation`** — search and read all AWS documentation
* **`get_presigned_url`** — generate pre-signed S3 URLs

Agents can only do what the IAM role permits. The default is `ReadOnlyAccess`; you control this entirely.

## Before you start

You need permission to create IAM roles and identity providers in the target AWS account.

<Note>
  Connect as many AWS accounts as you like. Each gets its own label and an isolated MCP server session, so a `production` and a `staging` account never share credentials.
</Note>

## Choose a setup method

<CardGroup cols={2}>
  <Card title="Use the CloudFormation template" icon="cloud" href="#option-1-use-the-cloudformation-template">
    Fastest path. Tembo gives you a template that creates the OIDC provider and role for you.
  </Card>

  <Card title="Create the resources yourself" icon="wrench" href="#option-2-create-the-resources-yourself">
    Use your own Terraform, CDK, Pulumi, or the AWS CLI. Full requirements below.
  </Card>
</CardGroup>

Both produce identical results. Tembo only needs the finished role ARN.

## Option 1: Use the CloudFormation template

<Steps>
  <Step title="Open the connect modal">
    Go to [Integrations](https://app.tembo.io/integrations) and click **Connect** next to AWS. Enter a name for this account, for example `production`.
  </Step>

  <Step title="Deploy the stack">
    Click **Create via CloudFormation** to open a pre-filled stack in your AWS console, then deploy it.

    If that link returns "Access Denied", download the template from the connect modal and upload it manually instead: in the [CloudFormation console](https://console.aws.amazon.com/cloudformation), choose **Create stack → With new resources → Upload a template file**, then supply your [workspace ID](#find-your-workspace-id) when prompted.
  </Step>

  <Step title="Copy the role ARN">
    When the stack completes, open its **Outputs** tab and copy the `RoleArn` value.
  </Step>

  <Step title="Finish in Tembo">
    Back in the connect modal, switch to **Enter ARN manually**, paste the ARN, and click **Connect**.
  </Step>
</Steps>

## Option 2: Create the resources yourself

Create two resources in the AWS account you want to connect, then hand Tembo the role ARN.

### Find your workspace ID

The role's trust policy has to name the workspace allowed to assume it. In Tembo, go to **Settings → Workspace** and copy the value under **Workspace ID**.

The value starts with `org_`, because a workspace is an organization internally. That's why the trust policy's subject is `org:` followed by this value.

### Requirements

| Setting                           | Value                                                        |
| --------------------------------- | ------------------------------------------------------------ |
| OIDC provider URL                 | `https://internal.tembo.io`                                  |
| Audience (client ID)              | `sts.amazonaws.com`                                          |
| Trust policy action               | `sts:AssumeRoleWithWebIdentity`                              |
| `internal.tembo.io:aud` condition | `sts.amazonaws.com`                                          |
| `internal.tembo.io:sub` condition | `org:<your-workspace-id>`                                    |
| Max session duration              | 3600 seconds                                                 |
| Permissions                       | Your choice. `ReadOnlyAccess` is the default Tembo suggests. |

Three details are easy to get wrong:

* **The provider must live in the same AWS account as the role.** AWS resolves the federated principal locally when the role is assumed, so a provider in another account will not work.
* **The condition keys drop the scheme.** They are `internal.tembo.io:sub`, not `https://internal.tembo.io:sub`.
* **The subject is prefixed.** If your workspace ID is `org_2vyf1Ja...`, the `sub` value is `org:org_2vyf1Ja...` — the literal string `org:` followed by the full ID.

<Warning>
  Always pin the `sub` condition to your workspace ID. The OIDC provider only proves that Tembo signed the token, not which workspace it was issued for. Without the `sub` condition, a token issued to any other Tembo workspace would satisfy your trust policy.
</Warning>

### The OIDC provider

Register `https://internal.tembo.io` as an IAM OIDC identity provider with `sts.amazonaws.com` as the only audience.

You only need one per AWS account. IAM identity providers are global, so if you manage infrastructure per-region, create it once rather than once per region. If the provider already exists in the account, reuse it instead of creating a second one.

Thumbprints do not need maintaining. AWS verifies the JWKS endpoint's TLS certificate against its own library of trusted root certificate authorities, and only falls back to the configured thumbprint if the certificate is not signed by one of those. Tembo's endpoint uses a publicly trusted certificate, so a placeholder value of forty zeroes is fine.

### The IAM role

Attach this trust policy, replacing the account ID and workspace ID:

```json Trust policy theme={null}
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::111122223333:oidc-provider/internal.tembo.io"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "internal.tembo.io:aud": "sts.amazonaws.com",
          "internal.tembo.io:sub": "org:org_2vyf1Ja..."
        }
      }
    }
  ]
}
```

Then attach permissions. Start with `arn:aws:iam::aws:policy/ReadOnlyAccess` and narrow or widen it to suit. Set the role's maximum session duration to 3600 seconds to match the session length Tembo requests.

The role name does not matter — Tembo identifies the role by ARN.

### Terraform

```hcl theme={null}
resource "aws_iam_openid_connect_provider" "tembo" {
  url             = "https://internal.tembo.io"
  client_id_list  = ["sts.amazonaws.com"]
  thumbprint_list = ["0000000000000000000000000000000000000000"]
}

data "aws_iam_policy_document" "tembo_assume_role" {
  statement {
    effect  = "Allow"
    actions = ["sts:AssumeRoleWithWebIdentity"]

    principals {
      type        = "Federated"
      identifiers = [aws_iam_openid_connect_provider.tembo.arn]
    }

    condition {
      test     = "StringEquals"
      variable = "internal.tembo.io:aud"
      values   = ["sts.amazonaws.com"]
    }

    condition {
      test     = "StringEquals"
      variable = "internal.tembo.io:sub"
      values   = ["org:${var.tembo_workspace_id}"]
    }
  }
}

resource "aws_iam_role" "tembo" {
  name                 = "tembo-integration"
  assume_role_policy   = data.aws_iam_policy_document.tembo_assume_role.json
  max_session_duration = 3600
}

resource "aws_iam_role_policy_attachment" "tembo_read_only" {
  role       = aws_iam_role.tembo.name
  policy_arn = "arn:aws:iam::aws:policy/ReadOnlyAccess"
}

output "tembo_role_arn" {
  value = aws_iam_role.tembo.arn
}
```

### AWS CLI

```bash theme={null}
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
TEMBO_WORKSPACE_ID=org_2vyf1Ja...   # from Settings → Workspace

aws iam create-open-id-connect-provider \
  --url https://internal.tembo.io \
  --client-id-list sts.amazonaws.com \
  --thumbprint-list 0000000000000000000000000000000000000000

cat > trust-policy.json <<EOF
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": { "Federated": "arn:aws:iam::${ACCOUNT_ID}:oidc-provider/internal.tembo.io" },
    "Action": "sts:AssumeRoleWithWebIdentity",
    "Condition": {
      "StringEquals": {
        "internal.tembo.io:aud": "sts.amazonaws.com",
        "internal.tembo.io:sub": "org:${TEMBO_WORKSPACE_ID}"
      }
    }
  }]
}
EOF

aws iam create-role \
  --role-name tembo-integration \
  --assume-role-policy-document file://trust-policy.json \
  --max-session-duration 3600

aws iam attach-role-policy \
  --role-name tembo-integration \
  --policy-arn arn:aws:iam::aws:policy/ReadOnlyAccess

aws iam get-role --role-name tembo-integration --query 'Role.Arn' --output text
```

### Connect it

Paste the role ARN into the Tembo connect modal under **Enter ARN manually** and click **Connect**.

<Note>
  **Self-hosted Tembo:** replace `internal.tembo.io` throughout with your instance's `TEMBO_OIDC_ISSUER` hostname, scheme stripped. Your instance must serve `/.well-known/openid-configuration` and `/.well-known/jwks.json` over public HTTPS, because AWS STS fetches the JWKS itself when a role is assumed — reachability from inside your own network is not enough.
</Note>

## How authentication works

Tembo never stores AWS credentials. For each agent run:

1. Tembo mints a short-lived RS256 JWT (5-minute TTL) signed with its OIDC private key, carrying `iss` of the Tembo issuer, `aud` of `sts.amazonaws.com`, and `sub` of `org:<your-workspace-id>`
2. Tembo calls `sts:AssumeRoleWithWebIdentity` against your role, presenting that JWT. This call carries no AWS credentials of its own — the token is the identity
3. STS finds the OIDC provider in your account matching the token's issuer, fetches Tembo's public JWKS to verify the signature, then evaluates your trust policy conditions
4. The resulting temporary credentials (1-hour TTL) are injected into the agent's sandbox and never leave it

Because the token is the identity, nothing about this depends on which AWS account Tembo runs in.

## Troubleshooting

<AccordionGroup>
  <Accordion title="&#x22;Access Denied&#x22; when opening the CloudFormation link">
    The one-click URL fetches the template from an S3 bucket. If the bucket policy has not been updated, the AWS console returns an access denied error. Download the template from the connect modal and upload it manually instead — it creates identical resources.
  </Accordion>

  <Accordion title="AssumeRoleWithWebIdentity fails after deploy">
    Work through these in order:

    1. **Provider URL exact match.** It must be `https://internal.tembo.io` — correct scheme, no trailing slash, no typos. STS matches the token's `iss` claim against the registered provider URL exactly.
    2. **Provider is in the same account as the role.** A provider in a different account is not usable.
    3. **`sub` includes the `org:` prefix.** The value is `org:org_2vyf1Ja...`, not `org_2vyf1Ja...`.
    4. **Condition keys have no scheme.** `internal.tembo.io:sub`, not `https://internal.tembo.io:sub`.
    5. **Workspace ID matches.** Compare against the value under **Workspace ID** in **Settings → Workspace**.
  </Accordion>

  <Accordion title="Credentials expire during a long agent run">
    Sessions are 1 hour. If your role's maximum session duration is lower than 3600 seconds, sessions will be shorter than expected — raise it to 3600.
  </Accordion>

  <Accordion title="Agent can't reach AWS APIs">
    The agent sandbox requires outbound access to `https://aws-mcp.us-east-1.api.aws` for the AWS Agent Toolkit MCP service. On self-hosted deployments in a private network, confirm egress to that endpoint is allowed.
  </Accordion>

  <Accordion title="Agent hits permission errors on AWS calls">
    The role's policies decide what agents can do, and `ReadOnlyAccess` is read-only by design. To allow writes, attach additional policies to the role. Note that `ReadOnlyAccess` does grant `s3:Get*`, so agents can read object contents — attach an explicit `Deny` if you need to keep specific buckets out of reach.
  </Accordion>

  <Accordion title="Performance Insights or other encrypted data returns access denied">
    Some AWS features encrypt data with a customer-managed KMS key and require the caller to hold `kms:Decrypt` on that key. `ReadOnlyAccess` does not grant `kms:Decrypt`. Add a scoped statement to the role for the specific key, ideally conditioned on `kms:ViaService` so it is only usable through the owning service.
  </Accordion>
</AccordionGroup>
