?

When to use Bedrock

The bedrock provider is the right choice when:

  • You are on AWS and want Claude billed through Bedrock rather than the Anthropic API.
  • You need SigV4 auth via the standard AWS credential chain (env vars, ~/.aws/credentials, IMDS, IRSA on EKS).
  • You want to keep model traffic inside a single AWS region for data-residency reasons.
  • You need to route model traffic through a VPC endpoint so it never touches the public internet.
  • You want cross-account access via sts:AssumeRole.

Configuration

provider: bedrock

bedrock:
  region: us-east-1
  model: anthropic.claude-sonnet-4-6-20260101-v1:0
  profile: default
  max_tokens: 4096
Field Default Effect
region required AWS region. Bedrock model availability is regional; check the AWS console.
model required Bedrock model ID. Anthropic Claude IDs follow the shape anthropic.claude-<name>-<date>-<version>:<revision>.
profile empty Credentials profile from ~/.aws/credentials. Empty falls through the standard credential chain.
max_tokens SDK default Caps output tokens per completion.

Credential chain

The provider constructs a Bedrock client via awsconfig.LoadDefaultConfig, which walks the standard chain in order:

  1. Environment (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN).
  2. Shared credentials file (~/.aws/credentials), narrowed by profile if set.
  3. Shared config file (~/.aws/config).
  4. IAM Roles for Tasks (ECS) / IAM Roles Anywhere.
  5. EC2 IMDS (v2).
  6. IRSA — the IAM role attached to a Kubernetes service account (EKS).

None of these are configured through rousseau; the SDK handles resolution.

Required IAM permissions

The minimum policy the caller must be able to assume:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "bedrock:InvokeModel",
        "bedrock:InvokeModelWithResponseStream"
      ],
      "Resource": "arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-sonnet-4-6-*"
    }
  ]
}

Scope the Resource to the specific model family you plan to invoke. Broader wildcards work but are usually overkill.

Wire format

The provider sends the standard Anthropic messages JSON body (anthropic_version, messages, system, tools, max_tokens) to bedrock:InvokeModel, and receives the same shape back. This mirrors the Anthropic direct API — tool use, stop reasons, and usage counters are the same.

Streaming uses bedrock:InvokeModelWithResponseStream with the SDK's event-stream decoder.

Streaming

The provider implements agent.StreamingProvider. Streaming is used automatically in rousseau chat.

Tool use

Tool definitions from the Registry are converted to Bedrock's tool JSON in internal/llm/bedrock/client.go. Approval policies apply.

Auth pattern by deployment

For local dev, use a named profile with SSO or long-lived keys:

aws configure sso --profile rousseau-dev
aws sso login --profile rousseau-dev
bedrock:
  region: us-east-1
  profile: rousseau-dev
  model: anthropic.claude-sonnet-4-6-20260101-v1:0

profile: is honoured because rousseau passes awsconfig.WithSharedConfigProfile(cfg.Profile) when non-empty (see internal/llm/bedrock/client.go line 63). Omit profile to fall through the default chain.

Least-privilege IAM policy

The minimum policy the caller must be able to assume:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "bedrock:InvokeModel",
        "bedrock:InvokeModelWithResponseStream"
      ],
      "Resource": "arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-sonnet-4-6-*"
    }
  ]
}

Scope the Resource to the specific model family. Broader wildcards work but grant more than needed. For provisioned throughput, add the ARN of your provisioned model as a second resource.

Trust policy for cross-account (Account B, the model-hosting side):

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": { "AWS": "arn:aws:iam::111111111111:role/rousseau-caller" },
    "Action": "sts:AssumeRole",
    "Condition": { "StringEquals": { "sts:ExternalId": "rousseau-prod" } }
  }]
}

ExternalId is required by AWS security guidance for third-party cross-account access.

VPC endpoints

For deployments that must not reach the public internet, create an interface VPC endpoint for Bedrock in your VPC:

aws ec2 create-vpc-endpoint \
  --vpc-id vpc-0123456789abcdef0 \
  --vpc-endpoint-type Interface \
  --service-name com.amazonaws.us-east-1.bedrock-runtime \
  --subnet-ids subnet-aaa subnet-bbb \
  --security-group-ids sg-xxx

The AWS SDK will automatically resolve through the endpoint if the security group and route table allow it. No rousseau-side config change is needed — this is transparent to the provider.

Model availability by region

Availability shifts as AWS rolls out new snapshots. Snapshot as of mid-2026:

Model us-east-1 us-west-2 eu-west-2 eu-central-1 ap-southeast-1 ap-northeast-1
Claude Sonnet 4.6 yes yes yes yes yes yes
Claude Opus 4.6 yes yes limited limited no no
Claude Haiku 4.6 yes yes yes yes yes yes

Gotchas

  • Model IDs change per region. anthropic.claude-sonnet-4-6-20260101-v1:0 in us-east-1 may be a different snapshot in eu-west-2. Check the Bedrock console.
  • Access must be granted per model. Even with IAM allowing InvokeModel, Bedrock requires you to click through Model access > Request access in the console before the first call succeeds.
  • Throttling. Bedrock enforces per-account and per-model concurrency limits (tokens-per-minute and requests-per-minute). Set max_tokens conservatively.
  • Provisioned throughput. If you have provisioned throughput, pass the provisioned model ID (arn:aws:bedrock:us-east-1:<account>:provisioned-model/…) as model.
  • Streaming decoder failures. The event-stream format changed subtly between SDK versions. Pin aws-sdk-go-v2/service/bedrockruntime to a known-good version and re-test on every bump.

Troubleshooting

AccessDeniedException: You don't have access to the model

Two separate checks: (1) the caller's IAM policy allows bedrock:InvokeModel on the model ARN, and (2) the account has explicitly requested access to the model in the Bedrock console. Item 2 catches most first-time users.

ValidationException: The model ID isn't valid

The model ID string does not match a model available in the configured region. Copy the exact ID from the Bedrock console (Providers > Anthropic > Model catalog) rather than typing it — the date and version suffixes must match exactly.

ThrottlingException

You hit a token or request-per-minute quota. Options: (1) request a service quota increase, (2) queue calls in the caller with exponential backoff, (3) switch to provisioned throughput.

bedrock: parse response: json: — malformed JSON

The response body is not the expected Anthropic-on-Bedrock shape. Usually indicates a non-Anthropic model was passed as model; buildBedrockBody in internal/llm/bedrock/client.go only produces the Anthropic wire format.

VPC endpoint unreachable — dial tcp: no route to host

The pod/instance cannot reach the endpoint's ENIs. Check the security group on the endpoint (must allow port 443 from the caller's SG), the endpoint's subnet route table, and DNS resolution (the endpoint requires private DNS enabled on the VPC).

Related pages

Further reading

Type to search 150+ pages. Ranking: BM25 with title/description boost.