AWS Budgets offers four budget types that matter for Bedrock governance. Understanding which to use — and when to combine them — is the first architectural decision.
1.1 Cost Budgets
Cost budgets track dollar spend against a threshold. For Bedrock, a cost budget filtered to Service = Amazon Bedrock gives you a monthly dollar ceiling with alert thresholds at any percentage of that ceiling. This is the most common starting point because it maps directly to finance reporting and is model-agnostic.
Cost budgets support both ACTUAL (spend already billed) and FORECASTED (AWS projected spend for the period) alert types. For Bedrock workloads with bursty usage patterns, forecasted alerts catch trajectory problems mid-month before the final bill arrives.
1.2 Usage Budgets (Token Units)
Usage budgets track consumption in native service units rather than dollars. For Bedrock, the relevant unit is tokens as they appear in the CUR line_item_usage_type field. Each model and token type generates a distinct usage type entry:
CUR line_item_usage_type pattern |
What it measures |
|---|---|
{region}-{model}-input-tokens |
Input tokens, standard tier, in-region |
{region}-{model}-output-tokens |
Output tokens, standard tier, in-region |
{region}-{model}-cache-read-input-token-count |
Prompt cache read tokens |
{region}-{model}-cache-write-input-token-count |
Prompt cache write tokens |
{region}-{model}-input-tokens-cross-region-global |
Input tokens, cross-region routing |
{region}-{model}-{token-type}-priority |
Priority tier tokens |
{region}-{model}-{token-type}-flex |
Flex tier tokens |
Key construction note: The region prefix uses the short CUR form, not the full endpoint name. USE1 maps to us-east-1. A Claude Sonnet 4.6 input-token usage type in us-east-1 reads as USE1-Claude4.6Sonnet-input-tokens.
Usage budget limitation: A usage budget can only monitor a single unit of measure. You cannot create one usage budget that covers both input tokens and output tokens unless you use the “Usage type group” filter, which rolls up all Bedrock token types by unit. In practice, separate usage budgets per token class are preferred for precision.
Token-based budgets are preferable to cost budgets when:
- You need to enforce a capacity commitment independent of model pricing changes
- Engineering teams are accountable to token quotas rather than dollar amounts
- You are on Provisioned Throughput and want to track utilization against reserved capacity
1.3 Reservation Utilization and Coverage Budgets
For teams using Bedrock Provisioned Throughput (model units purchased as reserved capacity), AWS Budgets supports RI utilization budgets that alert when actual usage drops below a utilization threshold — for example, alerting when provisioned model units are utilized below 70% of purchased capacity. This is a cost-efficiency signal: low utilization means you are paying for idle reserved capacity.
Coverage budgets invert the lens: they alert when a percentage of your on-demand spend is not covered by reservations. If your team is supposed to run 80% of traffic on provisioned units but on-demand spend climbs, the coverage budget catches the drift.
2. Budget Filter Configuration for Bedrock
AWS Budgets exposes the following filter dimensions that are relevant to Bedrock governance. Filters are applied at budget creation and narrow the spend tracked by that budget.
2.1 Service Filter
The primary filter for Bedrock isolation:
Service = Amazon Bedrock
This captures all Bedrock charges: model inference, knowledge base operations, agent invocations, and embedding generation. Without this filter, you are budgeting total account spend.
Important: The Service filter is only available for cost budgets, Savings Plans budgets, and RI budgets. It is not available for usage budgets. To scope a usage budget to Bedrock, use the Usage type or Usage type group filter instead.
2.2 Usage Type and Usage Type Group Filters
For usage budgets, specify the exact CUR usage type string or select a usage type group. Usage type groups aggregate types by unit:
- Select
Usage type group→ filter forBedrock Tokento capture all Bedrock token consumption across models in a single usage budget - Select
Usage type→ enter the full pattern likeUSE1-Claude4.6Sonnet-input-tokensfor model-specific budgets
2.3 Linked Account Filter
In a consolidated billing Organization, the management account can create budgets that filter to a specific member account:
Linked account = 012345678901 # the member account running Bedrock
This enables team-level or environment-level budgets from a centralized FinOps account without requiring access to each member account.
Critical constraint: The Linked account filter is NOT available when creating budgets from within a member account. It is only available from the management account or from a delegated administrator account. Attempting to use it from a member account will fail silently or show no results.
2.4 Tag Filters
Cost allocation tags are the most granular filter available. Bedrock supports tag propagation through three mechanisms:
- IAM principal tags — tags on the IAM user or role making the request propagate to CUR under the
iamPrincipal/{key}prefix - Application Inference Profile tags — tags on an AIP appear under
resourceTags/{key} - Project tags — tags assigned to a Bedrock Project (GA 2025)
A common tagging taxonomy for Bedrock governance:
team = platform-engineering
cost-center = eng-001
environment = production
workload = document-qa
After activating these as cost allocation tags in the Billing console (allow up to 24 hours for backfill), a team-scoped budget filter looks like:
Tag: team = platform-engineering
Tag: environment = production
Activation is required. Tags that exist on resources but have not been activated as cost allocation tags do not appear in Budgets filters, Cost Explorer, or CUR.
2.5 Region Filter
Bedrock runs in multiple regions. A region filter scopes the budget to a specific deployment:
Region = US East (N. Virginia)
Useful when cross-region inference routing is intentionally controlled and costs should not bleed across regional budgets.
3. Budget Alert Thresholds
3.1 Actual vs. Forecasted
Each alert on a budget is independently configured as either ACTUAL or FORECASTED:
- ACTUAL: fires when spend already billed crosses the threshold. Zero-lag signal but late by definition — the usage has already occurred.
- FORECASTED: fires when AWS’s linear projection for the current period exceeds the threshold. Gives advance warning but can produce false positives early in the month when the projection line is steep due to sparse data.
Best practice: configure at least one FORECASTED alert at 80% and one ACTUAL alert at 90% on the same budget.
3.2 Absolute vs. Percentage Thresholds
Thresholds can be expressed as:
- Absolute value: a fixed dollar or token amount. Example: alert when actual spend exceeds $500.
- Percentage of budgeted amount: a fraction of the budget ceiling. Example: alert when actual spend exceeds 80% of a $1,000 budget.
Percentage thresholds survive budget ceiling changes without requiring alert reconfiguration.
3.3 Multiple Thresholds Per Budget
A single budget supports up to 5 alert thresholds. A production Bedrock cost budget might use:
| # | Type | Threshold | Channel |
|---|---|---|---|
| 1 | Forecasted | 50% | Email to FinOps team |
| 2 | Forecasted | 80% | SNS → Slack |
| 3 | Actual | 80% | SNS → Slack |
| 4 | Actual | 90% | SNS → PagerDuty (low severity) |
| 5 | Actual | 100% | SNS → PagerDuty (high severity) + Budget Action trigger |
Each alert threshold is independently addressable with its own SNS topic, email list, and Budget Action.
4. Budget Actions: Automatic IAM Restriction on Breach
Budget Actions convert a passive alert into an enforcement mechanism. When a threshold is breached, AWS Budgets can take one of three action types:
| Action type | What it does | Scope |
|---|---|---|
APPLY_IAM_POLICY |
Attaches a restrictive IAM policy to specified users, groups, or roles | Member account |
APPLY_SCP_POLICY |
Attaches a Service Control Policy to a member account or OU | Org-wide, management account only |
RUN_SSM_DOCUMENTS |
Stops specified EC2 or RDS instances | Member account |
For Bedrock governance, APPLY_IAM_POLICY is the primary mechanism for restricting API access at the team level without requiring SCP elevation.
4.1 Deny Policy for Bedrock Inference
The IAM policy attached by a Budget Action must pre-exist and carry a specific structure. A deny-all Bedrock inference policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyBedrockInferenceOnBudgetBreach",
"Effect": "Deny",
"Action": [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream",
"bedrock:Converse",
"bedrock:ConverseStream",
"bedrock:InvokeAgent"
],
"Resource": "*"
}
]
}
A more granular policy restricts only specific model ARNs or Application Inference Profiles:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyHighCostModelsOnBreach",
"Effect": "Deny",
"Action": [
"bedrock:InvokeModel",
"bedrock:Converse"
],
"Resource": [
"arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-opus-4-5",
"arn:aws:bedrock:us-east-1:123456789012:application-inference-profile/prod-document-qa"
]
}
]
}
4.2 Execution Role Requirements
AWS Budgets needs an IAM role to perform the action. The role must trust budgets.amazonaws.com and carry these permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iam:AttachGroupPolicy",
"iam:AttachRolePolicy",
"iam:AttachUserPolicy",
"iam:DetachGroupPolicy",
"iam:DetachRolePolicy",
"iam:DetachUserPolicy"
],
"Resource": "*"
}
]
}
AWS provides a managed policy AWSBudgetsActionsRolePolicyForResourceAdministrationWithSSM that includes these permissions and will be updated by AWS as new Budget Action capabilities are added — preferable to maintaining a custom inline policy.
4.3 Approval Modes
Budget Actions support two execution modes:
- AUTOMATIC: the action executes immediately when the threshold is crossed. Zero human latency, appropriate for hard budget enforcement.
- MANUAL: the action is queued but requires a human to approve it in the Budgets console or via the
ExecuteBudgetActionAPI. Appropriate when a false positive could cause an outage.
For production Bedrock workloads, the recommended configuration is AUTOMATIC at 100% with a 90% manual-approval gate, giving an operator window to review before the hard block fires.
4.4 SCP Kill Switch (Management Account)
For organizations where a single Bedrock budget applies across multiple member accounts, an SCP action from the management account is the most powerful mechanism. A Bedrock inference SCP:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyBedrockOrgWide",
"Effect": "Deny",
"Action": "bedrock:*",
"Resource": "*"
}
]
}
Apply this cautiously. An org-wide Bedrock deny will halt all inference workloads in all member accounts, including production systems not responsible for the budget breach.
5. Notification Channels
5.1 SNS → Slack / PagerDuty / Email
Each budget alert can publish to one SNS topic. The SNS topic then fans out to any number of downstream subscribers:
Budget alert
→ SNS topic (arn:aws:sns:us-east-1:123456789012:bedrock-budget-alerts)
→ Email subscription (finops@company.com)
→ Lambda subscription (fan-out to Slack webhook)
→ PagerDuty HTTPS endpoint
→ SQS queue (for audit logging)
SNS topic policy must grant the Budgets service principal permission to publish:
{
"Sid": "AllowBudgetsPublish",
"Effect": "Allow",
"Principal": {
"Service": "budgets.amazonaws.com"
},
"Action": "SNS:Publish",
"Resource": "arn:aws:sns:us-east-1:123456789012:bedrock-budget-alerts",
"Condition": {
"StringEquals": {
"aws:SourceAccount": "123456789012"
}
}
}
AWS Chatbot (Amazon Q Developer in chat applications) provides a native console-based integration to route budget alerts directly to Slack channels or Amazon Chime without a custom Lambda.
Notification constraint: A single alert threshold can target a maximum of 1 SNS topic and 10 email addresses. For multi-channel fan-out, use a Lambda subscriber on the SNS topic to route to multiple destinations.
5.2 EventBridge Integration
AWS Budgets publishes events to EventBridge via CloudTrail. The event pattern for all budget events:
{
"source": ["aws.budgets"],
"detail-type": ["AWS API Call via CloudTrail"],
"detail": {
"eventSource": ["budgets.amazonaws.com"]
}
}
To match a specific budget by name, add an eventName filter targeting CreateBudgetAction or ExecuteBudgetAction. EventBridge rules can route budget events to any target — Lambda, Step Functions, SQS, or another SNS topic — enabling richer automation than the native Budget Actions mechanism alone.
A common pattern: EventBridge rule on budget breach → Lambda → update a feature flag in Parameter Store → application reads flag and degrades gracefully before the IAM deny policy fires.
6. Known Limitation: Cost Categories NOT Available as Budget Filter
As of 2026, AWS Cost Categories cannot be used as a filter dimension when creating AWS Budgets.
Cost Categories can be used as a filter dimension in Cost Explorer, CUR queries, and Cost Allocation reports. They are visible in the Budgets UI as an additional billing dimension for grouping results after the fact, but they are not available in the filter configuration that scopes what a budget tracks.
This is a significant operational gap for organizations that have invested in Cost Category hierarchies (e.g., a TeamCostCenter category that maps multiple accounts and tags to a unified team label). Those categories cannot be used to drive Budgets alerts directly.
Workarounds:
- Replicate the Cost Category logic as tag filters on individual budgets. If a Cost Category rolls up three teams, create three budgets with tag filters and set the combined limit accordingly.
- Use EventBridge → Lambda to query Cost Explorer (which does support Cost Category filters) on a schedule and post synthetic alerts to SNS if the Cost Category total exceeds a threshold. This adds latency (scheduled polling vs. real-time alerts) but preserves the Cost Category abstraction.
- Raise the organizational budget from the management account using
Linked accountfilters for each member account captured by the Cost Category.
7. Bedrock Usage Budgets: Token-Based vs. Dollar-Based
7.1 When to Use Token Budgets vs. Cost Budgets
| Criterion | Token budget | Cost budget |
|---|---|---|
| Finance accountability | No — tokens are opaque to finance | Yes — maps to invoice |
| Model price change resilience | Yes — token quota is stable if pricing changes | No — same usage creates different spend |
| Cross-model comparison | Difficult — input tokens for Claude ≠ input tokens for Nova in value | Natural — dollars are comparable |
| Engineering team quotas | Natural — engineers think in tokens, not dollars | Requires mental conversion |
| Budget Action trigger | Supported | Supported |
7.2 Configuring a Token-Based Bedrock Usage Budget
In the AWS Budgets console or API, select:
- Budget type: Usage budget
- Usage type group: select
Bedrock Tokento cover all token types, OR - Usage type: enter specific pattern, e.g.,
USE1-Claude4.6Sonnet-input-tokens - Limit unit:
Tokens(set by the service; cannot be overridden) - Limit amount: integer token count for the period
A monthly budget of 500 million input tokens for Claude Sonnet 4.6 in us-east-1:
Budget type: USAGE
Budget amount: 500,000,000
Usage type: USE1-Claude4.6Sonnet-input-tokens
Period: MONTHLY
Practical sizing note: At Claude Sonnet 4.6’s 2026 pricing of approximately $3.00 per million input tokens, 500M tokens corresponds to roughly $1,500/month. Calibrate token budgets against your cost budget to maintain consistency.
7.3 Cache Token Accounting
Workloads using Bedrock prompt caching must budget separately for cache write tokens (priced above standard input) and cache read tokens (priced significantly below standard input). A workload that writes a 10,000-token system prompt to cache on every cold start will accumulate cache write charges that a standard input-token budget will not capture. Three separate usage budgets are required for full coverage: input, output, and cache tokens.
8. Multi-Account Budget Strategy
8.1 Management Account Budgets
Creating Bedrock budgets from the management account enables:
- Consolidated view: the budget aggregates spend across all member accounts in the org
- Linked account filters: narrow the consolidated budget to specific member accounts
- SCP actions: the only account level from which SCP-type Budget Actions can be applied
- Billing View budgets: AWS Budgets Billing Views (GA August 2025) allow custom cross-account views scoped to subsets of the org without requiring management account credentials for the view consumer
A management-account budget with linked account filter effectively creates a “team budget” that spans all environments (dev/staging/prod) owned by that team across separate accounts.
8.2 Member Account Budgets
Budgets created from a member account are limited to:
- Spend within that single account
- No
Linked accountfilter (self-filtering is not supported) - No SCP actions (management account only)
- IAM policy actions target roles within the same account
Member account budgets are appropriate for per-environment guardrails where engineering team leads need ownership without central FinOps involvement.
8.3 Recommended Multi-Account Architecture
Management account
├── Org-wide Bedrock cost budget (no linked account filter)
│ └── Alert at 80% forecasted → SNS → FinOps Slack channel
│ └── Alert at 100% actual → SCP action (org-wide Bedrock deny)
│
├── Per-team budget (linked account = team's prod account)
│ └── Alert at 80% → SNS → team Slack channel
│ └── Alert at 100% → IAM policy action (Bedrock deny in prod account)
│
└── Per-environment budget (linked account = staging account)
└── Alert at 70% → email to team lead
└── Alert at 100% → IAM policy action (Bedrock deny in staging)
Member accounts (each)
├── Per-workload budget (tag filter: workload = document-qa)
│ └── Alert at 90% → SNS → application owner
8.4 Consolidated Billing and Tiered Pricing
Under consolidated billing, Bedrock on-demand usage is aggregated at the organization level for discount tier purposes. This does not affect budget filter precision — each member account’s charges are still identifiable — but it means the management account’s total Bedrock budget will not equal the sum of member account budgets if cross-account volume discounts apply.
9. Budgets API: Terraform and boto3
9.1 Terraform: Bedrock Cost Budget with Actions
# SNS topic for budget notifications
resource "aws_sns_topic" "bedrock_budget_alerts" {
name = "bedrock-budget-alerts"
}
resource "aws_sns_topic_policy" "bedrock_budget_sns_policy" {
arn = aws_sns_topic.bedrock_budget_alerts.arn
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Sid = "AllowBudgetsPublish"
Effect = "Allow"
Principal = {
Service = "budgets.amazonaws.com"
}
Action = "SNS:Publish"
Resource = aws_sns_topic.bedrock_budget_alerts.arn
Condition = {
StringEquals = {
"aws:SourceAccount" = data.aws_caller_identity.current.account_id
}
}
}]
})
}
# Deny policy applied by Budget Action on breach
resource "aws_iam_policy" "bedrock_deny_on_breach" {
name = "BedrockDenyOnBudgetBreach"
description = "Attached automatically by AWS Budgets when Bedrock spend limit is exceeded"
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Sid = "DenyBedrockInferenceOnBudgetBreach"
Effect = "Deny"
Action = [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream",
"bedrock:Converse",
"bedrock:ConverseStream",
"bedrock:InvokeAgent"
]
Resource = "*"
}]
})
}
# IAM role for Budget Actions to assume
resource "aws_iam_role" "budgets_action_role" {
name = "AWSBudgetsActionsRole-Bedrock"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = {
Service = "budgets.amazonaws.com"
}
Action = "sts:AssumeRole"
}]
})
}
resource "aws_iam_role_policy_attachment" "budgets_action_managed" {
role = aws_iam_role.budgets_action_role.name
policy_arn = "arn:aws:iam::aws:policy/AWSBudgetsActionsRolePolicyForResourceAdministrationWithSSM"
}
# Core Bedrock cost budget
resource "aws_budgets_budget" "bedrock_monthly" {
name = "bedrock-monthly-prod"
budget_type = "COST"
limit_amount = "2000"
limit_unit = "USD"
time_unit = "MONTHLY"
cost_filter {
name = "Service"
values = ["Amazon Bedrock"]
}
# Alert 1: 80% forecasted → SNS
notification {
comparison_operator = "GREATER_THAN"
threshold = 80
threshold_type = "PERCENTAGE"
notification_type = "FORECASTED"
subscriber_sns_topic_arns = [aws_sns_topic.bedrock_budget_alerts.arn]
}
# Alert 2: 90% actual → SNS + email
notification {
comparison_operator = "GREATER_THAN"
threshold = 90
threshold_type = "PERCENTAGE"
notification_type = "ACTUAL"
subscriber_sns_topic_arns = [aws_sns_topic.bedrock_budget_alerts.arn]
subscriber_email_addresses = ["finops@company.com"]
}
# Alert 3: 100% actual — Budget Action fires here (see aws_budgets_budget_action)
notification {
comparison_operator = "GREATER_THAN"
threshold = 100
threshold_type = "PERCENTAGE"
notification_type = "ACTUAL"
subscriber_sns_topic_arns = [aws_sns_topic.bedrock_budget_alerts.arn]
}
}
# Budget Action: attach Bedrock deny policy when 100% threshold is hit
resource "aws_budgets_budget_action" "bedrock_deny_on_breach" {
budget_name = aws_budgets_budget.bedrock_monthly.name
action_type = "APPLY_IAM_POLICY"
approval_model = "AUTOMATIC"
notification_type = "ACTUAL"
execution_role_arn = aws_iam_role.budgets_action_role.arn
action_threshold {
action_threshold_type = "PERCENTAGE"
action_threshold_value = 100
}
definition {
iam_action_definition {
policy_arn = aws_iam_policy.bedrock_deny_on_breach.arn
roles = ["BedrockInferenceRole"] # role used by the application
}
}
subscriber {
address = aws_sns_topic.bedrock_budget_alerts.arn
subscription_type = "SNS"
}
}
9.2 Terraform: Token-Based Usage Budget
resource "aws_budgets_budget" "bedrock_tokens_claude_sonnet" {
name = "bedrock-claude-sonnet-input-tokens-monthly"
budget_type = "USAGE"
limit_amount = "500000000" # 500 million tokens
limit_unit = "Tokens"
time_unit = "MONTHLY"
cost_filter {
name = "UsageTypeGroup"
values = ["Bedrock Token"]
}
notification {
comparison_operator = "GREATER_THAN"
threshold = 80
threshold_type = "PERCENTAGE"
notification_type = "ACTUAL"
subscriber_sns_topic_arns = [aws_sns_topic.bedrock_budget_alerts.arn]
}
notification {
comparison_operator = "GREATER_THAN"
threshold = 100
threshold_type = "PERCENTAGE"
notification_type = "ACTUAL"
subscriber_sns_topic_arns = [aws_sns_topic.bedrock_budget_alerts.arn]
}
}
9.3 boto3: Programmatic Budget Creation
import boto3
budgets = boto3.client("budgets", region_name="us-east-1")
account_id = boto3.client("sts").get_caller_identity()["Account"]
def create_bedrock_cost_budget(
budget_name: str,
monthly_limit_usd: str,
sns_topic_arn: str,
notification_email: str,
) -> dict:
"""
Creates a monthly Bedrock cost budget with forecasted (80%) and
actual (90%, 100%) alert thresholds.
"""
return budgets.create_budget(
AccountId=account_id,
Budget={
"BudgetName": budget_name,
"BudgetType": "COST",
"TimeUnit": "MONTHLY",
"BudgetLimit": {
"Amount": monthly_limit_usd,
"Unit": "USD",
},
"CostFilters": {
"Service": ["Amazon Bedrock"]
},
"CostTypes": {
"IncludeTax": True,
"IncludeSubscription": True,
"UseBlended": False,
"IncludeRefund": False,
"IncludeCredit": False,
"IncludeUpfront": True,
"IncludeRecurring": True,
"IncludeOtherSubscription": True,
"IncludeSupport": False,
"IncludeDiscount": True,
"UseAmortized": False,
},
},
NotificationsWithSubscribers=[
{
"Notification": {
"NotificationType": "FORECASTED",
"ComparisonOperator": "GREATER_THAN",
"Threshold": 80.0,
"ThresholdType": "PERCENTAGE",
},
"Subscribers": [
{"SubscriptionType": "SNS", "Address": sns_topic_arn}
],
},
{
"Notification": {
"NotificationType": "ACTUAL",
"ComparisonOperator": "GREATER_THAN",
"Threshold": 90.0,
"ThresholdType": "PERCENTAGE",
},
"Subscribers": [
{"SubscriptionType": "SNS", "Address": sns_topic_arn},
{"SubscriptionType": "EMAIL", "Address": notification_email},
],
},
{
"Notification": {
"NotificationType": "ACTUAL",
"ComparisonOperator": "GREATER_THAN",
"Threshold": 100.0,
"ThresholdType": "PERCENTAGE",
},
"Subscribers": [
{"SubscriptionType": "SNS", "Address": sns_topic_arn}
],
},
],
)
def attach_budget_action(
budget_name: str,
deny_policy_arn: str,
execution_role_arn: str,
target_role_name: str,
) -> dict:
"""
Attaches an automatic IAM-deny Budget Action at 100% actual threshold.
"""
return budgets.create_budget_action(
AccountId=account_id,
BudgetName=budget_name,
NotificationType="ACTUAL",
ActionType="APPLY_IAM_POLICY",
ActionThreshold={
"ActionThresholdValue": 100.0,
"ActionThresholdType": "PERCENTAGE",
},
Definition={
"IamActionDefinition": {
"PolicyArn": deny_policy_arn,
"Roles": [target_role_name],
}
},
ExecutionRoleArn=execution_role_arn,
ApprovalModel="AUTOMATIC",
)
10. LiteLLM Integration with AWS Budgets
LiteLLM Proxy provides two internal budget mechanisms:
soft_budget: threshold that triggers email notifications but does not block requestsmax_budget: hard cap that rejects API calls once the limit is reached with anHTTP 429response
These are independent of AWS Budgets and are evaluated against LiteLLM’s internal spend tracker, not AWS billing data. There is no native AWS Budgets SNS subscription in LiteLLM as of mid-2026.
10.1 SNS → Lambda → LiteLLM Budget Trigger Pattern
The practical integration connects AWS Budgets SNS alerts to a Lambda function that updates LiteLLM’s per-team budget via its admin API or by writing to the LiteLLM database:
AWS Budgets threshold breach
→ SNS topic (bedrock-budget-alerts)
→ Lambda: litellm-budget-enforcer
→ LiteLLM Admin API: PATCH /team/{team_id}
{ "max_budget": 0 } # sets effective spend limit to zero
# or
{ "budget_duration": null } # disables the team's budget window
The Lambda function receives the SNS payload, extracts the budget name (which encodes the team identifier by convention), maps it to a LiteLLM team ID, and calls the LiteLLM proxy admin API to set max_budget = 0 for that team — effectively shutting down inference via LiteLLM for the team until manually reset.
import json
import os
import urllib.request
LITELLM_ADMIN_URL = os.environ["LITELLM_ADMIN_URL"]
LITELLM_API_KEY = os.environ["LITELLM_MASTER_KEY"]
# Convention: budget name format = "bedrock-{team_id}-monthly"
BUDGET_NAME_PREFIX = "bedrock-"
def lambda_handler(event, context):
for record in event["Records"]:
message = json.loads(record["Sns"]["Message"])
budget_name = message.get("budgetName", "")
if not budget_name.startswith(BUDGET_NAME_PREFIX):
continue
team_id = budget_name[len(BUDGET_NAME_PREFIX):].removesuffix("-monthly")
shutdown_team(team_id)
return {"statusCode": 200}
def shutdown_team(team_id: str):
payload = json.dumps({"team_id": team_id, "max_budget": 0}).encode()
req = urllib.request.Request(
f"{LITELLM_ADMIN_URL}/team/update",
data=payload,
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {LITELLM_API_KEY}",
},
method="PATCH",
)
with urllib.request.urlopen(req) as resp:
return json.loads(resp.read())
10.2 LiteLLM Native Soft Budget Alerts
LiteLLM’s built-in soft_budget feature sends email notifications (via SendGrid, Resend, or SMTP) when a team’s spend crosses the soft threshold. This is complementary to, not a replacement for, the AWS Budgets signal: the LiteLLM signal fires against LiteLLM’s internal cost estimate using model pricing tables; the AWS Budgets signal fires against actual AWS billing data. The two signals can diverge if LiteLLM’s pricing tables are stale or if Bedrock pricing tiers apply.
11. Budget vs. Cost Anomaly Detection
AWS Budgets and AWS Cost Anomaly Detection serve different governance roles and should be deployed together.
11.1 AWS Budgets: Proactive Threshold Enforcement
Budgets enforce a known limit. They require a pre-defined ceiling and fire when spend approaches or exceeds that ceiling. Their utility depends entirely on the quality of the limit you set.
- Best for: known workloads with predictable baseline spend, hard organizational spend limits, automated enforcement via Budget Actions
- Limitation: cannot detect unexpected patterns within budget — if a workload doubles spend but stays under the dollar ceiling, no alert fires
11.2 AWS Cost Anomaly Detection: Reactive Pattern Detection
Cost Anomaly Detection uses ML to model your historical spend pattern and alerts when actual spend deviates significantly from the expected pattern — without requiring a pre-defined threshold. The ML model adjusts as your baseline changes.
- Best for: detecting misconfigured workloads, runaway agents, forgotten test deployments, unexpected model routing changes
- Limitation: ML threshold is opaque; does not support automated enforcement actions; not suitable for hard caps
11.3 Complementary Deployment for Bedrock
AWS Cost Anomaly Detection monitor
Service = Amazon Bedrock
Alert threshold = $50 anomaly (absolute)
→ SNS → Slack: "Unusual Bedrock spend detected"
Role: catches unexpected patterns within budget
AWS Budgets (cost budget)
Service = Amazon Bedrock
Monthly limit = $2,000
Thresholds: 80% forecasted, 90% actual, 100% actual + Budget Action
Role: enforces the organizational ceiling, triggers IAM deny on breach
The two tools answer different questions:
- Budgets: “Are we on track to stay within our approved limit?”
- Anomaly Detection: “Is something spending money that shouldn’t be?”
For a Bedrock-heavy platform, deploy both. A runaway agent loop can spend $500 in an hour without crossing a $2,000 monthly budget — Anomaly Detection catches it. A legitimate high-demand month approaching the ceiling — Budgets catches it and can block it before overrun.
11.4 Decision Matrix
| Signal | Right tool |
|---|---|
| Monthly spend approaching limit | AWS Budgets (forecasted alert) |
| Spend already exceeded limit | AWS Budgets (actual alert + action) |
| Unexpected spike in the middle of the month | Cost Anomaly Detection |
| Spend from a new application you didn’t know existed | Cost Anomaly Detection |
| Per-team token quota enforcement | AWS Budgets (usage budget + Budget Action) |
| Multi-account consolidated ceiling | AWS Budgets (management account budget) |
| Unexplained increase in cache write charges | Cost Anomaly Detection |
| Finance requires hard block at approved limit | AWS Budgets + Budget Action |
Architecture Reference
┌──────────────────────────────────────────────────────────────────┐
│ Management Account │
│ │
│ AWS Budgets │
│ ├── Org Bedrock cost budget ($20K/mo) │
│ │ ├── 80% forecasted → SNS → FinOps Slack │
│ │ └── 100% actual → SCP action (org Bedrock deny) │
│ └── Per-team budget (linked acct filter) │
│ ├── 80% → SNS → team Slack │
│ └── 100% → IAM action in member account │
│ │
│ Cost Anomaly Detection │
│ └── Bedrock monitor → SNS → anomaly Slack channel │
└──────────────────────────────────────────────────────────────────┘
│ Budget alerts via SNS
▼
┌────────────────────────────────────┐
│ SNS Topic: bedrock-budget-alerts │
│ ├── Email → finops@company.com │
│ ├── Lambda → Slack webhook │
│ ├── Lambda → LiteLLM admin API │
│ │ (sets max_budget=0 for team) │
│ └── PagerDuty HTTPS endpoint │
└────────────────────────────────────┘
│ EventBridge (CloudTrail)
▼
┌──────────────────────────────────────────────────┐
│ EventBridge Rule: budget threshold events │
│ └── Lambda: update Parameter Store feature flag │
│ → Application reads flag → graceful degrade │
└──────────────────────────────────────────────────┘
Member Account (prod)
┌─────────────────────────────────────────────┐
│ Application IAM Role (BedrockInferenceRole)│
│ ← Deny policy attached by Budget Action │
│ on 100% threshold breach │
│ │
│ LiteLLM Proxy │
│ ← max_budget=0 set by Lambda on SNS alert │
└─────────────────────────────────────────────┘
Sources
- Creating a usage budget — AWS Cost Management docs
- Budget filters — AWS Cost Management docs
- Configuring budget actions — AWS Cost Management docs
- Configuring a budget action (procedure) — AWS Cost Management docs
- AWS Budgets events — Amazon EventBridge Reference
- Understanding your Amazon Bedrock Cost and Usage Report data — Amazon Bedrock docs
- How to Create AWS Budget Actions for Automatic Cost Control — OneUptime Blog, Feb 2026
- Team Soft Budget Alerts — LiteLLM docs
- Budget Manager — LiteLLM docs
- Mastering Your Generative AI Spend: Monitoring Amazon Bedrock with CloudWatch, Cost Explorer, and Budgets
- aws_budgets_budget_action — Terraform Registry
- AWS Budgets now supports Billing View for cross-account cost monitoring — AWS What’s New, Aug 2025
- AWS Cost Anomaly Detection: Basics and Quick Tutorial — Finout Blog