Implementing Resource Tagging for Cost Allocation by Projects and Teams
At the end of the month, the finance department sends an AWS bill for $40,000 — and no one can tell which team consumed a third of the budget. EC2 instances without tags, S3 buckets with names like backup-old, RDS clusters with Owner left blank. We have faced this multiple times. The solution is always the same — systematic tagging with enforcement policies. This isn't about pretty reports. It's about turning the cloud bill from a black box into a detailed breakdown: how much team-backend spends, how much goes to the staging environment of the payments project, and where that unexplained $3,000 spike for egress comes from. Based on our data, up to 30% of cloud costs go to untagged resources. That's $10,000–$15,000 per month for a typical project. Our engineers hold AWS certifications and have 10+ years of experience in cloud infrastructure. We guarantee cost transparency after implementing the tagging system.
Why Simply Adding Tags Doesn't Work
The most common attempt is to tell developers "tag resources when creating them" and add this to the PR checklist. Three months later, 40% of resources are still untagged. Someone created an instance manually via the console, ran terraform apply without the required variables, or simply forgot.
The second pitfall is inconsistent taxonomy. One team writes environment: prod, another env: production, a third Env: Production. AWS Cost Explorer does not merge these automatically. The report shows three unrelated rows instead of one.
The third problem is that tags are not inherited. If Terraform creates an Auto Scaling Group without propagate_at_launch = true, EC2 instances from that group appear without tags. The ASG itself is correctly tagged.
How to Build a Tagging Strategy
We start with an audit of the current state. Use this command: aws resourcegroupstaggingapi get-resources --resource-type-filters ec2:instance --query 'ResourceTagMappingList[?Tags==[]]'. This shows how many resources have no tags at all. In a typical project, that's 30–50%.
Then we define mandatory tags. A minimal working set:
| Tag | Example Value | Purpose |
|---|---|---|
project |
payments-api |
Which product the resource belongs to |
team |
backend |
Owning team |
environment |
production |
Environment (production/staging/dev) |
managed-by |
terraform |
How the resource is managed |
cost-center |
CC-BE-01 |
Cost center for financial reporting |
After agreeing on the taxonomy, we implement it at the IaC level. In Terraform, we add default_tags in the provider block:
provider "aws" {
region = var.aws_region
default_tags {
tags = {
project = var.project_name
team = var.team_name
environment = var.environment
managed-by = "terraform"
}
}
}This ensures tag inheritance for all created resources without explicitly specifying them in each module. For ASG, we add propagate_at_launch:
resource "aws_autoscaling_group" "app" {
# ...
tag {
key = "project"
value = var.project_name
propagate_at_launch = true
}
}For enforcement, we enable AWS Config Rule required-tags. A resource without mandatory tags is marked as NON_COMPLIANT. We can set an alert in CloudWatch or an automatic quarantine policy via AWS Config Remediations.
What to Do with Existing Resources
Retrospective tagging is a separate task. Approaches include scripts in boto3 that iterate over all regions and services, adding tags based on rules (e.g., by Owner from the IAM role or by security group name). We use a combination of aws resourcegroupstaggingapi tag-resources with a preliminary export of the resource list. For S3 buckets created without tags, we use a separate script that reads the bucket name and applies tags based on a mask (e.g., logs-* → environment: production, team: infra). Run this in a maintenance window and first on non-production.
Tag Policies in AWS Organizations
If the account has multiple teams or uses a multi-account structure, Tag Policies at the Organization level are the only way to ensure consistency. According to AWS documentation on Tag Policies, Tag Policies define allowed values for specific keys. A policy:
{
"tags": {
"environment": {
"tag_key": {
"@@assign": "environment"
},
"tag_value": {
"@@assign": ["production", "staging", "development", "testing"]
},
"enforced_for": {
"@@assign": ["ec2:instance", "rds:db", "s3:bucket"]
}
}
}
}After applying the policy, a value like env: prod will be rejected. Only environment: production is allowed. This is strict, but exactly what is needed for working cost allocation. Our engineers configure such policies considering the existing landscape.
Reports and Visualization
After two to three weeks of working with tags, AWS Cost Explorer starts providing useful data. We configure Cost Allocation Tags in the Billing Console. Only then do tags appear in reports. Without this step, tags exist but Cost Explorer does not see them.
For more detailed analytics, we export Cost and Usage Reports to S3 and build Athena queries:
SELECT resource_tags_user_project AS project, resource_tags_user_team AS team, SUM(line_item_unblended_cost) AS total_cost
FROM cur_data
WHERE line_item_usage_start_date >= CURRENT_DATE - INTERVAL '90' DAY
GROUP BY 1, 2
ORDER BY 3 DESC;This is cheaper than Cloudability or Apptio if the scale does not require enterprise tools.
Which Enforcement Approach to Choose
Manual PR review works on a small scale but misses errors during console deployments. AWS Config Rules centrally block non-compliant resources but require rules for each service. Tag Policies guarantee a unified taxonomy at the account level but do not fix already created resources. CI checks in Terraform (tflint, checkov) protect at the code stage but do not cover manual changes. We combine Tag Policies with CI checks. This covers 95% of scenarios.
Work Stages
The implementation plan is divided into stages with specific timelines and deliverables:
| Stage | Duration | Result |
|---|---|---|
| Audit | 1–2 days | Inventory of untagged resources and analysis of current taxonomy |
| Design | 2–3 days | Agreement on mandatory tags, allowed values, and owners |
| IaC Integration | 3–5 days | default_tags in Terraform, module updates, ASG propagation checks |
| Enforcement | 3–5 days | AWS Config Rules, Tag Policies, CI gate via tflint or checkov |
| Retrospective Tagging | 2–4 days | Scripts for tagging existing resources via AWS CLI or boto3 |
| Reporting | 2–3 days | Cost Allocation Tags, CUR in S3, dashboards in Cost Explorer or Grafana |
Timelines depend on the number of accounts and IaC complexity. For a single account with Terraform, it's 1–2 weeks. For multi-account with Organizations and multiple teams, it's 3–6 weeks.
What is Included in the Work
- Documentation of tag taxonomy (mandatory and optional keys, allowed values)
- Update of Terraform modules and pipeline configurations for automatic tag checks
- Configuration of AWS Config Rules and Tag Policies with detection and alerts
- Scripts for retrospective tagging of existing resources
- Ready-made Athena queries and dashboards for cost reporting
- Team training (1–2 calls) and support for one month after implementation
Request a consultation: we will assess your project within two days and propose a turnkey implementation plan. Contact us to bring order to your cloud costs. Get an audit of your current tagging state — we will show how much money is leaking on untagged resources.







