Bedrock
The gateway speaks Bedrock natively and does the SigV4 signing itself.
| Property | Value |
|---|---|
| Provider id | bedrock |
| Gateway speaks | Bedrock Runtime (Converse API; InvokeModel for Claude on /v1/messages when enabled) |
| Credential | An AWS workload role, or a static access key and secret, plus a region |
| Signing | The gateway signs SigV4 itself |
| Client base URL | OPENAI_BASE_URL, or ANTHROPIC_BASE_URL for Claude, pointed at :8787 |
Set it up
AWS console → Bedrock → Model access, in the region you will use. Anthropic models need a one-time use-case form. Nothing below works until that is granted.
Attach this policy to the role your gateway workload already runs as. There is no credential to store or rotate.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "BedrockInvoke",
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream",
"bedrock:Converse",
"bedrock:ConverseStream",
"bedrock:ListFoundationModels",
"bedrock:ListInferenceProfiles"
],
"Resource": "*"
},
{
"Sid": "BedrockUseCaseAttestation",
"Effect": "Allow",
"Action": [
"bedrock:GetUseCaseForModelAccess",
"bedrock:PutUseCaseForModelAccess",
"aws-marketplace:ViewSubscriptions",
"aws-marketplace:Subscribe"
],
"Resource": "*"
}
]
}
The two List actions let the gateway resolve a model id its built-in table does not hold, which
includes every undated id such as claude-opus-5.
IAM evaluates at call time, so a running gateway can invoke Bedrock seconds after the attach. No redeploy.
Console → Providers → add bedrock. Set the region you enabled model access in, and
either both key fields or neither.
Blank key fields are the configuration, not a missing step: they select the workload role. An explicit pair takes precedence over the role, and one field without the other is rejected. Session token is optional, for temporary keys you set by hand.
export OPENAI_BASE_URL=http://<gateway>:8787/v1
# Claude on Bedrock through Anthropic SDKs:
export ANTHROPIC_BASE_URL=http://<gateway>:8787
# requests carry: x-anyray-provider: bedrock
To make Bedrock the default for every request that pins no provider, set Console → Routing to
mode single, target bedrock.
curl http://<gateway>:8787/v1/chat/completions \
-H "Authorization: Bearer <your-anyray-key>" \
-H "x-anyray-provider: bedrock" \
-H "Content-Type: application/json" \
-d '{"model":"claude-sonnet-4-5-20250929","messages":[{"role":"user","content":"reply with the word ok"}]}'
Console → Traces shows the call with provider bedrock, the model id, token counts, and a
cost. A success with no row means the client is not going through the gateway.
Model ids
Clients send canonical Anthropic ids and the gateway converts them, so
claude-sonnet-4-5-20250929 becomes us.anthropic.claude-sonnet-4-5-20250929-v1:0. It tries a
built-in table of dated ids, then live discovery through the List actions, and otherwise forwards
the id exactly as written. A native Bedrock id always works.
claude-opus-5, claude-sonnet-5, and claude-fable-5 are in no built-in table. They resolve only
through discovery, so for them the List actions are required, not optional.
From v1.10.269 an undated id for a dated-only family resolves to the newest published snapshot. On earlier releases, send the dated id or set a model alias, which pins an exact id ahead of all resolution.
Resolution order, region-prefix rules, and per-region Claude 5 availability: Bedrock reference.
How developers enrol
Bedrock is an org-account lane. The credential lives on the gateway, and developers reach it with their personal gateway key, so there is no per-developer AWS credential to distribute.
curl -fsSL https://app.anyray.ai/i/tnt_… | sh -s -- --org
Pass --org explicitly even though the org account is the fallback. With no flag, a developer signed
into a personal Claude plan bills that plan instead of your AWS account, silently. --subscription
is the wrong flag here: it forwards a Claude or ChatGPT seat token, which never reaches Bedrock.
To assign the lane per user and team, or when only some developers should route to Bedrock: mixing both lanes.
Network access
The gateway reaches two AWS hostnames on port 443:
| Host | Used for |
|---|---|
bedrock-runtime.<region>.amazonaws.com | Every inference call. Required |
bedrock.<region>.amazonaws.com | Model-id discovery, the List actions. Optional |
An egress allowlist naming only bedrock-runtime leaves inference working while discovery quietly
fails, so include both. The CloudFormation stack needs no networking change. Private subnets and VPC
endpoints: Bedrock reference.
CLAUDE_CODE_USE_BEDROCK bypasses the gatewayWith CLAUDE_CODE_USE_BEDROCK (or CLAUDE_CODE_USE_VERTEX) set, Claude Code signs requests straight
to the cloud provider and ignores ANTHROPIC_BASE_URL. Everything looks healthy and no request
reaches Anyray, so there is no attribution, no spend data, and no savings. Connect disables the
switch at apply time by pinning it empty in the user settings env block, which outranks a shell
export. Restart Claude Code afterwards and the gateway serves Bedrock.
The exception is an IT-managed managed-settings.json, which outranks user scope. There Connect
warns instead, and the admin who deploys that file must remove the switch.
Scoping the policy Resource
Name both the foundation-model and inference-profile ARNs, because Claude 4 and newer are profile-only in most regions:
"Resource": [
"arn:aws:bedrock:*::foundation-model/anthropic.*",
"arn:aws:bedrock:*:<account-id>:inference-profile/*anthropic*"
]
Where the credential comes from
With no explicit key pair configured, the gateway uses the standard AWS credential chain: an ECS or Fargate task role (not the task execution role), an EC2 instance profile, an EKS service-account role (IRSA), or standard AWS environment and shared-config credentials. Role credentials are short-lived and Anyray never stores them.
On the CloudFormation deployment, attach the policy to the stack's TaskRole as a managed
policy, never inline. The template reconciles inline policies on every stack update and can
remove one you added by hand (role mechanics).
A gateway with no AWS workload identity, or a Bedrock account different from the gateway's, uses a static key pair instead: static keys and cross-account access.
Troubleshooting
| What you see | Cause and fix |
|---|---|
AWS credentials were not found (500) | No key pair configured and no role reachable from the workload. Attach the policy to the role the gateway runs as (on ECS, the task role, not the execution role), or fill in the access-key pair. |
AWS access key ID and secret access key must be configured together (400) | Only one of the two fields is set. Set both, or clear both to fall back to the role. |
AccessDeniedException | Model access is not granted for that model in that region, or the policy omits the inference-profile ARN. |
ValidationException on the model id | An id that needed discovery without the List actions granted, an undated id for a dated-only family on a gateway older than v1.10.269, or a region with no profile for that model. Grant the List actions, or pin the exact Bedrock id with a model alias. |
ResourceNotFoundException asking for the use-case form | Bedrock evaluates the attestation per principal. Submit the form as the IAM user or role that is calling (how). |
| Requests succeed, nothing in the console | The client is signing to AWS directly. Unset CLAUDE_CODE_USE_BEDROCK and restart it. |
| Bedrock worked, then stopped after a stack update | An inline policy on a CloudFormation-managed role was reconciled away. Re-add it as a managed-policy attachment. |