← Agent Frameworks 🕐 17 min read
Agent Frameworks

Bedrock Multi-Account FinOps — Consolidated Billing and Cross-Account Governance (2026)

Enterprise Bedrock deployments almost universally span multiple AWS accounts: separate accounts for dev, staging, and prod; team-scoped accounts under Control Tower; shared-services or platform accoun

Enterprise Bedrock deployments almost universally span multiple AWS accounts: separate accounts for dev, staging, and prod; team-scoped accounts under Control Tower; shared-services or platform accounts hosting centralized gateways; and isolated accounts for regulated workloads. This creates three interlocking FinOps problems — seeing the spend, attributing it correctly, and governing it before costs escape into unmonitored accounts. This note covers all three layers in depth, with executable SQL, policy JSON, and org design patterns.


When consolidated billing is enabled in AWS Organizations, all member account charges roll up to the management (payer) account. Bedrock on-demand inference — including calls through the bedrock-runtime and bedrock-mantle endpoints — follows the same aggregation pattern as any other AWS service: usage originates in the member account, pricing is applied per token type and service tier, and the resulting charge appears on the management account’s consolidated bill.

Key aggregation behaviors:

  • Single invoice: The management account receives one AWS invoice covering all member account Bedrock usage. Line-item detail is available in CUR but the bill itself is consolidated.
  • Volume tiers: For any AWS service with volume-based pricing tiers, consolidated billing aggregates all member account usage toward tier breakpoints. Bedrock on-demand is priced per token (not volume-tiered), so this has limited direct impact on per-token rates — but it does matter for EDP commitment retirement (Section 9).
  • Managed entitlements billing: When using managed entitlements for third-party Marketplace models (Section 10), the account holding the original subscription — typically the management account — is billed for all usage across granted member accounts. This means Marketplace software fees also flow to the payer.
  • No org-level quota: Quotas are scoped per account and per region (Section 8). Consolidated billing does not provide a shared quota pool across accounts.
  • Account tags in cost allocation (Dec 2025): AWS launched support for AWS Organizations account tags to appear directly in Cost Management products. This means a tag like Environment: production applied at the account level in Organizations now flows into CUR and Cost Explorer without requiring every resource inside the account to carry that tag.

Org design implication: The management account should be used exclusively as the payer. Do not run Bedrock workloads from the management account. Keep it clean so that any Bedrock charges appearing on bill_payer_account_id with line_item_usage_account_id equal to the management account ID are immediately flagged as a policy violation.


2. CUR 2.0 Multi-Account Setup: Which Account Creates the Export

CUR 2.0 (AWS Data Exports) is the AWS-recommended method for detailed Bedrock cost analysis. The account that creates the export determines the scope of data returned.

Export created by Data scope
Management (payer) account All member accounts + management account for the billing period
Member account Only that member account’s usage

The correct setup for org-wide Bedrock FinOps: Create one CUR 2.0 export from the management account, delivered to an S3 bucket in a designated FinOps or shared-services account. All cross-account Bedrock analysis runs against this single export. Member accounts can optionally create their own exports for self-service cost visibility, but the management account export is the authoritative source for chargebacks and governance reporting.

CUR 2.0 improvements relevant to Bedrock:

  • Fixed schema: 125 columns with consistent naming across months. No column dropping when a service adds or removes features.
  • bill_payer_account_name and line_item_usage_account_name: New columns added in CUR 2.0 that complement the ID columns, making human-readable reports easier without a lookup join.
  • INCLUDE_IAM_PRINCIPAL_DATA: Table configuration (enabled April 8, 2026) that adds the line_item_iam_principal column — the IAM ARN of the caller — and populates iamPrincipal/-prefixed tag columns. This is critical for sub-account attribution when a single Bedrock account serves multiple teams.
  • Nested tags: Resource tags, IAM principal tags, and session tags all appear in a nested tags column with structured key-value pairs, flattened on query.

CUR 2.0 table configuration for Bedrock FinOps (recommended):

{
  "TIME_GRANULARITY": "HOURLY",
  "INCLUDE_RESOURCES": "TRUE",
  "INCLUDE_IAM_PRINCIPAL_DATA": "TRUE",
  "INCLUDE_SPLIT_COST_ALLOCATION_DATA": "FALSE"
}

Hourly granularity is important for detecting quota-driven throttling patterns (requests concentrate within a minute, costs spike then flatten). Resource-level detail exposes inference profile ARNs in line_item_resource_id, enabling attribution by application inference profile.


3. line_item_usage_account_id vs bill_payer_account_id: The Attribution Columns

These two columns are the primary mechanism for cross-account attribution in any multi-account Bedrock query.

Column Contents Use case
bill_payer_account_id The management (payer) account ID Identify which org the charge belongs to; always the same value in a single-org setup
line_item_usage_account_id The member account where the Bedrock API call was made The key dimension for attributing costs to specific teams, environments, or products
bill_payer_account_name Human-readable name of the payer account Display column for dashboards
line_item_usage_account_name Human-readable name of the member account Display column; set this to a meaningful name in Organizations (e.g., prod-ml-team-a)

Critical distinction for gateway architectures: When a centralized Bedrock gateway account makes all API calls on behalf of other teams, line_item_usage_account_id will show the gateway account for all traffic. The caller identity that maps to individual teams lives in line_item_iam_principal and the iamPrincipal/ tag columns. In this topology, you need both columns to answer “which team in which account generated this cost.”

Additional key columns for Bedrock analysis:

line_item_usage_type          -- Model + token type + tier + routing
                              -- e.g., USE1-Claude4.6Sonnet-input-tokens
                              -- e.g., USE1-Claude4.6Sonnet-output-tokens-cross-region-global
line_item_operation           -- InvokeModel | InvokeModelWithResponseStream | Converse
line_item_unblended_cost      -- Actual cost before discounts
line_item_blended_cost        -- After EDP/RI blending (use for committed-spend reporting)
line_item_iam_principal       -- Full IAM ARN of caller (requires INCLUDE_IAM_PRINCIPAL_DATA)
line_item_resource_id         -- Inference profile ARN (requires INCLUDE_RESOURCES)
product_region                -- AWS region where inference ran

Token type reconciliation: CUR creates separate line items for each token type. A single Bedrock request generating cached output will produce up to four line items: input tokens, output tokens, cache read tokens, and cache write tokens. Any query summing only input and output will undercount costs — typically by 15–40% for workloads using prompt caching. Always sum all four.


4. Cross-Account Athena Query Patterns

The CUR 2.0 export lands in S3. An Athena Data Catalog table (or AWS Glue crawler) maps the export to a queryable table — conventionally named COST_AND_USAGE_REPORT or similar. All queries below assume the management account CUR export is queried from an Athena workgroup in the FinOps account with appropriate cross-account S3 read permissions.

4.1 Total Bedrock spend by member account (monthly)

SELECT
  line_item_usage_account_id                          AS account_id,
  line_item_usage_account_name                        AS account_name,
  DATE_TRUNC('month', line_item_usage_start_date)     AS billing_month,
  SUM(line_item_unblended_cost)                       AS total_cost_usd,
  SUM(CASE
    WHEN line_item_usage_type LIKE '%-input-tokens%'       THEN line_item_unblended_cost
    ELSE 0 END)                                       AS input_token_cost,
  SUM(CASE
    WHEN line_item_usage_type LIKE '%-output-tokens%'      THEN line_item_unblended_cost
    ELSE 0 END)                                       AS output_token_cost,
  SUM(CASE
    WHEN line_item_usage_type LIKE '%-cache-read%'         THEN line_item_unblended_cost
    ELSE 0 END)                                       AS cache_read_cost,
  SUM(CASE
    WHEN line_item_usage_type LIKE '%-cache-write%'        THEN line_item_unblended_cost
    ELSE 0 END)                                       AS cache_write_cost
FROM COST_AND_USAGE_REPORT
WHERE
  product_product_name = 'Amazon Bedrock'
  AND line_item_line_item_type IN ('Usage', 'SavingsPlanCoveredUsage')
  AND year = '2026'
  AND month = '06'
GROUP BY 1, 2, 3
ORDER BY total_cost_usd DESC;

4.2 Bedrock spend by model across all member accounts

SELECT
  line_item_usage_account_id                       AS account_id,
  -- Extract model name from usage type: USE1-Claude4.6Sonnet-input-tokens -> Claude4.6Sonnet
  REGEXP_EXTRACT(
    line_item_usage_type,
    '^[A-Z0-9]+-(.+?)-(input|output|cache)',
    1
  )                                                AS model_name,
  -- Detect cross-region routing
  CASE
    WHEN line_item_usage_type LIKE '%-cross-region-global' THEN 'cross-region'
    WHEN line_item_usage_type LIKE '%-mantle-%'            THEN 'managed (mantle)'
    ELSE 'in-region'
  END                                              AS routing_type,
  SUM(line_item_unblended_cost)                    AS total_cost_usd,
  SUM(line_item_usage_amount)                      AS total_tokens
FROM COST_AND_USAGE_REPORT
WHERE
  product_product_name = 'Amazon Bedrock'
  AND line_item_line_item_type = 'Usage'
  AND year = '2026'
GROUP BY 1, 2, 3
ORDER BY total_cost_usd DESC;

4.3 IAM principal attribution — who is calling what across accounts

Requires INCLUDE_IAM_PRINCIPAL_DATA = TRUE in CUR table configuration.

SELECT
  line_item_usage_account_id                       AS account_id,
  line_item_iam_principal                          AS caller_arn,
  -- Extract role or user name from ARN
  REGEXP_EXTRACT(line_item_iam_principal, ':(?:role|user)/(.+)$', 1)
                                                   AS principal_name,
  -- IAM principal tags (activated cost allocation tags)
  tags['iamPrincipal/team']                        AS team,
  tags['iamPrincipal/cost-center']                 AS cost_center,
  tags['iamPrincipal/project']                     AS project,
  SUM(line_item_unblended_cost)                    AS total_cost_usd
FROM COST_AND_USAGE_REPORT
WHERE
  product_product_name = 'Amazon Bedrock'
  AND line_item_iam_principal IS NOT NULL
  AND year = '2026'
  AND month = '06'
GROUP BY 1, 2, 3, 4, 5, 6
ORDER BY total_cost_usd DESC
LIMIT 100;

4.4 Application inference profile attribution

Application inference profiles (AIP) tag all inference through them. The profile ARN appears in line_item_resource_id when INCLUDE_RESOURCES = TRUE.

SELECT
  line_item_usage_account_id                       AS account_id,
  line_item_resource_id                            AS inference_profile_arn,
  -- Tags on the inference profile surface as resource tags
  resource_tags['resourceTags/application']        AS application,
  resource_tags['resourceTags/env']                AS environment,
  resource_tags['resourceTags/team']               AS team,
  SUM(line_item_unblended_cost)                    AS total_cost_usd
FROM COST_AND_USAGE_REPORT
WHERE
  product_product_name = 'Amazon Bedrock'
  AND line_item_resource_id LIKE 'arn:aws:bedrock:%:application-inference-profile/%'
  AND year = '2026'
GROUP BY 1, 2, 3, 4, 5
ORDER BY total_cost_usd DESC;

4.5 Cross-account chargeback — cost by OU

Requires joining CUR to the Organizations account-to-OU mapping. Export that mapping via AWS Organizations API to a reference table in S3/Athena.

-- Assumes org_account_ou mapping table: account_id, ou_id, ou_name, account_name
SELECT
  m.ou_name,
  c.line_item_usage_account_id,
  m.account_name,
  DATE_TRUNC('month', c.line_item_usage_start_date) AS billing_month,
  SUM(c.line_item_unblended_cost)                   AS bedrock_cost_usd
FROM COST_AND_USAGE_REPORT c
JOIN org_account_ou m
  ON c.line_item_usage_account_id = m.account_id
WHERE
  c.product_product_name = 'Amazon Bedrock'
  AND c.line_item_line_item_type = 'Usage'
  AND c.year = '2026'
GROUP BY 1, 2, 3, 4
ORDER BY bedrock_cost_usd DESC;

5. Service Control Policies for Cross-Account Bedrock Governance

SCPs are the primary mechanism for enforcing Bedrock governance at scale. They apply to all IAM principals in all member accounts within the targeted OU or account — including the root user. They cannot be bypassed by account-level IAM permissions. SCPs do not affect the management account.

5.1 Deny direct Bedrock invocation — require application inference profiles

This pattern forces all Bedrock invocations through tagged application inference profiles, ensuring every call is attributable and monitored. Teams cannot bypass the tagging requirement by calling the foundation model ARN directly.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyDirectFoundationModelInvocation",
      "Effect": "Deny",
      "Action": [
        "bedrock:InvokeModel",
        "bedrock:InvokeModelWithResponseStream",
        "bedrock:Converse",
        "bedrock:ConverseStream"
      ],
      "Resource": [
        "arn:aws:bedrock:*::foundation-model/*"
      ],
      "Condition": {
        "StringNotLike": {
          "bedrock:InferenceProfileArn": "arn:aws:bedrock:*:*:application-inference-profile/*"
        }
      }
    }
  ]
}

5.2 Restrict allowed models org-wide

Allow only approved models. Any model not in the list is denied across all member accounts. Update the list as new models complete your internal security review.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowApprovedBedrockModelsOnly",
      "Effect": "Deny",
      "Action": [
        "bedrock:InvokeModel",
        "bedrock:InvokeModelWithResponseStream",
        "bedrock:Converse",
        "bedrock:ConverseStream"
      ],
      "Resource": "arn:aws:bedrock:*::foundation-model/*",
      "Condition": {
        "StringNotLike": {
          "aws:ResourceTag/bedrock:model-id": [
            "anthropic.claude-*",
            "amazon.nova-*",
            "amazon.titan-*"
          ]
        }
      }
    },
    {
      "Sid": "BlockUnapprovedModelArns",
      "Effect": "Deny",
      "Action": [
        "bedrock:InvokeModel",
        "bedrock:InvokeModelWithResponseStream"
      ],
      "NotResource": [
        "arn:aws:bedrock:*::foundation-model/anthropic.claude-*",
        "arn:aws:bedrock:*::foundation-model/amazon.nova-*",
        "arn:aws:bedrock:*::foundation-model/amazon.titan-*",
        "arn:aws:bedrock:*:*:application-inference-profile/*",
        "arn:aws:bedrock:*:*:inference-profile/*"
      ]
    }
  ]
}

5.3 Enforce tagging on application inference profile creation

Prevent member accounts from creating inference profiles that lack required cost allocation tags. Without this, teams can create profiles that produce unattributable spend.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "RequireTagsOnInferenceProfileCreation",
      "Effect": "Deny",
      "Action": [
        "bedrock:CreateInferenceProfile"
      ],
      "Resource": "*",
      "Condition": {
        "Null": {
          "aws:RequestTag/team": "true"
        }
      }
    },
    {
      "Sid": "RequireCostCenterTag",
      "Effect": "Deny",
      "Action": [
        "bedrock:CreateInferenceProfile"
      ],
      "Resource": "*",
      "Condition": {
        "Null": {
          "aws:RequestTag/cost-center": "true"
        }
      }
    }
  ]
}

5.4 Restrict Bedrock to approved regions

Enforce data residency and prevent shadow deployments in regions outside your approved footprint.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyBedrockOutsideApprovedRegions",
      "Effect": "Deny",
      "Action": "bedrock:*",
      "Resource": "*",
      "Condition": {
        "StringNotEquals": {
          "aws:RequestedRegion": [
            "us-east-1",
            "us-west-2",
            "eu-west-1"
          ]
        }
      }
    }
  ]
}

5.5 Cross-account Bedrock Guardrails enforcement (April 2026)

AWS launched org-level Guardrails enforcement via an Organizations policy type. A Bedrock policy attached to the org root or an OU pins a centrally-managed guardrail to all member account invocations. This is infrastructure-layer enforcement — member accounts cannot override it with IAM permissions. The governance account creates the guardrail and pins the version; the Organizations policy distributes it.

This is distinct from SCPs. SCPs control whether the API call is allowed. Guardrails enforcement controls what happens after the call is allowed — content filtering, topic denial, sensitive data redaction, grounding checks. Use both layers together.


6. AWS Organizations Tag Policies for Bedrock

Tag policies define the canonical taxonomy and enforce it across accounts. Two enforcement modes matter for Bedrock FinOps.

team          -- Engineering team or squad (e.g., "platform-ml", "product-search")
cost-center   -- Financial cost center code (e.g., "CC-4421")
environment   -- Stage (e.g., "prod", "staging", "dev")
project       -- Business initiative or product line (e.g., "contract-review-v2")
application   -- Specific application or service name (e.g., "legal-assist-api")

Case sensitivity is a common failure mode. CostCenter, cost-center, and costcenter create three separate columns in CUR. Standardize on hyphenated lowercase before rolling out enforcement.

6.2 Tag policy JSON for Bedrock inference profiles

{
  "tags": {
    "team": {
      "tag_key": {
        "@@assign": "team"
      },
      "enforced_for": {
        "@@assign": [
          "bedrock:application-inference-profile"
        ]
      }
    },
    "cost-center": {
      "tag_key": {
        "@@assign": "cost-center"
      },
      "tag_value": {
        "@@assign": [
          "CC-*"
        ]
      },
      "enforced_for": {
        "@@assign": [
          "bedrock:application-inference-profile"
        ]
      }
    },
    "environment": {
      "tag_key": {
        "@@assign": "environment"
      },
      "tag_value": {
        "@@assign": [
          "prod",
          "staging",
          "dev",
          "sandbox"
        ]
      },
      "enforced_for": {
        "@@assign": [
          "bedrock:application-inference-profile"
        ]
      }
    }
  }
}

Important limitation: Tag policies can enforce values and key casing on tagged resources, but they cannot force a tag to be present on creation. Use the SCP from Section 5.3 (Null condition) to block creation without the required tags. The tag policy then enforces the format of the tags that are present. Together, the two mechanisms close the compliance gap.

6.3 Reporting and remediation

After attaching a tag policy to an OU, generate a cross-account compliance report from the Organizations console or CLI:

aws organizations start-policy-change-effects-simulation \
  --policy-id p-tagpolicy123456 \
  --account-id-to-simulate <member-account-id>

# Export non-compliant resource report across all accounts in OU
aws resourcegroupstaggingapi get-compliance-summary \
  --target-id ou-xxxx-yyyyyyy \
  --target-type OU

Tag changes take up to 24 hours to propagate to CUR. After activating new cost allocation tags in the Billing console, allow 24 hours before running attribution queries against them.


7. Cross-Account LiteLLM Patterns with Proper Attribution

LiteLLM is the most common open-source gateway for centralized Bedrock access. The architectural challenge: LiteLLM authenticates users at its own layer (API keys, teams, virtual keys) but calls Bedrock using a single IAM role. Without additional work, all Bedrock costs in CUR appear under the gateway’s execution role ARN — zero per-team visibility in billing.

7.1 Architecture: dedicated Bedrock account with cross-account IAM

┌─────────────────────────────────┐
│  Platform Account (gateway)     │
│  LiteLLM on EKS                 │
│  API key → team mapping         │
│  AssumeRole per team ──────────►│─────────────────────────────────┐
└─────────────────────────────────┘                                  │
                                                                     ▼
                                              ┌─────────────────────────────────┐
                                              │  Bedrock Account (centralized)  │
                                              │  Bedrock API                    │
                                              │  Application inference profiles │
                                              │  One IAM role per team          │
                                              └─────────────────────────────────┘

The gateway calls sts:AssumeRole for the team-specific role in the Bedrock account, passing session tags:

import boto3

def get_bedrock_client_for_team(team_id: str, cost_center: str, project: str):
    sts = boto3.client("sts")
    response = sts.assume_role(
        RoleArn=f"arn:aws:iam::BEDROCK_ACCOUNT_ID:role/bedrock-{team_id}",
        RoleSessionName=f"litellm-{team_id}",
        Tags=[
            {"Key": "team",        "Value": team_id},
            {"Key": "cost-center", "Value": cost_center},
            {"Key": "project",     "Value": project},
        ],
        DurationSeconds=3600,
    )
    creds = response["Credentials"]
    return boto3.client(
        "bedrock-runtime",
        region_name="us-east-1",
        aws_access_key_id=creds["AccessKeyId"],
        aws_secret_access_key=creds["SecretAccessKey"],
        aws_session_token=creds["SessionToken"],
    )

Session tags passed at AssumeRole time appear in CUR 2.0 as iamPrincipal/team, iamPrincipal/cost-center, iamPrincipal/project — separate from any tags on the role itself. This enables Athena queries to slice Bedrock costs by team even though all traffic goes through a single gateway.

7.2 LiteLLM virtual key → team mapping

LiteLLM maintains a PostgreSQL database with virtual key records. Map virtual keys to team IDs and cost centers in the LiteLLM_Team table. Use the LiteLLM /spend API for internal dashboards; use CUR + Athena for chargebacks and executive reporting (the two systems should agree within normal latency windows).

# LiteLLM budget enforcement per team
litellm --config config.yaml &

# Set budget via API
curl -X POST https://litellm-proxy/team/new \
  -H "Authorization: Bearer sk-admin" \
  -d '{"team_id": "platform-ml", "max_budget": 5000, "budget_reset_at": "2026-07-01T00:00:00Z"}'

LiteLLM budget limits are soft guards (deny requests when budget exceeded) running at the proxy layer. They complement — do not replace — hard organizational budget alerts and SCP-enforced quota management.

7.3 Single-account vs centralized Bedrock account

Two common topologies:

Topology When to use CUR attribution
Each team has its own AWS account with Bedrock access Teams operate independently; isolation is primary concern; org is decentralized line_item_usage_account_id directly identifies the team; IAM principal tags give sub-team detail
Centralized Bedrock account, all teams access via cross-account role Platform team owns Bedrock capacity and quotas; cost negotiation is centralized; quota management is simpler line_item_usage_account_id is always the Bedrock account; IAM principal + session tags carry team attribution

For organizations with active EDP negotiations, the centralized topology pools all Bedrock spend into one account’s usage history, which simplifies commitment sizing conversations with AWS. For organizations prioritizing team autonomy and blast radius isolation, the per-account topology with IAM-principal attribution is preferable.


8. Account-Level Quota Management: Strategy for Large Orgs

Bedrock quotas are strictly per-account and per-region. There is no org-level quota pool. Every member account starts with default limits that apply independently. This has direct operational and financial consequences at scale.

8.1 Quota structure

The bedrock-runtime endpoint enforces three quota types per model per region per account:

Quota Scope Adjustable
On-demand TPM (tokens per minute) Per model, per region, per account Yes (most models)
Cross-region TPM Per model, per region, per account Yes
Max tokens per day Per model, per region, per account Yes (linked to TPM increases)
RPM (requests per minute) Per model, per region, per account Yes (model-specific)

The bedrock-mantle endpoint (Amazon’s managed inference tier) has separate input-TPM and output-TPM quotas tracked independently, distinct from bedrock-runtime quotas.

New AWS accounts receive reduced default quotas. AWS support documentation states that quota increase requests “might be denied if you don’t meet this condition” — i.e., if the account is not already consuming a meaningful fraction of its current quota. This creates a cold-start problem for new team accounts.

8.2 Quota strategy for large organizations

Option A: Centralized Bedrock account (quota pooling by consolidation)

All inference runs through one account. Request large quota increases once for that account. Teams that would individually fail quota increase approvals (insufficient traffic history) benefit from the combined traffic the central account generates. The tradeoff is tight coupling — if the central account hits a limit, all teams degrade simultaneously.

Option B: Per-team accounts with pre-provisioned quotas

Each team account requests quota increases as part of account provisioning. Use a Control Tower Account Factory customization (via CfCT or AFT) to automatically submit quota increase requests when a new account is vended.

# Submit quota increase via CLI at account vend time
aws service-quotas request-service-quota-increase \
  --service-code bedrock \
  --quota-code L-CLAUDE46SONNET-TPM \
  --desired-value 2000000 \
  --region us-east-1

Track all in-flight quota requests in a central registry. AWS processes increases asynchronously; status checks:

aws service-quotas list-requested-changes-by-service \
  --service-code bedrock \
  --query 'RequestedQuotas[?Status==`PENDING`].[QuotaName, DesiredValue, Status]' \
  --output table

Option C: Provisioned Throughput for predictable workloads

For production applications with sustained, predictable traffic, Provisioned Throughput reserves capacity in model units (MUs). PT quotas are separate from on-demand quotas and are not shared across accounts. PT commitments are account-scoped. If the same application runs in multiple accounts (e.g., multi-region active-active), each account needs its own PT commitment — there is no cross-account PT sharing.

Quota monitoring: AWS released a CloudWatch metric EstimatedTPMQuotaUsage in early 2026 that tracks token-per-minute quota consumption in real time, including prompt cache write token burndown. Set alarms at 75% of quota limit per model per account to get advance warning before throttling begins.

aws cloudwatch put-metric-alarm \
  --alarm-name "bedrock-tpm-75pct-claude-sonnet" \
  --metric-name EstimatedTPMQuotaUsage \
  --namespace AWS/Bedrock \
  --dimensions Name=ModelId,Value=anthropic.claude-sonnet-4-6 \
  --threshold 75 \
  --comparison-operator GreaterThanOrEqualToThreshold \
  --evaluation-periods 3 \
  --period 60 \
  --statistic Average \
  --alarm-actions arn:aws:sns:us-east-1:ACCOUNT:bedrock-quota-alerts

9. EDP Structure for Bedrock: Multi-Account Spend Pooling

The Enterprise Discount Program (EDP) is a private negotiated agreement where an organization commits to a minimum dollar spend over 1–5 years in exchange for a percentage discount across eligible AWS services. Key Bedrock-specific dynamics in 2026:

9.1 Bedrock inclusion in EDP

As of 2026, Bedrock on-demand inference is explicitly negotiable as part of EDP scope. In 2024, AI services were frequently excluded or treated as a low-discount category. The shift reflects AWS’s strategic interest in locking in AI workloads at enterprise scale. For organizations with material Bedrock spend (>$500K/year projected), explicitly include Bedrock in EDP negotiation rather than accepting the default all-services treatment.

Discount tiers reported in market for 2026 EDP negotiations covering Bedrock: 8–15% on committed Bedrock spend for three-year commitments. Spot discounts for high-token-throughput customers are being offered ad hoc but are not yet systematized into standard EDP tier structures.

9.2 Multi-account spend pools against EDP commitment

EDP commitment retirement is calculated against the consolidated bill at the management account level. All member account Bedrock spend — regardless of how many accounts generate it — contributes to the same EDP commitment pool. This is the key financial argument for consolidated billing even when teams prefer isolated accounts.

Practical implication: an org with 20 member accounts each spending $50K/month on Bedrock has $1M/month pooled against a single EDP commitment. The same 20 accounts, if operating as separate AWS customers with separate EDPs, would each need to individually negotiate an EDP against $50K/month — a threshold that does not typically justify a formal EDP.

9.3 EDP commitment sizing for Bedrock

Token usage is volatile — model selection, context lengths, and caching ratios all shift as applications mature. Structure Bedrock EDP commitments with:

  • A conservative base (75% of current 3-month average) as the hard floor
  • Overage rates negotiated below list price (not just list)
  • A ramp clause in year 1 if Bedrock adoption is early-stage

9.4 Marketplace SaaS purchases against EDP

AWS EDP allows up to 25% of commitment to be retired through qualifying AWS Marketplace SaaS purchases. Some third-party model providers on Bedrock Marketplace bill as SaaS; usage of those models can count toward EDP retirement. Verify eligibility for specific Marketplace model vendors during EDP negotiation — not all third-party Bedrock models qualify.


10. Consolidated Billing for Marketplace Bedrock Models

Third-party models on Bedrock — including Anthropic Claude models (sold as Anthropic PBC third-party content), Mistral, Meta Llama, and others that require Marketplace subscriptions — have a distinct billing flow from AWS first-party services.

10.1 How managed entitlements work

Organizations subscribe once from the management account and distribute access via AWS License Manager grants:

  1. Management account subscribes to the model on Marketplace (or receives a Private Offer)
  2. License Manager creates a license in us-east-1 (all licenses are created here regardless of invocation region)
  3. Management account creates grants to member accounts or the entire org
  4. Member accounts activate their grants
  5. Member accounts invoke the model; billing flows to the subscription holder (management account)

The key FinOps property: When grants are used, the billing entity is the account holding the original subscription — not the member account invoking the model. Marketplace software fees appear on the management account’s AWS bill consolidated with all other charges.

10.2 Does multi-account spending aggregate for software fees?

For third-party Bedrock models: yes, effectively. When the management account holds the subscription and distributes via managed entitlements, the management account is billed for all member account usage. CUR line items for Marketplace model invocations appear under the management account (or payer account) as seller-specific charges — e.g., sold by Anthropic, PBC with bill_payer_account_id equal to the management account.

For Private Offer pricing: the negotiated rates apply automatically to all member accounts receiving grants, ensuring consistent pricing org-wide rather than each team independently negotiating from list price.

10.3 Model access without Marketplace (auto-enable)

Some Bedrock models support auto-enablement — on first invocation in a member account, Bedrock automatically creates a Marketplace subscription. In a managed entitlements setup, this creates a billing anomaly: the member account is now the subscription holder for that model, not the management account. Prevent this by:

  1. Pre-distributing grants from the management account before teams invoke
  2. Using an SCP to deny marketplace:Subscribe in member accounts for Bedrock model categories
  3. Enabling All features in AWS Organizations (vs consolidated billing only), which allows automatic grant acceptance

11. Cost Allocation at Org Level: Cost Categories and Cross-Account Attribution

AWS Cost Categories create named cost dimensions that span accounts, services, and tags. They appear in CUR as cost_category_* columns and in Cost Explorer as filterable dimensions. For Bedrock FinOps across a large org, Cost Categories layer on top of raw tag-based attribution to build the reporting hierarchy that finance teams need.

11.1 Cost Category structure for Bedrock

A three-tier hierarchy maps cleanly to enterprise reporting:

Business Unit  (cost_category_business_unit)
  └── Product Line  (cost_category_product_line)
        └── Environment  (cost_category_environment)

Define categories using tag matching rules in the AWS Billing console or via API. Example: the “Platform ML” Business Unit rule matches all accounts in the platform OU plus any resource tagged team: platform-*.

11.2 Account tag cost allocation (December 2025 feature)

AWS launched support for Organizations account tags as cost allocation dimensions in December 2025. Tags applied at the account level in AWS Organizations (e.g., business-unit: fraud-prevention, environment: prod) now propagate automatically to all line items from that account in CUR — without requiring every Bedrock inference profile or IAM principal inside the account to carry those tags.

This dramatically simplifies attribution for the common pattern where one account = one team. The account-level tags carry the business dimension; resource-level and principal-level tags carry the application and use-case dimension.

11.3 Tagging strategy: multi-layer approach

Tag layer Where applied Propagates to CUR Purpose
Account tag AWS Organizations account object Yes (Dec 2025) Team, business unit, environment
IAM principal tag IAM user or role in member account Yes (via iamPrincipal/ prefix) Service, persona, functional role
Session tag Passed at AssumeRole Yes (via iamPrincipal/ prefix) Dynamic project or tenant attribution
Application inference profile tag Bedrock AIP resource Yes (via resourceTags/ prefix) Application, use case, model policy

Activate all tag keys as cost allocation tags in the Billing console. Process: Billing → Cost Allocation Tags → Activate. Takes 24 hours to populate in CUR and Cost Explorer.

11.4 Cross-account cost allocation Athena query combining all layers

SELECT
  -- Account-level dimensions (from Organizations account tags via Dec 2025 feature)
  tags['account/business-unit']                    AS business_unit,
  tags['account/environment']                      AS environment,
  -- Team-level (from IAM principal tags)
  tags['iamPrincipal/team']                        AS team,
  tags['iamPrincipal/cost-center']                 AS cost_center,
  -- Application-level (from inference profile tags)
  tags['resourceTags/application']                 AS application,
  tags['resourceTags/project']                     AS project,
  -- Cost Category hierarchies (pre-computed by AWS billing)
  cost_category['business_unit']                   AS reporting_bu,
  -- Spend metrics
  line_item_usage_account_id                       AS account_id,
  DATE_TRUNC('month', line_item_usage_start_date)  AS billing_month,
  SUM(line_item_unblended_cost)                    AS total_usd,
  SUM(line_item_blended_cost)                      AS blended_usd,  -- after EDP
  SUM(CASE WHEN line_item_usage_type LIKE '%-cross-region-global'
           THEN line_item_unblended_cost ELSE 0 END) AS cross_region_premium_usd
FROM COST_AND_USAGE_REPORT
WHERE
  product_product_name = 'Amazon Bedrock'
  AND line_item_line_item_type IN ('Usage', 'SavingsPlanCoveredUsage')
  AND year = '2026'
  AND month = '06'
GROUP BY 1, 2, 3, 4, 5, 6, 7, 8, 9
ORDER BY total_usd DESC;

Org Design Reference

The following account topology supports all patterns in this note:

Management (payer) account
├── FinOps account
│   ├── CUR 2.0 S3 bucket (management account export)
│   ├── Athena workgroup + Glue catalog
│   └── Cost dashboard / chargeback tooling
│
├── Governance OU
│   └── AI Governance account
│       ├── Bedrock Guardrails (org-enforced)
│       └── Marketplace subscriptions + managed entitlement grants
│
├── Platform OU
│   └── Bedrock Gateway account
│       ├── LiteLLM or custom gateway
│       ├── Application inference profiles (one per team × environment)
│       └── Per-team IAM roles (cross-account AssumeRole targets)
│
├── Product OU (per business unit)
│   ├── Team A prod account
│   ├── Team A staging account
│   └── Team A dev account
│
└── SCP policy attachments:
    ├── Root: region restriction, model allowlist
    ├── Product OU: deny direct foundation model invocation
    └── All member accounts: require tags on AIP creation

Key invariants this design enforces:

  • No Bedrock workloads in the management account
  • All Marketplace subscriptions held by AI Governance account, distributed via grants
  • All cross-account Bedrock calls flow through per-team roles with session tags
  • Single CUR export from management account is the billing authority
  • SCPs at the OU level — not account level — prevent drift when new accounts are vended

Known Gaps and Caveats (as of June 2026)

  • No org-level quota: There is still no mechanism to share quota headroom across accounts. Centralized Bedrock account remains the only practical way to pool quota.
  • CUR latency: CUR 2.0 data is finalized for the previous day by ~10am UTC. Real-time cost monitoring requires CloudWatch metrics (per-account only) rather than CUR queries.
  • IAM principal data availability: INCLUDE_IAM_PRINCIPAL_DATA only backfills to April 8, 2026. Historical queries before that date have no line_item_iam_principal column data.
  • Tag policy Bedrock resource type support: The enforced_for field in tag policies requires the resource type to be on the AWS-supported enforcement list. As of June 2026, bedrock:application-inference-profile is listed as supported; verify in the Organizations console for any new resource types before relying on tag policy enforcement rather than SCP enforcement.
  • EDP Marketplace retirement (25% cap): The 25% Marketplace-against-EDP retirement cap limits how much Anthropic model spend can retire EDP commitment when billed as third-party content. Negotiate this cap explicitly if Marketplace models are a large fraction of your Bedrock footprint.

Sources