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

# Amazon Bedrock with an IAM role

> Let xpander call Amazon Bedrock in your own AWS account through an IAM role it assumes, with no long-lived keys stored.

Connect Amazon Bedrock with an IAM role and xpander calls Bedrock in your AWS account with short-lived credentials it gets by assuming that role. No access key is stored, you can revoke access at any time by editing the role, and every call shows up in your CloudTrail under a session named `xpander-<your organization ID>`. Calls on your own Bedrock are never charged credits.

You need an organization admin in xpander and permission to create IAM roles in the AWS account that runs Bedrock.

<Tabs>
  <Tab title="xpander cloud">
    <Steps>
      <Step title="Copy the trust policy from xpander">
        In xpander, open **Settings > LLM**, choose **Add key**, pick **Amazon Bedrock** and select **IAM role**. The dialog shows:

        * the xpander AWS role your role must trust,
        * your **external ID**, which is your organization ID,
        * a trust policy and a permissions policy, ready to copy.

        xpander always sends your external ID when it assumes your role, and you cannot change it. Another organization cannot use your role even if it knows the role's ARN, because xpander sends that organization's own ID instead.
      </Step>

      <Step title="Create the role in AWS">
        Create a role whose trust policy is the one you copied. It has this shape:

        ```json theme={"dark"}
        {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": { "AWS": "<xpander role ARN shown in the dialog>" },
              "Action": "sts:AssumeRole",
              "Condition": { "StringEquals": { "sts:ExternalId": "<your organization ID>" } }
            }
          ]
        }
        ```

        <CodeGroup>
          ```text AWS console theme={"dark"}
          1. IAM > Roles > Create role.
          2. Trusted entity type: Custom trust policy. Paste the trust policy from xpander.
          3. Skip permissions for now and name the role, for example xpander-bedrock.
          4. Create the role.
          ```

          ```bash AWS CLI theme={"dark"}
          # trust.json is the trust policy copied from xpander
          aws iam create-role \
            --role-name xpander-bedrock \
            --assume-role-policy-document file://trust.json
          ```

          ```hcl Terraform theme={"dark"}
          resource "aws_iam_role" "xpander_bedrock" {
            name = "xpander-bedrock"

            assume_role_policy = jsonencode({
              Version = "2012-10-17"
              Statement = [{
                Effect    = "Allow"
                Principal = { AWS = var.xpander_principal_arn }      # shown in the dialog
                Action    = "sts:AssumeRole"
                Condition = { StringEquals = { "sts:ExternalId" = var.xpander_external_id } }  # your organization ID
              }]
            })
          }
          ```
        </CodeGroup>
      </Step>

      <Step title="Attach the permissions policy">
        Give the role permission to call Bedrock models:

        ```json theme={"dark"}
        {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Sid": "InvokeBedrockModels",
              "Effect": "Allow",
              "Action": [
                "bedrock:InvokeModel",
                "bedrock:InvokeModelWithResponseStream",
                "bedrock:CountTokens"
              ],
              "Resource": [
                "arn:aws:bedrock:*::foundation-model/*",
                "arn:aws:bedrock:*:*:inference-profile/*",
                "arn:aws:bedrock:*:*:application-inference-profile/*"
              ]
            }
          ]
        }
        ```

        <CodeGroup>
          ```bash AWS CLI theme={"dark"}
          # permissions.json is the permissions policy copied from xpander
          aws iam put-role-policy \
            --role-name xpander-bedrock \
            --policy-name invoke-bedrock \
            --policy-document file://permissions.json
          ```

          ```hcl Terraform theme={"dark"}
          resource "aws_iam_role_policy" "xpander_bedrock_invoke" {
            name = "invoke-bedrock"
            role = aws_iam_role.xpander_bedrock.id

            policy = jsonencode({
              Version = "2012-10-17"
              Statement = [{
                Sid    = "InvokeBedrockModels"
                Effect = "Allow"
                Action = ["bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream", "bedrock:CountTokens"]
                Resource = [
                  "arn:aws:bedrock:*::foundation-model/*",
                  "arn:aws:bedrock:*:*:inference-profile/*",
                  "arn:aws:bedrock:*:*:application-inference-profile/*",
                ]
              }]
            })
          }
          ```
        </CodeGroup>

        You can narrow `Resource` to the models and regions you use. Keep the inference-profile entries if you use cross-region profiles such as `us.anthropic.claude-sonnet-4-5-20250929-v1:0`.
      </Step>

      <Step title="Connect and test">
        Back in the dialog, paste the role ARN (for example `arn:aws:iam::123456789012:role/xpander-bedrock`), pick the region your Bedrock models run in, and choose **Test connection**. A passing test means xpander assumed the role and Bedrock accepted the call. Save the key.
      </Step>
    </Steps>
  </Tab>

  <Tab title="Hybrid and air-gapped">
    On your own install, the role your xpander install runs as (its IRSA role or EKS Pod Identity role) assumes the Bedrock role. The account is yours, so no external ID is required. You can add one in the trust policy if your own rules call for it.

    <Steps>
      <Step title="Find your install's role">
        Settings > LLM > **Add key** > **Amazon Bedrock** > **IAM role** shows the role your install runs as when it can read it. Otherwise use the IAM role attached to the xpander controller's service account in your cluster.
      </Step>

      <Step title="Create the Bedrock role">
        Create a role that trusts your install's role:

        ```json theme={"dark"}
        {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": { "AWS": "arn:aws:iam::<your-account-id>:role/<role-your-xpander-install-runs-as>" },
              "Action": "sts:AssumeRole"
            }
          ]
        }
        ```

        Allow `sts:AssumeRole` on this role in your install role's own permissions as well.
      </Step>

      <Step title="Attach the permissions policy">
        Use the same permissions policy as on xpander cloud: `bedrock:InvokeModel`, `bedrock:InvokeModelWithResponseStream` and `bedrock:CountTokens` on `foundation-model/*`, `inference-profile/*` and `application-inference-profile/*`.
      </Step>

      <Step title="Connect and test">
        Paste the role ARN, pick the region and choose **Test connection** on an air-gapped install. On a hybrid install the role is used from your own cluster, so confirm it by running an agent on Amazon Bedrock.
      </Step>
    </Steps>

    You can also skip the extra role: give your install's own role the Bedrock permissions above, and leave the organization's Bedrock key empty. See [AI vendors](/run/integrations/ai-vendors) for the install-level Bedrock settings.
  </Tab>
</Tabs>

## Troubleshooting

| Message | What to check |
| - | - |
| xpander could not assume this role | The trust policy's `Principal` must be the exact role shown in the dialog, and on xpander cloud the `sts:ExternalId` condition must be your organization ID. Trust policy changes can take a few seconds to apply; test again. |
| The role was assumed, but it cannot call Bedrock models in `<region>` | Attach the permissions policy to the role. If you narrowed `Resource`, include the model or inference profile you use, in that region. |
| Bedrock in `<region>` answered an error | Check that the region is one where your models are available. Cross-region inference profiles (`us.`, `eu.`, `apac.`, `global.`) route to several regions, so the policy must allow every region they can reach. |
| This role is in an xpander AWS account | Create the role in your own AWS account and enter its ARN. |
| Enter the role's full ARN | Paste the ARN itself, for example `arn:aws:iam::123456789012:role/xpander-bedrock`, not the role name. |

Fable- and Mythos-class Anthropic models also need your account's data-retention opt-in per region; see [AI vendors](/run/integrations/ai-vendors).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.