finopstaggingcost-allocationgovernance

Finding untagged resources: closing the allocation gap

Untagged resources are the reason your cost allocation never reaches 100 percent. Finding them systematically, by account and service, turns an unattributable slice of the bill into owned, actionable spend. Here is the method.

The C3X Team··6 min read

Quick answer

Find untagged resources by querying your billing data (the AWS Cost and Usage Report, Azure cost exports, or GCP BigQuery billing export) for line items whose required tag columns are null, then grouping the unallocated spend by account and service to find the biggest offenders first. Cross-check with a resource inventory (AWS Resource Groups Tagging API, Azure Resource Graph, GCP asset inventory) to catch idle resources that generate little cost but still need an owner. Attack the top few services that hold most of the unallocated dollars, assign owners, and backfill tags. Most teams find that a handful of services hold 80 percent of the untagged spend.

When cost allocation stalls at 70 or 80 percent, the missing piece is almost always untagged resources: line items on the bill with no owner, no cost-center, no environment. That unallocated slice is invisible to showback, immune to accountability, and usually where quiet waste hides. Finding it systematically, rather than stumbling on it, is a core FinOps task. The good news is the data to find it is already in your billing export.

Start from the billing data

The authoritative source is the detailed billing export: the AWS Cost and Usage Report (CUR), Azure cost exports, or the GCP BigQuery billing export. Each row carries the resource, its cost, and its tag columns. Query for rows where a required tag is null and sum the cost. That total is your unallocated spend, and it is the number to drive down. Grouping it by service and account immediately shows where to start, because the unallocated dollars are rarely spread evenly.

SourceWhat to query
AWS CURRows where resource_tags_user_owner is null
Azure cost exportRecords with empty required tag fields
GCP billing exportBigQuery rows missing labels.owner
Tagging API / inventoryLive resources with no required tags

Follow the money, not the resource count

A common mistake is sorting by count of untagged resources. You end up chasing hundreds of tiny objects while a single untagged RDS cluster or NAT gateway holds most of the money. Sort by unallocated cost instead. In practice a handful of services, often compute, managed databases, and data transfer, hold 80 percent of the untagged dollars. Fixing those few moves your coverage number the most for the least effort, the same Pareto logic that governs any waste cleanup.

Catch the cheap-but-orphaned resources

Billing data misses resources that cost almost nothing yet still matter for governance: an untagged security group, an empty S3 bucket, an idle IP. For those, cross-check with a resource inventory API: the AWS Resource Groups Tagging API, Azure Resource Graph, or GCP Cloud Asset Inventory. These list every resource and its tags regardless of cost, so you catch the orphans that are cheap today but might grow, and the ones that signal a broader gap in a team's tagging discipline. Many of these overlap with the orphaned resources worth deleting entirely.

Assign owners and backfill

Once you have the list ranked by cost, the work is attribution. Use account, resource naming, creation timestamps, and CloudTrail or activity logs to infer the likely owner, then confirm and apply the tag. For resources you genuinely cannot attribute, apply an explicit unallocated tag so they show up as a known bucket rather than a silent gap, and split them by a rule as covered in the shared-cost splitting guide. The goal is that every dollar lands somewhere on purpose.

Make the finding continuous

A one-time hunt drifts back within weeks unless you close the loop. Turn the query into a weekly report, publish coverage per team, and enforce required tags at deploy time so the backlog stops growing. This combination, a deploy-time gate plus a recurring find-and-fix sweep, is what holds allocation coverage above 95 percent instead of letting it decay. Coverage is a real cost KPI, so trend it over time. Price new infrastructure against the resource catalog so the owner and the cost are both known before the resource ever appears untagged on a bill.

FAQ

How do I find untagged cloud resources?

Query your detailed billing export, the AWS Cost and Usage Report, Azure cost exports, or the GCP BigQuery billing export, for rows where a required tag column is null, then sum and group the cost by account and service. Cross-check with a resource inventory API (AWS Resource Groups Tagging API, Azure Resource Graph, GCP Cloud Asset Inventory) to catch cheap-but-orphaned resources that generate little cost but still need an owner.

Should I prioritize by resource count or by cost?

By cost. Sorting by count of untagged resources makes you chase hundreds of tiny objects while a single untagged database or NAT gateway holds most of the money. Sort by unallocated cost, and you will usually find a handful of services, compute, managed databases, and data transfer, hold about 80 percent of the untagged dollars. Fixing those few moves coverage the most for the least effort.

What about resources that cost almost nothing but are untagged?

Catch them with a resource inventory API rather than billing data, since billing data barely shows them. The AWS Resource Groups Tagging API, Azure Resource Graph, and GCP Cloud Asset Inventory list every resource and its tags regardless of cost. This surfaces orphans like untagged security groups, empty buckets, and idle IPs that are cheap now but may grow or signal a team's broader tagging gap.

What do I do with resources I cannot attribute?

Apply an explicit unallocated tag so they appear as a known, measured bucket rather than a silent gap in your data, then split that bucket by a rule (for example, proportionally across teams by their allocated spend). Use account, naming, creation timestamps, and activity logs to attribute as many as possible first. The goal is that every dollar lands somewhere on purpose, even if the landing spot is a shared bucket.

How do I keep untagged resources from coming back?

Close the loop. Turn the find query into a weekly coverage report published per team, and enforce required tags at deploy time with policy as code so the backlog stops growing. A one-time hunt drifts back within weeks, but a deploy-time gate plus a recurring sweep holds allocation coverage above 95 percent. Treat coverage as a tracked KPI and trend it over time.

How does C3X help close the allocation gap?

C3X prices Terraform resources in the pull request against a live catalog, so cost visibility arrives before the resource exists. Paired with a required-tag check in the same CI step, a resource is understood and attributable before it can ever show up untagged on a bill, shrinking the source of the allocation gap rather than only cleaning it up after the fact.

What to do next

Know the cost and the owner before a resource lands on the bill. C3X reads your Terraform and prices your resources against a live catalog. Start with the quickstart.

Try C3X on your own Terraform

Free and open source. No API key required. One command to install, one command to estimate.