Deploy Claude apps gateway on AWS changedclaude-apps-gateway-on-aws
Nearest release: v2.1.286, published 3 hours before upstream edited the page. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.
Upstream edited this page at 30 Sep 2026 20:43 UTC, give or take a minute or two: the time comes from Anthropic’s own sitemap rather than from a commit. This site recorded the change at 30 Sep 2026 21:07 UTC.
Upstream edited
Recorded here
Lines+64added
Lines−1removed
From line
520
where the diff opens
First seen
14 Aug 2026
this site's first read of the page
Recorded edits10to this page, all time
## Cost attribution ### Per developer with `assume_role` ### Per team with application inference profiles
The whole hunk
from line 520, old and new numbered
/
from line 520
520520
521521### Spend
522522
523Telemetry shows usage after the fact; [spend limits](/docs/en/claude-apps-gateway-spend-limits) are the gateway's live per-developer view and enforcement on top of the shared upstream credential.
523Telemetry shows usage after the fact; [spend limits](/docs/en/claude-apps-gateway-spend-limits) are the gateway's live per-developer view and enforcement.
524
525## Cost attribution
526
527The gateway signs every Bedrock request with its own principal, the ECS task role or EKS IRSA role, so by default AWS sees all of that spend under one IAM principal. There are two ways to split it in AWS's own billing data, and they combine.
528
529### Per developer with `assume_role`
530
531Create a second IAM role that holds the Bedrock permissions and trusts the gateway's principal, grant that principal `sts:AssumeRole` on it, and set [`assume_role`](/docs/en/claude-apps-gateway-config#per-developer-aws-cost-attribution) with `session_name: email` on the Bedrock upstream. The gateway then assumes that role once per developer per hour with the session name set to their email and signs their requests with the result. Requires a gateway running Claude Code v2.1.281 or later. The role can also be in another AWS account: see [Bedrock in another AWS account](/docs/en/claude-apps-gateway-config#bedrock-in-another-aws-account). In Terraform, next to the task role in the [Terraform bundle](#terraform-reference):
532
533```hcl theme={null}
534resource "aws_iam_role" "bedrock_user" {
535 name = "claude-gateway-bedrock-user"
536 assume_role_policy = jsonencode({
537 Version = "2012-10-17"
538 Statement = [{ Effect = "Allow", Action = "sts:AssumeRole", Principal = { AWS = aws_iam_role.task.arn } }]
539 })
540}
541resource "aws_iam_role_policy" "bedrock_user_invoke" { # same Bedrock policy as the task role's
542 role = aws_iam_role.bedrock_user.id
543 policy = aws_iam_role_policy.bedrock_invoke.policy
544}
545resource "aws_iam_role_policy" "task_assume_bedrock_user" {
546 role = aws_iam_role.task.id
547 policy = jsonencode({
548 Version = "2012-10-17"
549 Statement = [{ Effect = "Allow", Action = "sts:AssumeRole", Resource = aws_iam_role.bedrock_user.arn }]
550 })
551}
552```
553
554With `assume_role` set the gateway signs every Bedrock call, the free `CountTokens` call for spend metering included, with the assumed role's credentials, so the gateway's principal needs a Bedrock policy of its own only for an upstream without `assume_role`.
555
556Because the gateway calls STS at request time, the private subnets need a path to `sts.<region>.amazonaws.com`. The NAT gateway from the prerequisites provides one, and so does an STS interface VPC endpoint that answers for that hostname. Each active developer costs one STS call per hour per gateway replica.
557
558Each developer's requests reach AWS as the principal `arn:aws:sts::<account>:assumed-role/<role>/<email>`. To see spend per principal, use a billing export that includes IAM principal data; AWS's [IAM principal cost allocation](https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/iam-principal-cost-allocation.html) page covers how to enable it and which billing tools show it.
559
560### Per team with application inference profiles
561
562This route uses only the [`models`](/docs/en/claude-apps-gateway-config#models) and [`managed`](/docs/en/claude-apps-gateway-config#managed) sections. Create one Bedrock [application inference profile](https://docs.aws.amazon.com/bedrock/latest/userguide/inference-profiles-create.html) per team and model, tag each profile with the team, and activate that tag as a cost allocation tag. Then give each team its own model id in `gateway.yaml` and pin each IdP group to its team's ids:
563
564```yaml theme={null}
565models:
566 - id: platform-claude-opus-4-8
567 upstream_model:
568 bedrock: arn:aws:bedrock:us-east-1:123456789012:application-inference-profile/abc123
569 - id: data-claude-opus-4-8
570 upstream_model:
571 bedrock: arn:aws:bedrock:us-east-1:123456789012:application-inference-profile/def456
572managed:
573 policies:
574 - match: {groups: [team-platform]}
575 cli: {availableModels: [platform-claude-opus-4-8], enforceAvailableModels: true}
576 - match: {groups: [team-data]}
577 cli: {availableModels: [data-claude-opus-4-8], enforceAvailableModels: true}
578 - match: {}
579 cli: {availableModels: [claude-opus-4-8, claude-sonnet-4-6], enforceAvailableModels: true}
580```
581
582Tell developers in a pinned team to start Claude Code with `--model platform-claude-opus-4-8`, using their team's id, because a session started without it runs the default model, which the gateway refuses for them.
583
584The gateway enforces `availableModels` on every request, not only in the model picker, and AWS billing groups the spend by the tag you activated. Without the `match: {}` catch-all, a developer who matches no policy gets every model in the catalog and can bill either team's profile.
585
586The costs: the config grows with teams times models, and the role that signs this upstream's Bedrock requests must also be allowed to invoke the `application-inference-profile/*` ARNs. That role is the gateway's principal, or with `assume_role` the role it assumes. See [`pricing`](/docs/en/claude-apps-gateway-config#pricing) for how the gateway's own spend meter prices these ids.
524587
525588## Next steps
526589
No line in this hunk matches that.