The Ghost Inventory: Detecting Orphaned Cloud Resources in Billing Data

Every cloud account has them: resources that are still billing, but delivering nothing. A Reserved Instance purchased for a workload that was decommissioned six months ago. A Kinesis stream left provisioned after the data pipeline was replaced. An EC2 instance that a developer stopped but forgot to terminate โ€” still carrying its RI commitment.

The billing rows look normal. The cost is real. The value is zero.

This is the orphaned resource pattern โ€” infrastructure that is "configured and forgotten." It is distinct from a cost spike (the cost is flat, not elevated), distinct from a commitment loss (the resource may not have a commitment), and distinct from a scheduling miss (the resource is not being used at all, not just unused on weekends). The signal is the same billing cost maintained against near-zero or zero actual consumption.

Two Sub-Patterns, One Signal

PatternSQL ConditionReal-world root cause
Configured and forgotten Near-zero ConsumedQuantity for 5+ days out of 30 RI/SP commitment billing after workload terminated; Kinesis stream or WAF WebACL with no traffic; EC2 instance stopped but not terminated
Over-provisioned avg_daily_qty < avg_daily_cost ร— 0.10 Reserved capacity where actual consumption is a small fraction of what was committed โ€” the unit economics have inverted

Both require a cost floor to suppress noise (resources below a few cents per day are not worth investigating). The "configured and forgotten" path is the higher-fidelity signal: a resource that was billing $5/day and now has five consecutive days of near-zero consumption has clearly lost its workload.

What Appears in FOCUS Billing Data

The defining characteristic: BilledCost remains at the pre-orphan level while ConsumedQuantity collapses to zero or near-zero.

FOCUS FieldWorkload running (normal)Orphaned state
ConsumedQuantity 24 instance-hours/day (steady) 0.0 โ€” or near-zero (trace billing for minimum charges)
BilledCost $X.XX/day at committed rate Same $X.XX/day โ€” commitment billing continues unchanged
PricingCategory Committed / Reserved Same โ€” the pricing category does not change because the workload is gone
ResourceId Stable instance ID, active Same ID โ€” or "unmatched RI" rows with no associated running resource
Tags Team, project, cost-center tags intact Tags may be stripped or stale โ€” orphans often lose ownership metadata over time

AWS explicitly documents this: Reserved Instances bill "for every clock-hour during the term regardless of whether an instance is running." The commitment is a purchase, not a metered service โ€” the billing continues until the term expires, regardless of whether there is anything consuming it.

Temporal Profile

The orphaned resource pattern is a persistent flat-zero, not a decay curve. Before the workload is decommissioned: stable, non-zero consumption. After: flat-zero consumption, unchanged billing. No gradual transition โ€” the workload either runs or it does not.

This distinguishes it from:

The orphan's signature is the permanence of the near-zero state โ€” resources that have been at near-zero for weeks, not resources temporarily idle between batch runs.

Services with Fixed Minimum Charges

Some services charge a fixed fee regardless of usage, making their billing rows look like orphans even when the resource is correctly provisioned:

ServiceFixed chargeWhen ConsumedQuantity drops to near-zero
Amazon Kinesis Data Streams Shard-hours (billed regardless of throughput) When there are no data producers writing to the stream
AWS WAF WebACL $1/month per WebACL + $0.60/million requests When the ACL is provisioned but no traffic routes through it
Amazon GuardDuty Minimum account-level charge When log volume is very low โ€” may appear as near-zero usage, non-zero cost

For these services, the "configured and forgotten" signal fires on the usage charge leg (data PUT requests for Kinesis; web requests for WAF) when there is no traffic โ€” not on the infrastructure charge leg, which is constant by design.

Real-World Incidents

$2 million/month in orphaned resources (industry report): An e-commerce organization discovered approximately $2 million per month in cloud resources that were billing without any associated active workloads. The resources were a combination of Reserved Instances from decommissioned services, provisioned-but-idle infrastructure, and services with minimum charges that had no consumers. Detection came from a billing audit, not automated monitoring.

$127,000 surprise bill (dev.to post-mortem): A developer team's infrastructure โ€” provisioned for a project that had ended โ€” continued running for a full billing period. Nobody had set up billing alerts. Nobody had terminated the resources. The $127,000 bill appeared at month-end. The resources had been running at their normal daily rate the entire time; the bill was entirely predictable from the billing data, but nobody was watching.

$211,680/year in RI/SP waste (startup case study): A startup transitioned from on-demand to Reserved Instances at a rate that turned out to exceed their actual usage. The combination of commitment over-purchasing and workload changes left $42,000/month in committed capacity partially uncovered. A billing audit identified the gap; restructuring the RI portfolio and eliminating orphaned commitments saved $211,680 annually.

Detection Logic

-- Configured and forgotten: near-zero consumption for 5+ of 30 days
near_zero_qty_days = COUNT(days WHERE daily_consumedquantity < 0.01)
WHERE near_zero_qty_days >= 5
  AND avg_daily_cost > cost_floor

-- Over-provisioned: consumption tiny relative to cost
-- (fires on reserved capacity where the unit economics are inverted)
WHERE avg_daily_qty < avg_daily_cost ร— 0.10
  AND avg_daily_cost > cost_floor

The cost floor excludes resources with negligible billing where the savings from termination are smaller than the investigation effort. In production environments, a threshold of $5โ€“$10 over 30 days is practical. For demo environments, the floor is lower to catch smaller instances.

Fix Checklist

  1. For orphaned RIs and Savings Plans: check the AWS RI Marketplace. Standard RIs can be listed for resale. Convertible RIs can be exchanged for a different instance type that your active workloads can absorb. Both options are preferable to waiting for the term to expire.
  2. For over-provisioned commitments: do not renew at the same level. Before purchasing the next RI term, verify current utilization against committed capacity. The waste pattern often develops gradually as workloads right-size over time.
  3. For idle services (Kinesis, WAF): delete streams and WebACLs that have no active producers or traffic. These resources have no termination penalty โ€” the billing stops immediately.
  4. For stopped EC2 instances: an EC2 instance in "stopped" state still generates EBS storage charges. An instance that has been stopped for more than a few days with no intention to restart should be terminated (EBS volumes snapshotted if needed). Set a policy: any non-production EC2 instance stopped for more than 7 days is a candidate for termination review.
  5. Establish a monthly orphan audit cadence: run the near-zero-qty detection query monthly on non-production accounts. Fresh billing exports combined with a simple SQL query catch orphans in minutes. Without a cadence, orphans accumulate silently until someone happens to look.

See if this pattern is in your billing data

The 5-question DropInFinOps assessment takes 2 minutes and tells you which anomaly patterns your current billing setup is positioned to catch โ€” and which ones are slipping through.

Take the free assessment โ†’