Deploying Claude on Amazon Bedrock: IAM, Provisioning, and Cross-Region Inference
Amazon Bedrock puts Claude behind your existing AWS account: IAM controls who can call it, model access is requested per model per region, and some models need a cross-region inference profile to handle capacity and latency.
Summary
Bedrock is not a drop-in replacement for the direct Anthropic API - it is a different authentication and provisioning model layered on the same underlying Claude models.
Before any application code can call Claude on Bedrock, three things must exist: an IAM principal with permission to invoke Bedrock, an explicit grant of access to the specific model you want, and, for some models, a cross-region inference profile rather than a plain single-region model ID.
Skipping any one of those three steps produces a permission or not-found error that looks like a code bug but is actually a provisioning gap.
This page walks through IAM setup, requesting model access, and choosing between a plain model ID and a cross-region inference profile, then shows the request shape your application code actually calls.
Recipe
Quick-reference recipe card - copy-paste ready.
from anthropic import AnthropicBedrock
client = AnthropicBedrock(aws_region="us-east-1")
response = client.messages.create(
model="anthropic.claude-sonnet-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Summarize this ticket in one sentence."}],
)
print(response.content[0].text)When to reach for this:
- Your organization already runs production workloads on AWS and wants Claude usage to flow through existing IAM and billing.
- You need Claude's traffic to stay inside an AWS-managed network boundary for compliance reasons.
- You want Claude spend to count against an existing AWS Enterprise Discount Program or committed-use agreement.
- You are integrating Claude into an application that already assumes an IAM role for every other AWS service call.
Working Example
import os
from anthropic import AnthropicBedrock
import anthropic
# aws_region is required - there is no default region fallback for Bedrock.
client = AnthropicBedrock(aws_region=os.environ.get("AWS_REGION", "us-east-1"))
def summarize_ticket(ticket_text: str) -> str:
"""Call Claude on Bedrock and return a one-sentence summary.
Assumes the caller's IAM role has bedrock:InvokeModel permission and
that model access for claude-sonnet-5 has been granted in this region.
"""
try:
response = client.messages.create(
model="anthropic.claude-sonnet-5",
max_tokens=200,
messages=[
{
"role": "user",
"content": f"Summarize this support ticket in one sentence:\n\n{ticket_text}",
}
],
)
return response.content[0].text
except anthropic.PermissionDeniedError:
raise RuntimeError(
"IAM role lacks bedrock:InvokeModel, or model access was never "
"granted for this model in this region."
)
except anthropic.NotFoundError:
raise RuntimeError(
"Model ID not found - check the anthropic. prefix and confirm "
"the model is available in this AWS region."
)
if __name__ == "__main__":
ticket = "Customer reports login page returns a 500 error after the latest deploy."
print(summarize_ticket(ticket))What this demonstrates:
AnthropicBedrockresolves AWS credentials through the standard chain (environment variables, shared credentials file, or an assumed IAM role) - there is no separate Anthropic API key involved.- The
anthropic.prefix on the model ID is mandatory on Bedrock; the bareclaude-sonnet-5ID from the direct API returns a 404 here. - Catching
PermissionDeniedErrorandNotFoundErrorseparately turns the two most common first-deploy failures into an actionable message instead of a stack trace.
Deep Dive
How It Works
- Every Bedrock request is authenticated as an AWS IAM principal (a role or user), not by an Anthropic-issued API key - the SDK signs requests using the AWS credential chain, the same way any other boto3-backed call would.
- The IAM principal needs an attached policy granting
bedrock:InvokeModel(andbedrock:InvokeModelWithResponseStreamfor streaming) scoped to the specific model ARNs you intend to call. - Having the IAM permission is necessary but not sufficient - each model also requires an explicit model access grant, requested per model per AWS region in the Bedrock console before the first successful invocation.
- Model access requests are typically approved automatically for most Claude models, but the grant is still a separate step from IAM policy attachment, and both must be in place before traffic flows.
- Some models additionally require a cross-region inference profile instead of a plain model ID - a profile ID that lets Bedrock route a single logical request across multiple regions within a geography for extra capacity and lower queueing latency during demand spikes.
IAM Policy Shape
A minimal IAM policy for invoking Claude on Bedrock scopes the action to the specific model resources rather than granting blanket Bedrock access:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream"
],
"Resource": [
"arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-sonnet-5",
"arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-opus-4-8"
]
}
]
}- Scoping
Resourceto exact model ARNs, rather than"*", means adding a new model later requires a deliberate policy update rather than being silently already-allowed. - If you use a cross-region inference profile, the resource ARN pattern changes to reference the inference profile rather than the plain foundation-model ARN - check the Bedrock console for the exact ARN once the profile is provisioned.
Model IDs vs. Cross-Region Inference Profiles
| Form | Example | When to use |
|---|---|---|
| Plain model ID | anthropic.claude-sonnet-5 | Default choice; works for most models in most regions. |
| Cross-region inference profile | us.anthropic.claude-sonnet-5 | Required for some models; also useful when a single region is hitting capacity limits during peak demand. |
- The profile ID's geography prefix (
us., for example) indicates which set of regions the profile is allowed to route across - it does not mean the request always leaves your primary region, only that it may during high demand. - Using a profile ID where a plain model ID would work is harmless; using a plain model ID where a profile is required returns a
ValidationExceptionat request time, not a silent fallback.
Python Notes
from anthropic import AnthropicBedrock
# Prefer environment-driven region configuration over a hardcoded string,
# so the same code deploys cleanly to a second region later.
client = AnthropicBedrock(aws_region="us-east-1")
# Streaming works identically to the direct API - only the client class differs.
with client.messages.stream(
model="anthropic.claude-sonnet-5",
max_tokens=512,
messages=[{"role": "user", "content": "Draft a short release note."}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)AnthropicBedrockexposes the samemessages.createandmessages.streammethods as the direct-API client - code written against the direct API needs only a client-construction change to run on Bedrock.- The legacy
AnthropicBedrockclient uses thebedrock-runtimeInvokeModel path; check current SDK documentation for the newer Mantle-based client if you need the latest Messages API surface on Bedrock.
Parameters & Return Values
| Parameter | Type | Description |
|---|---|---|
aws_region | str | Required constructor argument. No default - Bedrock has no implicit region fallback. |
model | str | Bedrock model ID, either anthropic.<model> or a cross-region inference profile like us.anthropic.<model>. |
max_tokens | int | Same meaning as the direct API - the output token ceiling for this request. |
Gotchas
- Forgetting the
anthropic.prefix on the model ID. A bareclaude-sonnet-5string that works on the direct API returns a 404 on Bedrock. Fix: always prefix Bedrock model IDs withanthropic.. - IAM policy attached but model access never requested. The role has
bedrock:InvokeModel, but the account never requested access to that specific model in the Bedrock console. Fix: check the Bedrock console's Model Access page for that model and region before assuming it's an IAM problem. - Region mismatch between IAM policy and client construction. The IAM policy scopes the model ARN to
us-east-1, butAnthropicBedrock(aws_region="us-west-2")is used at runtime. Fix: keep the IAM policy's resource ARNs and the client'saws_regionin sync, or scope the policy to multiple regions deliberately. - Using a plain model ID where a cross-region inference profile is required. Some models reject a plain
anthropic.model ID with a validation error. Fix: check the Bedrock console for whether the model requires an inference profile ID before wiring up the integration. - Assuming model access approval is instant. Some models or regions can have a review delay before access is granted. Fix: request model access well before a launch date, not on the day of deployment.
- Hardcoding a single region with no fallback plan. A regional Bedrock outage or capacity limit then has no mitigation. Fix: consider a cross-region inference profile, or a fallback path to another platform, for latency- or availability-sensitive workloads.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| Direct Anthropic API | You want the fastest path to new models and features, with no AWS dependency. | Your organization requires traffic to stay inside AWS-managed IAM and network boundaries. |
| Google Cloud Vertex AI | Your organization is standardized on GCP instead of AWS. | You have no GCP footprint and would be onboarding a new cloud vendor for this alone. |
| A self-hosted gateway in front of Bedrock | You want to add caching, centralized rate limiting, or fallback to another provider without touching application code. | You have a single simple workload where the added infrastructure isn't worth the operational cost. |
FAQs
Do I need an Anthropic API key to use Claude on Bedrock?
No. Authentication is entirely IAM-based - the SDK signs requests with your AWS credentials, and there is no separate Anthropic-issued API key involved.
Why does my request return a 404 even though the model name looks right?
Bedrock model IDs require the anthropic. prefix. A bare model ID copied from direct-API code, like claude-sonnet-5, is not a valid Bedrock model ID on its own.
What's the difference between an IAM policy and model access?
- The IAM policy grants the permission to call
bedrock:InvokeModelat all. - Model access is a separate, per-model, per-region grant requested in the Bedrock console.
- Both must be in place - having one without the other still fails.
When do I need a cross-region inference profile instead of a plain model ID?
Some models require one outright, and it's also useful for models under heavy regional demand, since the profile can route a request across multiple regions within a geography for extra capacity.
How do I know if my account has model access for a given model?
Check the Model Access page in the Bedrock console for your account and target region. A missing grant there causes a permission error at request time even with a correctly scoped IAM policy.
Can the same application code run against both the direct API and Bedrock?
Mostly, yes. Both clients expose the same messages.create and messages.stream methods - the differences are the client construction (API key vs. AWS credentials plus region) and the model ID format.
What happens if I use a plain model ID where a profile is required?
The request fails with a validation error at call time rather than silently falling back to a plain model - check the Bedrock console for whether your target model requires a profile ID before deploying.
Does Bedrock support streaming the same way the direct API does?
Yes. client.messages.stream(...) on AnthropicBedrock behaves the same as on the direct-API client, including the text_stream convenience iterator.
Is a region mismatch between IAM policy and client construction a common failure?
Yes. If the IAM policy scopes model ARNs to one region but the client is constructed with a different aws_region, requests fail even though the policy looks correct on a quick read.
Should I scope IAM policies to specific model ARNs or use a wildcard?
Scope to specific model ARNs. A wildcard grants access to any model your account might later gain access to, which is broader than most teams intend and harder to audit.
Does requesting model access cost anything by itself?
No. Model access is a permission grant, not a purchase - billing only occurs when you actually invoke the model.
Why might a team choose Bedrock over the direct API even though it's more setup?
To keep Claude traffic inside existing AWS IAM and network governance, and to have the spend count against an existing AWS billing or discount agreement rather than a new vendor relationship.
Related
- Choosing Between Direct API, Bedrock, and Vertex AI for Claude - decide whether Bedrock is the right platform before provisioning it.
- Enterprise Deployment Basics - the minimal first call across all three platforms, including Bedrock.
- Running Claude on Google Cloud Vertex AI: Quotas and Service Accounts - the equivalent provisioning steps on GCP.
- Data Residency and Region-Pinning Checklist for Regulated Workloads - how region choice on Bedrock interacts with compliance requirements.
- Comparing Bedrock, Vertex AI, and Direct Anthropic API Access - trade-offs across all three platforms in one table.
Stack versions: Written against the Claude model lineup current as of ~June 2026 - Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5 (the default), and Claude Haiku 4.5 - and the official
anthropicPython SDK (latest 0.x release). Model names, pricing, and SDK versions move quickly - verify current specifics at platform.claude.com/docs before relying on them.