A tagging strategy that makes cost allocation possible
Without consistent tags, your cost reports are fiction. A tagging policy that sticks.
Finance once asked me a simple question: "How much does Team Atlas spend on AWS each month?" It took me three days to answer, and the answer was a guess. We had 40,000 resources and maybe a third of them carried any tag at all. That month I stopped treating tagging as hygiene and started treating it as the foundation of cost visibility.
A tagging strategy only works if it's small, enforced, and tied to the bill. Here's the one that finally let me answer that question in five minutes instead of three days.
Pick a tiny set of mandatory tags
The mistake teams make is designing 25 tags and enforcing none. I run with four mandatory keys, all lowercase, all from controlled vocabularies:
| Tag key | Purpose | Example values |
|---|---|---|
team | Owning team for chargeback | atlas, orion |
environment | Lifecycle stage | prod, staging, dev |
cost-center | Finance GL code | cc-4412 |
service | Logical application | checkout-api |
Four tags answer the questions people actually ask: who owns this, is it production, which budget pays for it, and what app is it part of.
Activate the tags as cost allocation tags
This is the step everyone forgets. A tag does nothing for billing until you activate it in Billing and Cost Management → Cost Allocation Tags. Until then your tags exist on resources but never appear in Cost Explorer or the Cost and Usage Report. Activation isn't retroactive either, data only flows from activation forward, so do it early.
aws ce get-cost-and-usage \
--time-period Start=2026-06-01,End=2026-07-01 \
--granularity MONTHLY \
--metrics "UnblendedCost" \
--group-by Type=TAG,Key=team
Untagged spend is the metric that matters most. Track it as a percentage and drive it toward zero, every untagged dollar is a dollar nobody is accountable for.
Enforce at creation, don't audit after
Cleaning up tags after the fact is a losing battle. I enforce two ways. First, a Service Control Policy or IAM policy that denies resource creation when the required tag is missing:
{
"Effect": "Deny",
"Action": ["ec2:RunInstances"],
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"Null": { "aws:RequestTag/team": "true" }
}
}
Second, an AWS Config rule (required-tags) that flags any existing resource missing the keys, so legacy gaps surface in a dashboard. The SCP stops the bleeding; Config tracks the backlog.
Push tags down with Terraform default_tags
Manual tagging doesn't scale. In Terraform, default_tags on the AWS provider stamps every taggable resource automatically, so engineers can't forget:
provider "aws" {
region = "us-east-1"
default_tags {
tags = {
team = "atlas"
environment = "prod"
cost-center = "cc-4412"
}
}
}
The service tag stays per-resource since it varies, but the three account-wide tags come for free.
Watch the resources that don't tag cleanly
Some costs resist tagging. Data transfer, NAT Gateway throughput, and shared support charges don't attach to a single team's tag. For those I split by usage proportion in the Cost and Usage Report, or isolate them in their own account so the boundary is the allocation. Knowing which 10-15% of spend is genuinely unallocatable is itself useful, it stops people from chasing perfection.
Takeaways
- Enforce four mandatory tags, not twenty-five, small and enforced beats comprehensive and ignored.
- Activate tags as cost allocation tags in Billing; activation is not retroactive, so do it on day one.
- Block creation of untagged resources with SCPs and stamp tags automatically via Terraform
default_tags. - Track untagged spend as a percentage and accept that shared costs like data transfer need a proportional split.