Showback that survives contact with finance: tag inheritance and cost allocation rules in Azure
Resource tags alone will never give you a clean cost-per-team report in Azure. Here is how I combine Azure Policy, Cost Management tag inheritance and cost allocation rules into a showback model that actually adds up.
Almost every FinOps engagement I’ve done starts with the same slide: “we tag everything with
costCenter, so we can already see cost per team.” Then we open Cost analysis, group by that
tag, and the biggest bar on the chart is untagged. Sometimes it’s 20% of the bill,
sometimes it’s half. Nobody lied — the tagging policy exists — it’s just that tags on
resources and tags on cost records are two different things, and shared platform costs
(hub networking, firewalls, Log Analytics, the landing zone itself) don’t belong to any single
team in the first place.
Here’s the three-layer model I use to close that gap: enforce tags where they’re cheap to enforce, let Cost Management fill in the rest, and explicitly redistribute what’s genuinely shared.
Why resource tags leak
There are three separate reasons your tagged estate still produces untagged cost:
- Resources created before the policy. A
denypolicy only stops new non-compliant deployments; it does nothing for the 4,000 resources already there. - Resource types that don’t pass tags to billing. The Azure tag support reference has a column literally called “Tag in cost report”, and plenty of resource types that support tags are marked No there. You can tag them perfectly and still see nothing in Cost analysis.
- Charges that don’t come from a tagged resource. Purchases, and resources that don’t emit usage at subscription scope, never carry a resource tag to begin with.
No amount of “please tag your stuff” emails fixes #2 or #3. That’s why the model has three layers.
Layer 1: tag the containers, not every resource
My rule of thumb: ownership tags (costCenter, owner, environment) are mandatory on
subscriptions and resource groups, optional on resources. Containers are few, created by
the platform team or a vending pipeline, and easy to govern. Resources are many and created by
everyone.
The built-in Azure Policy definitions cover this directly:
- Require a tag on resource groups (
deny) — no resource group withoutcostCenter. - Inherit a tag from the resource group if missing (
modify) — copies the tag down onto resources that don’t have it, and leaves an existing different value alone. - Inherit a tag from the subscription if missing (
modify) — same idea, one level up.
Because the inheritance policies use the modify effect, a remediation task can fix existing
resources, not just new ones. A minimal assignment at management group scope looks like this:
$mg = '/providers/Microsoft.Management/managementGroups/corp'
$def = Get-AzPolicyDefinition -Id '/providers/Microsoft.Authorization/policyDefinitions/ea3f2387-9b95-492a-a190-fcdc54f7b070'
$assignment = New-AzPolicyAssignment -Name 'inherit-costcenter-from-rg' `
-Scope $mg -PolicyDefinition $def `
-PolicyParameterObject @{ tagName = 'costCenter' } `
-IdentityType SystemAssigned -Location 'westeurope'
# The modify effect needs the assignment identity to hold the roles the definition declares
foreach ($roleId in $def.PolicyRule.then.details.roleDefinitionIds) {
New-AzRoleAssignment -Scope $mg -ObjectId $assignment.IdentityPrincipalId `
-RoleDefinitionId ($roleId -split '/')[-1]
}
# Fix what already exists
Start-AzPolicyRemediation -Name 'remediate-costcenter' `
-PolicyAssignmentId $assignment.Id -ManagementGroupName 'corp'
This gets real tags onto real resources, which matters beyond cost — automation, inventory and incident response all read them. But it still doesn’t solve the resource types that never emit tags into billing data.
Layer 2: turn on tag inheritance in Cost Management
This is the setting I find most often switched off, and it’s the one that makes the biggest difference to the “untagged” bar. Cost Management tag inheritance applies subscription and resource group tags (and on MCA, billing profile and invoice section tags) to the usage records of child resources. It doesn’t touch the resources themselves — it rewrites what the cost data says, which is exactly the part Azure Policy can’t reach.
Key behaviours, straight from the docs:
- Available for EA, MCA, and MPA with Azure plan subscriptions, configurable at EA billing account, MCA billing profile and subscription scope.
- After you enable it, usage records are updated in roughly 8–24 hours, and the change applies to the current month — enable it on the 20th and records from the 1st get the tags that existed on the 20th. It doesn’t rewrite prior closed months, so switch it on early.
- When a resource tag and an inherited tag have the same key, the resource tag wins by default. You can flip that so the container tag overrides — useful when you trust your resource group tags more than whatever engineers typed on individual resources.
- Purchases, and resources that don’t emit usage at subscription scope, won’t pick up the subscription tags even with the setting on.
You can set it in the portal under Cost Management → Settings, or — better, so it’s part of your subscription vending — via the Cost Management Settings API:
PUT https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.CostManagement/settings/taginheritance?api-version=2026-06-01
{
"kind": "taginheritance",
"properties": {
"preferContainerTags": false
}
}
preferContainerTags: true is the “inherited tag overrides resource tag” option. I start with
false and only change it once the resource group tagging is trustworthy.
Layer 3: allocate the genuinely shared costs
After layers 1 and 2, what’s left untagged is usually not a tagging problem — it’s the hub. The firewall, the ExpressRoute gateway, the central Log Analytics workspace. Those belong to the platform team on paper and to everyone in practice.
Cost allocation rules handle that. A rule takes costs from source subscriptions, resource groups or tags and redistributes them to target subscriptions, resource groups or tags. You can split them evenly, in proportion to the targets’ total, compute, storage or network cost, or with custom whole-number percentages that add up to 100%.
The details that matter in an enterprise rollout:
- Supported for EA, MCA-E and MCA-online. Creating rules needs Enterprise Administrator (EA) or billing account owner (MCA) — so plan this with whoever holds the billing roles, not just the platform team.
- Prefilled percentages are frozen. The proportional split is calculated when you create the rule and doesn’t move until you edit it. If your consumption mix changes, schedule a quarterly review of the rules.
- Rules are processed in creation order. If rule 1 already allocates all of subscription A, a later rule with the same source has nothing left to allocate.
- Allocation doesn’t support purchases, including reservations and savings plans, and it doesn’t change the invoice. It’s a reporting construct for showback and chargeback.
- Allocated costs show up in Cost analysis, budgets and forecasts, and in exports and the Cost
Details API via the
costAllocationRuleNamecolumn. The Cost Management Power BI app, the Power BI Desktop connector and the older Usage Details API don’t support it.
That last point bites during invoice reconciliation: an export will contain the negative
source line and the positive target line. Filter on costAllocationRuleName being empty when
you need numbers that match the invoice, and include it when you’re producing the team report.
How I roll it out
- Tag every subscription and resource group with
costCenterandowner; add thedenypolicy for new resource groups. - Assign the “inherit if missing” policies and run remediation.
- Enable Cost Management tag inheritance at the highest scope you control — ideally at the start of a month.
- Wait a full cycle and look at the untagged remainder. What’s left is your shared-cost list.
- Create allocation rules for that list, agree the split method with finance, and document when each rule gets reviewed.
Takeaway
Showback fails when it’s framed as a tagging discipline problem. It’s a data pipeline problem: enforce tags on the handful of containers you control, let Cost Management project them onto usage records, and treat shared platform costs as an explicit, reviewed allocation rather than an embarrassing “untagged” bar. Do that and the report you hand to finance finally adds up to the invoice.
Sources & further reading: Group and allocate costs using tag inheritance, Allocate Azure costs, Policy definitions for tagging resources, Tag support for Azure resources, Settings - Create Or Update By Scope (Cost Management REST API).