Tokenomics at scale: Track and cap Amazon Bedrock spend per IAM principal with CUR 2.0 and AWS Budgets

Generative AI spend is hard to attribute. Before an organization expands AI access, CFOs and CTOs usually want three answers: what do we spend per person or per team, can we cap it, and how much work does it take to get there. In our previous post, Tokenomics at Scale: How Jamf Built Real-Time Spend Enforcement for Amazon Bedrock , we explained a custom enforcement loop built on AWS IAM Identity Center , Amazon Athena over Amazon Bedrock model invocation logs , and AWS Lambda . This approach gives near-real-time control, but it requires code you then own and operate. This post shows how to get per-identity Amazon Bedrock cost visibility and enforceable spend limits using only AWS-native features, with no application code to write for the common case. The approach relies on three things: IAM principal attribution , which Amazon Bedrock records automatically; AWS Cost and Usage Reports (CUR) 2.0 or AWS Cost Explorer for reporting; and AWS Budgets with budget actions for enforcement. By the end, you will have per-identity cost reporting and an automatic guardrail that restricts Amazon Bedrock access when a threshold is crossed. Solution overview The solution has three parts: attribute, report, and enforce. Attribute. Amazon Bedrock captures the AWS Identity and Access Management (IAM) principal identity, the IAM user or role , for every inference request. This happens automatically, with no change to your Amazon Bedrock model inference calls. If several people share one role, you add per-user detail with session tags passed at role assumption time. If each person or application has its own role, principal tags on the role are enough. Report. Activate those tags as cost allocation tags, then read the data either in Cost Explorer for a console-only view, or in a CUR 2.0 data export for detailed line-item analysis and SQL queries. Enforce. Create an AWS Budget scoped to Amazon Bedrock and filtered to one identity or tag value, then attach a budget action that applies a Deny IAM policy when the threshold is crossed. The following sections show each part in more detail, alongside the implementation steps. Prerequisites To deploy this solution, you need: An AWS account with Amazon Bedrock model access enabled. Permissions to tag IAM principal , activate cost allocation tags , create data exports , and create budgets and budget actions. Amazon Bedrock accessed through IAM roles or IAM users. AWS Command Line Interface (AWS CLI) configured with appropriate credentials. A CUR 2.0 data export and an Amazon Simple Storage Service ( Amazon S3 ) bucket to receive it. (optional, for detailed line-item analysis) . Amazon Athena. (optional, for querying the export) . AWS Billing Console access is managed separately from most IAM permissions. Confirm you have it before starting. Walkthrough Before configuring anything, check what you already have. Amazon Bedrock records caller identity for every inference request automatically. Open Cost Explorer, filter Service to Amazon Bedrock, and group by the available identity or tag dimension. For accounts where each application or person already uses a distinct IAM role, this may be all the visibility you need. To configure additional visibility: Step 1 gives you identity-level visibility. Steps 2 through 4 add tag dimensions and detailed reporting. Step 5 adds enforcement. Step 1: Decide how identity maps to your users How you tag depends on how your IAM principals are organized. One role per person or per application. Attach principal tags directly to each IAM role or user. These are static and apply to every request from that principal. Use the IAM console, or the AWS CLI: aws iam tag-role \ --role-name BedrockDeveloperRole-alice \ --tags Key=user,Value=alice@example.com Key=team,Value=platform Key=CostCenter,Value=CC-1001 A shared role used by several people, or a gateway. Principal tags cannot distinguish users on a shared role, because every session carries the same tags. Use session tags instead, passed when the role is assumed. Session tags are dynamic and can vary per session. If a session tag and a principal tag share a key, the session tag wins for that session. The role’s trust policy must allow sts:TagSession . Session tags can be passed three ways: sts:AssumeRole with --tags , for a gateway assuming a role per user or tenant. AssumeRoleWithWebIdentity , with tags in the https://aws.amazon.com/tags claim of the OpenID Connect (OIDC) ID token (this is a claim name, not a URL you browse to). AssumeRoleWithSAML , by mapping PrincipalTag:* attributes in the identity provider’s Security Assertion Markup Language (SAML) assertion. If your organization already captures a claim like saml:sub for other purposes, that alone does not make it available here. Your identity provider must separately map that attribute to a PrincipalTag:* SAML attribute statement, and the role’s trust policy must allow sts:TagSession , before it flows through as a session tag. The two integrations draw from the same SAML assertion but are configured independently. Common tag keys are user, team, Department, CostCenter, and Environment. You can apply up to 50 principal or session tags per IAM user or role. Figure 1: Attribution with principal tags compared to session tags Step 2: Activate cost allocation tags Tags do not appear in billing data until you activate them. Open the AWS Billing and Cost Management Console . Choose Cost allocation tags . Filter by type IAM principal . Select your tag keys and choose Activate . In an AWS Organization , activate IAM principal cost allocation tags in the management account (payer). Member accounts cannot activate them independently. Two things to expect: A tag key only appears in this list after the principal has made at least one Amazon Bedrock call, so make a test call first if the list looks empty. It might take up to 24 hours for a newly applied tag key to appear for activation, then up to another 24 hours after you activate it before it begins populating billing data. Activation does not apply retroactively by default, so activate tags before you need the data. Step 3: Create a CUR 2.0 data export that includes caller identity Skip this step if Cost Explorer is enough for your reporting. In the Billing and Cost Management console, choose Data Exports . Choose Create and create a CUR 2.0 (Standard) export. Under Additional export content , select Include caller identity (IAM principal) allocation data . Under Time granularity , select Hourly. Under Report data integration , select Amazon Athena . This sets the file format to Parquet and, importantly, delivers a setup script to your S3 bucket alongside the export data. Choose the destination Amazon S3 bucket. Run the delivered setup script (or the Glue crawler/DDL it defines) once. This is what actually creates the Glue Data Catalog table you’ll query in Step 4. The preceding console flow does not create it for you automatically. If you already have a CUR 2.0 export created before enabling identity attribution, it will not include identity data retroactively. Create a new export with the caller identity option selected. In the export, principal and session tags appear as columns prefixed iamPrincipal/ , and resource tags as resourceTags/ . For example, a tag key team appears as iamPrincipal/team . AWS publishes a ready-made query set for this exact pattern in aws-samples/sample-cur-iam-principal-bedrock-tracking . Step 4: Read the data The following diagram compares the two ways to read the data: a console-only path through Cost Explorer, and a SQL path over the CUR 2.0 export with Amazon Athena. Figure 2: Reporting with Cost Explorer compared to CUR 2.0 and Amazon Athena Console path, no custom code. Cost Explorer, filtered to Amazon Bedrock and grouped by your tag key, gives per-team or per-user spend as a chart and table. This covers most recurring reporting needs and requires no query authoring. SQL path, low code. Point Amazon Athena at the CUR 2.0