The Shared-Model Cost Problem Nobody Warns You About
You rolled out Amazon Bedrock across your org. HR uses it for policy Q&A. Accounting feeds it financial PDFs. IT asks it to debug CloudFormation stacks. Everyone's happy — until the bill arrives.
One line item. One foundation model. Three departments. Finance has no way to charge back, set budgets, or catch the team burning through tokens at 3 AM.
This is the classic shared-tenant cost attribution trap. Most teams solve it the wrong way — spinning up separate IAM roles per department and passing user identities through to AWS. That works, but it drags session management and per-user identity plumbing into your app layer.
There's a cleaner path: Amazon Bedrock application inference profiles. They're tagged wrappers around a foundation model that let you attribute cost by workload, not by caller identity. Same foundation model, same per-token price, but now each department's usage lands on its own line in AWS Cost Explorer.
If you're tracking broader cloud AI economics, the same architectural thinking applies to hardware accelerators — see our deep dive on how Microsoft's Maia 200 reshapes inference cost curves.
Here's the mental model: your application authenticates users, looks up their department, and routes the Bedrock call through the matching inference profile ARN. Bedrock records usage against that profile's Team tag. Cost Explorer groups by tag. Done.

Build It: Profiles, Tags, and a Python Router
Step 1 — Create one inference profile per department
In the Bedrock console: Inference profiles → Application tab → Create inference profile. Point each one at the same foundation model (e.g., Anthropic Claude), but give it a unique Team tag:
| Profile name | Model | Tag key | Tag value |
|---|---|---|---|
| HR | Claude (shared) | Team | HR |
| Accounting | Claude (shared) | Team | Accounting |
| IT | Claude (shared) | Team | IT |
Status flips to Active once created. For dozens of teams, skip the console and use the AWS::Bedrock::ApplicationInferenceProfile CloudFormation resource.
Step 2 — Activate the cost allocation tag
Tags don't show up in Cost Explorer until you activate them. Go to Billing and Cost Management → Cost allocation tags, search Team, select it, hit Activate.
Two gotchas that bite everyone:
- Case-sensitive.
Team≠team. - 24–48 hour propagation delay before tagged costs appear.
In AWS Organizations setups, activate in the management (payer) account so member-account usage consolidates.
Step 3 — Route invocations through the profile ARN
The API call doesn't change. You just swap modelId from the foundation model ID to the inference profile ARN:
# Route a Bedrock invocation to the correct department's inference profile.
# The profile ARN is passed as modelId — the API shape is identical to a direct model call.
import boto3
bedrock = boto3.client("bedrock-runtime", region_name="us-east-1")
# Map each department to its tagged inference profile ARN.
# Replace 111122223333 with your AWS account ID.
DEPARTMENT_PROFILES = {
"HR": "arn:aws:bedrock:us-east-1:111122223333:application-inference-profile/hr-profile-id",
"Accounting": "arn:aws:bedrock:us-east-1:111122223333:application-inference-profile/acct-profile-id",
"IT": "arn:aws:bedrock:us-east-1:111122223333:application-inference-profile/it-profile-id",
}
def invoke_for_department(department: str, prompt: str) -> str:
"""Invoke Bedrock via the department's inference profile for cost attribution."""
if department not in DEPARTMENT_PROFILES:
raise ValueError(f"Unknown department: {department}")
response = bedrock.invoke_model(
modelId=DEPARTMENT_PROFILES[department], # <-- the only thing that changes
body={"anthropic_version": "bedrock-2023-05-31",
"max_tokens": 512,
"messages": [{"role": "user", "content": prompt}]},
)
return response["body"].read().decode("utf-8")
# Example: HR asks a policy question
print(invoke_for_department("HR", "Summarize the parental leave policy."))
Step 4 — Grant the app role permission on profiles and the model
A single IAM role serves all departments. The policy needs both the profile ARN and the underlying foundation model ARN — invoking through a profile requires permissions on both:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream"
],
"Resource": [
"arn:aws:bedrock:us-east-1:111122223333:application-inference-profile/*",
"arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-*"
]
}
]
}
For production, replace the wildcard * with explicit profile ARNs — otherwise any future profile inherits invoke permissions automatically.
Step 5 — Read the breakdown in Cost Explorer
Cost Explorer → Group by → Tag → Team, set granularity to Daily or Monthly, and pick a date range after your invocations. You'll see HR, Accounting, and IT as separate colored segments with exact dollar amounts in the table below.
![]()
Where This Approach Breaks Down
Inference profiles are elegant, but they're not a silver bullet. Know the edges before you ship:
1. Tag propagation lag is real. 24–48 hours between invocation and cost visibility. If you need real-time per-team spend, this isn't your tool — pair it with CloudWatch token metrics for near-real-time signals.
2. Tags are a soft boundary, not a security boundary. A bug in your routing logic can silently attribute HR's traffic to IT's profile. Nothing in Bedrock stops that. Your routing code must be tested as carefully as an auth check.
3. Case sensitivity will burn you. Team vs team vs TEAM are three different tags in AWS's eyes. Standardize on one casing in a shared constants file.
4. Deleting a profile breaks live apps instantly. The ARN changes on recreation, so any hardcoded reference dies. Treat profile ARNs like database connection strings — config, not code.
5. Cost attribution ≠ cost control. Profiles tell you who spent what. They don't cap it. Layer on AWS Budgets for per-team alerts and Cost Anomaly Detection for the "why is IT burning 10x today" moments.
Where to go next
Once per-team attribution is working, the natural extensions are:
- AWS Budgets — set a hard monthly ceiling per
Teamtag value and alert at 80%. - Cost Anomaly Detection — let AWS learn each team's baseline and page you on outliers.
- CloudWatch token metrics — per-profile input/output token counts for capacity planning.
- Knowledge Bases (RAG) — reference the same tagged profile ARN so RAG retrieval costs attribute to the same team, not just direct invocations.
If you're building out an AI platform on top of Bedrock, the same cost-discipline mindset shows up at the silicon layer too — see our analysis of NVIDIA's IGX Thor and edge AI cost tradeoffs for how hardware choices ripple into your bill.

The Takeaway
If multiple teams share one Bedrock foundation model, you have three options:
- Do nothing — eat the single line item and argue about it monthly.
- Per-IAM-role attribution — accurate but requires per-user session plumbing.
- Application inference profiles — same per-token price, tag-based attribution, minimal code change.
Option 3 wins for most teams. The setup is ~30 minutes of console work plus a routing change in your app. The payoff is a Cost Explorer view where every department sees its own number — and finance stops sending passive-aggressive Slack messages.
Start with one department. Prove the tag flows through to Cost Explorer. Then scale with CloudFormation and per-team budgets.
Source: This walkthrough is based on the AWS Architecture Blog post on tracking generative AI costs with Amazon Bedrock inference profiles — read the original here.