Business Challenge
The previous post was about what logging costs. This one is about the question that follows every cost conversation eventually: whose is it?
A platform team is asked to report spend by business unit. They have a tagging standard, it is enforced by an SCP on resource creation, and a dashboard says coverage is 94%. The report still does not reconcile, the gap is much larger than 6%, and the reflex is to push tagging coverage higher — which will not close it, because the gap is not one thing.
There are three distinct reasons a dollar is unallocated, and they are not variations of each other. One is fixable retroactively, one is permanently lost, and one was never a tagging problem to begin with. Telling them apart is most of the work.
A tag on a resource is not a cost allocation tag until it is activated in the Billing console, and AWS-generated and user-defined tags must each be activated separately. Teams routinely tag for months before anyone activates the key, and the cost data for those months carries no tag values.
This one is recoverable. A management account user can request a backfill of up to twelve months, which retroactively applies the current activation status across that window. It is the only one of the three that gives you history back.
FixBackfill, once. You may only submit one request every 24 hours, and not at all while one is running.
Backfill looks like it should fix this too, and it does not. AWS is unambiguous: “the resource tag must be historically assigned to the AWS resource for the backfilled cost data to be available.” Backfill changes an activation status retroactively; it cannot invent a value that was never on the resource.
AWS's own example makes the boundary concrete. A tag applied in June and activated in November, backfilled from January, produces tag values from June to December — and January to May stay empty, because the tag was not on the resource then.
FixNone retroactively. Tag now so that this month is recoverable later, and report the historical gap as a gap.
The largest share of the gap is usually here, and no amount of tagging touches it. A NAT gateway serves eleven teams. A transit gateway serves the estate. Enterprise Support is one line for the organisation. AWS names the category precisely when describing what split charge rules are for: costs “that aren't directly attributed to a single owner”, such as “data transfer costs, enterprise support, and operating costs”.
A tag on the NAT gateway would not help. It has one owner in the tag and eleven in reality, and the honest answer is an allocation rule rather than a label.
FixCost Categories with split charge rules — and read the reporting caveat below before building on them.
Architecture
The three causes map onto three different mechanisms, and the useful discipline is refusing to let one tool be the answer to all of them.
The unallocated bucket is a feature, not a failure
One property makes an honest report possible at all: the cost allocation report includes both tagged and untagged resources, and at the end of the billing cycle its total reconciles with the Bills page. The residue is always visible and always adds up.
That is worth defending against the instinct to hide it. A report that shows 94% allocated and 6% unallocated is more useful to a finance team than one that quietly spreads the 6% around, because the first can be argued with. Show the bucket, name what is in it, and shrink it deliberately.
Containers are the case where tagging genuinely cannot reach
An EC2 instance running forty pods from six teams has one set of tags. Split cost allocation data
exists for exactly this: it generates container-level costs by taking the amortized cost of the
instance and the percentage of CPU and memory resources consumed by the containers that ran on
it, and for EKS it creates aws:eks: tags — cluster name,
namespace, node, deployment, workload name and type — enabled for cost allocation by default.
Two details decide whether the result is trustworthy. aws:eks:workload-type
is populated only when exactly one workload manages the pod and it is a built-in type, and
aws:eks:deployment only for ReplicaSet. Pods
outside those shapes are still costed and still less attributable, which is a smaller version of the
same unallocated bucket one layer down.
Split cost allocation data adds two usage records per task or pod per hour. AWS's own worked example — 1,000 pods with a lifetime under an hour — is 48,000 new records a day, and 72,000 where accelerators are involved, because those add a third record. The previous post was about what it costs to ingest and keep data; this is a feature that materially enlarges the Cost and Usage Report you are ingesting and querying. Worth switching on, worth sizing first.
Why This Architecture Holds Up
Split charge rules are the right shape for shared cost
The model is small and sound. A source is the pool of shared cost, the targets are the values it is split across, and the allocation method is one of Proportional, weighting by each target's own cost, Fixed, by a percentage you set, or Even split. Ten rules per cost category, and a value used as a source cannot also be a target, which prevents circular allocation by construction.
There is a sequencing requirement that is easy to miss and breaks the result silently: cost category rules evaluate top-down, so AWS recommends putting the values holding shared costs at the top of the rule list. Categorise the shared platform before the business units, or the platform's costs get absorbed into whichever unit matched first and there is nothing left to split.
AWS states it plainly: “Split charge rules and the total allocated costs are only presented on the cost categories details page. These costs do not appear and don't impact your AWS Cost and Usage Reports, Cost Explorer, and other AWS Cost Management tools.” The allocation you build is visible on one console page and in a CSV you download from it. Every dashboard, chargeback pipeline and QuickSight report reading CUR or Cost Explorer will show the unsplit figures.
What that means in practice
It does not make split charge rules useless — it makes them a reporting mechanism rather than a data-pipeline one. If the deliverable is a monthly shared-cost statement that a finance team reads and signs off, the details page and its CSV are sufficient and the rules are the shortest path to a defensible number.
If the deliverable is a live chargeback dashboard, they are not sufficient, and the allocation has to be re-implemented downstream against CUR — where you own the arithmetic and the method is whatever you write. Deciding which of those two you are building, before configuring anything, is the decision this whole section exists to force.
Key Architecture Decisions
| Decision | Choice | Reasoning |
|---|---|---|
| Tags activated late | Backfill, up to twelve months | The only mechanism that returns history. One request per 24 hours, and none while another is running. |
| Resources never tagged | Accept the gap and report it | Backfill applies an activation status, not a tag value. AWS requires the tag to have been historically assigned. |
| Shared infrastructure | Cost Categories with split charge rules | A NAT gateway has one owner in a tag and many in reality. An allocation rule is the honest representation. |
| Rule ordering | Shared-cost values at the top | Rules evaluate top-down. Categorise the shared platform first or there is nothing left to split. |
| Where the number is consumed | Decide before configuring | Split charge results never reach CUR or Cost Explorer. A signed monthly statement is fine; a live dashboard is not. |
| Containers | Split cost allocation data, sized first | It is the only way to attribute shared compute, and it adds tens of thousands of CUR records a day. |
Two operational details worth knowing before you promise a date
Nothing here is immediate. Tags can take up to 24 hours to appear in the Billing console, and a backfill updates Cost Explorer, Data Exports and CUR automatically but those refresh once every 24 hours, so the result is not visible the moment the request succeeds. A backfill requested on the morning of a reporting deadline will not make that deadline.
Access is narrower than most people expect. Only the management account — or a standalone account outside an organisation — can reach the cost allocation tags manager at all. A member-account team asked to improve their own allocation cannot activate a tag key themselves, and an allocation programme that assumes otherwise stalls on its first ticket.
Closing Thought
Cost allocation gets treated as a hygiene problem — tag everything, chase coverage, the number falls out. That framing survives contact with a real bill for about a week, because the largest unallocated block is usually shared infrastructure that no tag could ever have resolved, and the second largest is history that no tool can recover.
The more useful framing is the one the tooling actually implements: allocation is three separate problems wearing one name. Tagging coverage is a real metric for exactly one of them. Reporting it as though it measures all three is how a programme ends up at 94% coverage and a report finance will not sign.
And when the shared-cost number is finally produced, check where it lives before building on it. A figure that exists on one console page is a perfectly good answer to a monthly question and a poor foundation for a pipeline — which is a distinction worth making deliberately, rather than discovering when the dashboard disagrees with the statement.
Cost & Governance — the commitment layer: how Savings Plans and Reserved Instances are applied across an organisation, why the account that buys them is rarely the account that benefits, and what discount sharing does to the allocation model this post just built.
Official AWS Reference
- Organizing and tracking costs using AWS cost allocation tags — activation, and the tagged-plus-untagged reconciliation
- Backfill cost allocation tags — the twelve-month window and what it cannot recover
- Splitting charges within cost categories — sources, targets, allocation methods and the reporting caveat
- Organizing costs using AWS Cost Categories
- Understanding split cost allocation data — container-level costs and the record volume it adds
Comments