Exam Room · Advanced Architecture

Cost Visibility and Allocation Across an Organisation

February 22, 2027 · 41 min read

Advanced Cloud Architecture · part of The Exam Room

The situation

We run an AWS Organization with sixty-odd member accounts under one management account: a couple of accounts per product line for prod and non-prod, a shared-services account, a security account, a handful of sandboxes, and the usual sprawl that accumulates when every team gets its own account. Consolidated billing is on, so one invoice lands each month. Last month it was AUD$480,000, up from AUD$390,000, and the first question in the finance review was “up because of what?”

Nobody could answer cleanly. The bill rolls up by account and by service, but not by the things the business cares about: which product line, which team, which environment, which customer. Finance wants a showback report each month that splits the total by product line so they can talk about margin. Engineering leads want an alert when a single team’s spend crosses its monthly allocation, and an earlier alert when a runaway batch job starts burning money at 3am. The CFO wants the month-on-month jump explained without a two-day spreadsheet exercise.

None of this is available until the spend carries the dimensions we want to slice it by, and until those dimensions land somewhere we can query. Right now maybe a third of resources are tagged, the tags that exist disagree on spelling (team, Team, owner-team), and the one report anyone trusts is a hand-built spreadsheet that the platform lead updates on the last Friday of the month.

What actually matters

The whole problem stands on attribution accuracy, and attribution accuracy is a tag-hygiene problem before it is a tooling problem. Every cost tool downstream (Cost Explorer, the Cost and Usage Report, Budgets scoped by tag) can only group spend by dimensions that are actually present on the resources. If half the fleet is untagged, the prettiest chargeback pipeline in the world produces a large “unallocated” bucket and a finance team that stops trusting the numbers. So the first thing worth thinking about is not which report to build; it is how tags get applied consistently and how we stop untagged resources from being created in the first place. Governance comes before reporting, or the reporting is fiction.

The second property is the split between showback and chargeback, because it changes how precise the numbers have to be. Showback means each team sees what it spent, for awareness, with no money changing hands; a bit of unallocated spend is survivable and nobody disputes a line item. Chargeback means the spend is actually billed back to a cost centre, journal entries get raised, and a team that thinks it has been over-charged will litigate every dollar. Chargeback needs near-total tag coverage, a defensible rule for splitting shared costs (the NAT gateways, the shared observability platform, the support charge), and an audit trail. Deciding which one finance actually needs sets the accuracy bar for everything else.

The third is timeliness, and it splits in two. Budget tracking against a monthly allocation is a slow signal; a daily refresh is fine, because the decision it drives (“this team is tracking 15% over, have a conversation”) is a slow decision. Catching a runaway job is a fast signal; by the time a monthly budget notices, the job has run for days. Those are different mechanisms with different data latencies, and trying to make one tool do both jobs well is where people get frustrated. Cost data is inherently laggy (usage records land in the billing pipeline hours after the usage), so “real-time cost alerting” has a floor no tool can go below; the honest question is how close to the floor each mechanism gets.

The fourth is finding the savings, which is a different question from attributing the spend. Attribution tells you where the money went; optimisation tells you where it did not need to go. Rightsizing recommendations, idle-resource findings, and commitment-purchase advice (Savings Plans and Reserved Instances) are their own toolset, and at org scale the interesting wrinkle is that commitments purchased in one account get shared across the whole organisation by default, which changes the math on who should buy them and how the discount gets attributed back.

What we’ll filter on

  1. What question does it answer? Attribution, alerting, anomaly-catching, or optimisation are different jobs.
  2. Granularity: can it slice by tag, by account, by Cost Category, by service, by resource, by the hour?
  3. Latency: how fresh is the data, and how fast does the signal fire?
  4. Automation: does it just notify, or can it take an action (stop the resource, apply an SCP, block the launch)?
  5. Org-scope: does it work across the whole Organization from the management or a delegated account, or per-account only?
  6. Effort to stand up: a checkbox, a rule set, or a data pipeline you own.

The landscape

Consolidated billing. The foundation. With all member accounts in one Organization, the management account receives a single bill and, more usefully, aggregates usage across accounts so that tiered pricing and free-tier limits apply to the combined total, and so that Savings Plans and RIs float across accounts. It answers “what did the whole org cost” and provides the raw material every other tool reads. It does not, on its own, tell you which team spent what beyond the account boundary.

Cost allocation tags. The dimension system. Two kinds. AWS-generated tags (prefixed aws:, e.g. aws:createdBy) are applied automatically but limited. User-defined tags are the ones you put on resources (team, product, environment, cost-centre). A tag does nothing for billing until you activate it in the Billing console’s Cost Allocation Tags page, and here is the trap worth burning into memory: activation is not retroactive and there is a lag. Once activated, a tag only shows up as a billing dimension for usage recorded from roughly the next day onward; spend already booked stays unallocated against that tag. Activate the tags you care about on day one, not the month you decide to build the report.

Cost Categories. Rule-based grouping that sits above tags and accounts. You define a category (say, Product Line) with rules that map spend into buckets: “accounts 111 and 222, or anything tagged product=greenbox, → Greenbox”; “these three accounts → Platform”; everything else → a default bucket. Categories can reference tags, accounts, other categories, and charge types, and they apply retroactively across up to the past twelve months when you create them, which is the opposite of tag activation and enormously handy. They give you a stable business dimension that survives messy underlying tags, and they show up in Cost Explorer, Budgets, and the Cost and Usage Report.

AWS Cost Explorer. The interactive analysis surface. Filter and group the last thirteen months (up to thirty-eight months of history is available) by service, account, tag, Cost Category, usage type, and more, with daily or monthly granularity and an hourly/resource-level mode you opt into for extra cost. It has forecasting, RI and Savings Plans utilisation and coverage reports, and rightsizing recommendations. It answers “why did this move” and “where is the spend concentrated” fast, in a console, with no pipeline to build. Its limits are the flip side: it is not a data warehouse, the API has a per-request cost, and you cannot join it against your own business data (customer IDs, contract values) the way a real chargeback model needs.

The Cost and Usage Report (CUR). The source of truth for anyone building their own reporting. The CUR (now delivered as CUR 2.0 through Data Exports) drops line-item-level billing detail (one row per resource per hour per line item, with every tag and Cost Category as a column) into an S3 bucket, refreshed multiple times a day. You point Athena at it, or load it into Redshift, or visualise it in QuickSight, and now you can write arbitrary SQL: spend by product line joined to your contract table, blended vs unblended vs amortised cost, split shared costs by a rule you define. This is how real chargeback gets built. The cost is that you own the pipeline: the Athena table, the partition maintenance, the QuickSight dashboards, the SQL.

AWS Budgets. The tracking-and-alerting tool. Create a budget (cost, usage, RI/SP utilisation, or coverage) scoped by account, service, tag, or Cost Category, set a monthly (or quarterly, or annual) amount, and get alerted at thresholds of actual or forecast spend. Budgets refresh up to three times a day. The part people underuse is budget actions: when a threshold is crossed, a budget can apply an IAM or SCP policy, stop EC2 or RDS instances, or target a Systems Manager action, either automatically or after an approval. That turns a budget from a notification into a control.

AWS Cost Anomaly Detection. The runaway-job catcher. It builds an ML model of each monitor’s normal spend pattern (per service, per account, per Cost Category, or per tag) and alerts when actual spend deviates beyond a threshold you set, with a root-cause breakdown of what drove the anomaly. It is free, it catches the “someone left a p5 instance running” or “a misconfigured job is scanning all of S3” class of surprise that a fixed budget threshold misses, and it is the closest thing to a fast, unattended spike alarm. It cannot take an action; it notifies (SNS, email, chatbot).

AWS Compute Optimizer. Rightsizing recommendations from actual utilisation. It analyses CloudWatch metrics for EC2, Auto Scaling groups, EBS, Lambda, ECS on Fargate, and RDS, and recommends a better size or configuration, with projected savings and the performance risk of each option. Enable it for the whole org from the management or a delegated admin account and it covers every member account. It answers “what is over-provisioned” with evidence.

AWS Trusted Advisor. The broad checklist, including cost-optimisation checks: idle load balancers, underutilised EBS volumes, idle RDS instances, low-utilisation EC2, unassociated Elastic IPs, RI and Savings Plans purchase recommendations. Full checks need Business or Enterprise Support. It answers “what is obviously wasteful” across categories, and at org level its findings aggregate in the management account.

Savings Plans and Reserved Instances recommendations. The commitment-purchase advice, surfaced in Cost Explorer and Trusted Advisor. Based on historical usage they recommend how much hourly commitment to buy and at what term and payment option. The org-scale subtlety is sharing: by default, a Savings Plan or RI bought in any account applies its discount across every account in the Organization, cheapest-eligible-usage-first. You can turn RI/SP discount sharing off per account from the management account. This is central to how commitments get attributed in a chargeback model.

Tag governance: Tag Policies and SCPs. The enforcement layer, from AWS Organizations. Tag Policies define the allowed keys and values (correct case for Team, an allowed set of Environment values) and report non-compliant resources; they standardise and detect, but on their own they do not block a non-compliant resource from being created. Service Control Policies are the hard stop: an SCP with a condition like aws:RequestTag/cost-centre Null: true denies the create call outright when the mandatory tag is absent, so an untagged resource never gets made. The two together (Tag Policies for the shape, an SCP for the mandate) are what make tags reliable enough to bill on.

Evaluation

Side by side

Tool Question it answers Granularity Latency Acts or notifies Best for
Consolidated billing What did the whole org cost Account, service Monthly bill / daily usage Neither The foundation everything reads
Cost allocation tags Which dimension owns this spend Per-tag Next-day after activation Neither The dimensions you slice by
Cost Categories Which business bucket owns this Rule-based, retroactive Applies to past 12 mo Neither Stable product/team dimension over messy tags
Cost Explorer Why did spend move, where is it Service/account/tag/hourly Up to ~24h Neither Fast interactive analysis, no pipeline
Cost and Usage Report Anything, joined to your data Resource, hourly line items Multiple times/day Neither Custom showback and chargeback
Budgets (+ actions) Are we over an allocation Account/service/tag/category Up to 3x/day Can act (SCP, stop, SSM) Guardrails against a monthly overrun
Cost Anomaly Detection Did spend spike unexpectedly Service/account/tag/category ~Daily, ML-based Notifies Catching runaway jobs and surprises
Compute Optimizer What is over-provisioned Per-resource Continuous analysis Notifies (recommends) Rightsizing with utilisation evidence
Trusted Advisor What is obviously wasteful Per-check Refreshed periodically Notifies (recommends) Broad waste sweep + commitment advice
Tag Policies + SCP Are resources correctly tagged Org-wide At create time (SCP) / on scan SCP blocks, TP detects Making tags reliable enough to bill on

How the pieces stack

1. Governance make tags reliable Tag Policies standardise + detect SCP: deny untagged create hard stop at launch 2. Dimensions give spend meaning Cost allocation tags activate early, next-day lag Cost Categories rules, retroactive 12 mo 3. Data where you query it Consolidated billing one bill, shared discounts Cost + Usage Report S3 → Athena / QuickSight Cost Explorer interactive, no pipeline 4. Action alert + optimise Budgets + budget actions Anomaly Detection ML spike alerts Compute Optimizer rightsizing Trusted Advisor waste + commitments
Four layers. Each one is only as useful as the layer beneath it: the reports and alerts at the top are fiction if the tags at the bottom are not enforced.

The solution

Start with a tag strategy, then enforce it. Before any report, agree a small, mandatory tag set and stop debating it: cost-centre, product, environment, team. Keep it small; a twelve-tag standard nobody can remember gets ignored. Then make it real in two moves. A Tag Policy published from the Organizations management account declares the allowed keys and the allowed values (correct capitalisation for Environment, a fixed enum of prod/staging/dev/sandbox) and flags non-compliant resources across every account. A Service Control Policy makes the mandatory ones unavoidable: a Deny on ec2:RunInstances, rds:CreateDBInstance, and the other create actions when aws:RequestTag/cost-centre is null means a resource without a cost centre never gets created. Then activate those tags as cost allocation tags in the billing console on the same day, because activation is not retroactive: a tag you activate in March starts allocating spend in March, and February’s spend stays unallocated against it forever. The order is deliberate: enforce, activate, then wait a billing cycle before you trust the reports, because the first cycle is when the untagged backlog is still washing through.

Cost Categories give you a business dimension that outlives the tag mess. Even with an SCP in place, you inherit a backlog of half-tagged resources and a set of accounts that predate the standard. A Cost Category called Product Line papers over that with rules evaluated in order: an account-list rule for the accounts that are wholly one product, a tag rule (product=greenbox → Greenbox) for shared accounts, and a default bucket for the remainder. Because Cost Categories apply retroactively across the past twelve months, you get a coherent product view of historical spend the day you define them, which is exactly what the CFO’s “why did last month jump” question needs and what raw tags can never give you retroactively. Split charges (a rule that proportionally allocates a shared account’s cost across the other categories) handle the shared-services and support charges without hand math.

The CUR-plus-Athena pipeline is how real chargeback gets built. Cost Explorer answers most showback questions in the console, and for pure awareness that is often enough. Chargeback, where finance raises journal entries, needs more: line-item detail, your own business data joined in, and a defensible rule for shared costs. Enable the Cost and Usage Report (CUR 2.0 via Data Exports) into an S3 bucket in a dedicated billing account, with resource IDs and hourly granularity and every tag and Cost Category included as a column. Point Athena at it (AWS supplies the table definition and a Glue crawler pattern), partition by billing period, and now chargeback is SQL: sum line_item_unblended_cost grouped by the cost-centre tag column, join to a contracts table by customer, allocate the shared-platform account’s total across product lines by their share of compute spend. QuickSight sits on top for the finance-facing dashboard, refreshed daily. Use amortised cost, not unblended, when you present it, so that an up-front Savings Plan purchase spreads across the months it covers instead of spiking the month it was bought; unblended will make one team look wildly over budget the month a three-year RI lands.

Budgets and Anomaly Detection are different alarms for different failures. A Budget scoped to a team tag or a Cost Category, set to the monthly allocation with alerts at 80% actual and 100% forecast, is the guardrail against a slow overrun: it answers “is this team on track to blow its number.” Wire a budget action on the non-prod sandboxes so that at 100% it applies a restrictive SCP or stops the tagged instances; that turns a warning into a control for the accounts where a hard stop is acceptable. But a fixed budget is blind to the fast failure: a job that starts scanning all of S3 at 3am produces a spike that a monthly budget only notices near month-end, when the damage is done. That is Cost Anomaly Detection’s job. Point a monitor at each major service or Cost Category; its model learns the normal daily shape and alerts within about a day when the spend deviates, with a root-cause breakdown naming the account and usage type. Run both: Budgets for the allocation you set in advance, Anomaly Detection for the surprise you could not have set a threshold for. Neither is real-time (cost data lags usage by hours no matter what), so treat “within a day” as the floor, not a failing.

RI and Savings Plans sharing changes who should buy, and how the discount is attributed. With consolidated billing, a Savings Plan or Reserved Instance purchased in any account has its discount applied across the whole Organization by default, cheapest-eligible-usage-first each hour. That is usually what you want: buy commitments centrally against the org’s aggregate baseline (Cost Explorer’s Savings Plans recommendation computes that baseline for you) and let the discount float to wherever the matching usage runs, which maximises utilisation. The complication is attribution. If the platform team buys a big Savings Plan and its discount floats to a product team’s account, the product team’s net cost drops without them doing anything, and the platform account shows the commitment charge with no matching usage. For showback that is a footnote. For chargeback it needs a rule, and there are two clean ones: either buy commitments centrally and re-allocate the discount benefit back to each account by its share of covered usage (computable from the CUR’s Savings Plans columns), or turn RI/SP discount sharing off for specific accounts from the management account so a team that buys its own commitment keeps its own benefit. Decide this before finance starts asking why the platform account’s bill looks strange.

Worked example

The AUD$480k month lands. Because the CUR has been flowing into S3 for a year and the Product Line Cost Category was defined months ago (so it covers history), the platform lead does not open a spreadsheet. In Cost Explorer, group by Product Line Cost Category, compare month over month: three product lines are flat, one (Greenbox) is up AUD$85k. Drill into Greenbox by service: EC2-Other and data transfer, not compute. Group by usage type: NAT gateway data-processing charges, tripled.

That points at a specific behaviour, not a mystery. Cost Anomaly Detection had in fact fired eleven days earlier, with a root cause naming the Greenbox prod account and NAT gateway usage; the alert had gone to a team channel and been missed. The cause turned out to be a new service pulling large objects from S3 across the public path through the NAT gateway instead of via a Gateway VPC Endpoint. A Gateway Endpoint for S3 is free and routes that traffic off the NAT gateway entirely; adding it drops the charge back to baseline.

Three things made the hour possible: the CUR gave line-item detail to drill into, the Cost Category gave a product dimension over the past year without retroactive tagging, and Anomaly Detection had already caught it (the failure was routing the alert to a channel nobody owned, not the tooling). The fix for the process is a Budget action on the anomaly-alert path and an owner for the channel. The fix for the bill is one VPC endpoint. Finance got its answer the same afternoon, and the showback report now carries a Product Line split every team recognises.

What’s worth remembering

  1. Attribution is a tag-hygiene problem before it is a tooling problem. Every downstream report can only group by dimensions that are actually on the resources, so governance (Tag Policies plus an SCP that denies untagged creates) comes before reporting or the reporting is fiction.
  2. Cost allocation tags are not retroactive and lag by about a day after activation. Activate the tags you care about on day one; spend booked before activation stays unallocated against that tag forever.
  3. Cost Categories are retroactive up to twelve months, which is the opposite of tags and exactly what “why did last month jump” needs. Use them for a stable business dimension (product line, cost centre) that survives messy underlying tags.
  4. Cost Explorer answers showback in the console with no pipeline; the CUR into S3 with Athena and QuickSight is how you build chargeback that joins spend to your own business data.
  5. Budgets catch the slow overrun you can set a threshold for; Cost Anomaly Detection catches the fast spike you cannot. Run both, and remember neither beats the inherent hours-long lag of cost data.

These posts are LLM-aided. Backbone, original writing, and structure by Craig. Research and editing by Craig + LLM. Proof-reading by Craig.