Skip to main content
The Shadow Cloud Spend: $50k a Month FinOps Audit of Forgotten Dev Accounts

The Shadow Cloud Spend: $50k a Month FinOps Audit of Forgotten Dev Accounts

Amanpreet Kaur By Amanpreet Kaur
Published: May 6, 2026 11 min read

The Shadow Cloud Spend: $50k a Month Hiding in Forgotten Dev Accounts

Every mid-size engineering organization has 5 to 15 AWS accounts that nobody actively owns. The “POC” account from 2024. The “team-old-name” account that survived the 2025 reorg. The “consultant-X-temp” account that got a working IAM role and then went quiet. Each one runs a few NAT gateways, an idle RDS, EBS volumes from 2023, and a CloudWatch log group with infinite retention.

Shadow cloud spend in those forgotten accounts totals $30,000 to $80,000 per month per organization. None of it produces business value. None of it shows up cleanly on the FinOps dashboard, because cost-allocation tag schemes assume the account has an active owner and the forgotten accounts have stale or no tags.

The accounts are hard to see for the same reason they are hard to reclaim. The original owner left. The team got renamed. The IAM root credentials are in a stale 1Password vault. AWS Organizations sees the account but no human has logged in for 9 months. So the cleanup gets postponed forever, and the bill compounds.

This post is the playbook. Inventory the accounts you forgot you have. Audit what is running in each. Decide per-account: archive, delete, adopt, or invoice. Then the structural fix: an account lifecycle policy that prevents the next round of orphans. The pattern composes with closed-loop FinOps and the cost-per-customer attribution work that gives you visibility on the bill in the first place.

The 5-15 unowned-account pattern

Talk to FinOps practitioners at any organization with more than a year of AWS history and 200+ engineers. The same archetype emerges every time. Four shapes account for most forgotten accounts.

ArchetypeTypical resources runningMonthly spend
The 2024 POC account (project never moved to prod)2 NAT gateways, 1 t3.large EC2, RDS db.t3.medium, 200 GB EBS$4,200
The renamed-team account (org chart changed, account name did not)1 NAT gateway, 6 idle EBS volumes, S3 bucket with versioning enabled, Lambda hourly cron with no purpose$1,800
The consultant temp account (engagement ended, account stayed)1 NAT gateway, 1 RDS Multi-AZ, EFS volume with 80 GB stale data$3,600
The disaster-recovery test account (test happened, account stayed)Cross-region replication still running, 4 EBS snapshots from 2024, 1 forgotten Elastic IP$2,400

Mid-size orgs typically have 8 to 12 accounts matching one of these archetypes. Total shadow spend lands $30,000 to $80,000 per month. At the upper end, this is roughly 5 percent of total cloud spend for an organization in the $1M to $2M monthly range, all of it producing zero business value. The pareto is heavy: of 10 unowned accounts, 2 typically account for 60 to 80 percent of the total shadow bill. Triage them first.

What is actually running in there

The audit checklist for an unowned account is short. Five resource types account for almost all the persistent cost.

ResourceTypical monthly costWhy it persists
NAT Gateway (idle)$32 fixed + small data feesSingle biggest forgotten-account driver; runs even when no real traffic flows
RDS instance (idle, Multi-AZ)$50 to $300RDS does not scale to zero; idle RDS bills the same as busy RDS
EBS volume (unattached)$0.08 per GB-monthUnattached EBS bills indefinitely; 1 TB volume costs $80 per month for nothing
Elastic IPs (unattached)$3.65 per EIP per monthAWS charges for unused EIPs; 4 forgotten EIPs is ~$15 per month per account
CloudWatch log groups (infinite retention)$0.03 per GB-month + ingestDefault retention is “Never expire”; 200 GB of logs costs $6 per month, growing forever
Architecture diagram

NAT gateways are the single biggest driver. A forgotten NAT in a quiet account costs $40 to $100 per month because there is still small egress from CloudWatch agent telemetry, S3 health checks, or stale Lambda functions logging to a CloudWatch log group. The fixed $32 per month is the floor; the data processing on stale background traffic adds another $10 to $70 depending on what tooling was left running.

Why your dashboards miss them

Cost dashboards are designed for active accounts. Tag-based allocation, business-unit roll-ups, monthly budget comparisons. The whole machinery assumes the account has an owner who tagged resources and watches the budget. Forgotten accounts break every assumption.

Dashboard viewWhat it showsWhy orphans hide
Cost by tagSpend grouped by team or projectForgotten accounts have stale tags; resources aggregate to “untagged” or “unallocated”
Cost by business unitRoll-up to org chartThe owning business unit no longer exists in the org chart; spend has nowhere to roll up
Account-level monthlyPer-account totalsVisible but requires manual filtering; small accounts get ignored
Cost anomaly alertsSudden changes in spendForgotten accounts have stable spend curves; no anomaly fires

The “untagged” and “unallocated” buckets are the tell. They contain real money but get scrolled past during cost reviews because the conversation is always about active teams. Until someone deliberately filters to “spend in accounts with no owner-tag,” the shadow stays shadow.

The triage playbook

The cleanup is a one-time exercise. The structural fix (lifecycle policy) prevents the next round. Both are needed; do the cleanup first to free the budget, then ship the policy to keep it free.

Architecture diagram

1. Inventory unowned accounts. Run the AWS Organizations API for the full account list. Cross-reference against the owner-team tag. Anything missing the tag, or with a tag pointing to a team that no longer exists in HR, is a candidate.

2. CloudTrail lookup for original owner. The first IAM principal to provision resources in the account is usually the architect. Search CloudTrail for the earliest iam:CreateUser or ec2:RunInstances event. The principal email resolves to a team-of-record via your identity provider. Even if that engineer left, their team usually still exists.

3. Apply lifecycle:orphan tag. This is the lowest-risk first action. The tag declares the account orphaned without changing any resource state. It also gives the cost dashboard something to filter on so the spend stops hiding.

4. Attach Deny-all SCP. Use AWS Organizations Service Control Policies to prevent new resources from being created in tagged-orphan accounts. The SCP is reversible. Existing resources keep running until the per-account decision is made, but no new spend starts.

5. Per-account decision. Triage each account in 15 to 30 minutes once tooling is in place. List resources, check the top 3 cost drivers, contact the most plausible owner, decide.

Triage outcomeWhen to chooseKey risk
Archive (suspend the account)Most cases; preserves audit trail and rollback pathSuspended accounts cost ~$0 but stay in your Organization
Adopt (new owner team takes over)Active workload found that someone still usesOwner accepts the budget and the operational responsibility
Delete (close the account)Confirmed nothing of value, no audit-retention needClosure is permanent after 90 days; cannot recover anything
Invoice the teamWorkload exists, owner found, payment disputeSets expectation that team owns spend going forward

For 10 unowned accounts, total triage effort is 3 to 5 hours over 2 to 3 days. The ROI ratio is heavy: a few engineering hours against $30k to $80k per month in recovered spend.

The lifecycle policy that prevents the next round

The cleanup is a one-time saving. The lifecycle policy is the structural saving. Without policy, orphans regenerate at roughly 1 to 3 new accounts per quarter as teams reorg and projects end.

The policy has three rules. First, every AWS account in the Organization must have a OwnerTeam tag and a RenewalDate tag. Resources cannot be created in an account that lacks both, enforced by SCP. Second, on the renewal date each year, the platform team validates that the OwnerTeam still exists in HR and the team lead acknowledges renewal. Third, accounts that fail revalidation get auto-tagged lifecycle:orphan, which triggers the Deny-all SCP, which halts new spend within 24 hours.

Architecture diagram

The annual cron job is the low-effort win. It runs once a year per account, sends an email to the OwnerTeam asking for renewal, and auto-tags orphan if no acknowledgment lands within 14 days. Running this for the first time on an existing fleet finds the orphans you already have. Running it forward keeps the fleet clean.

Closing the loop

The whole pattern is a closed-loop FinOps instance. Detect: no-owner-tag at renewal. Decide: auto-tag orphan. Act: attach Deny-all SCP. Verify: no new resources created in the account for 30 days. Same shape as cost anomaly response and IAM remediation, just on an annual cadence instead of 5-minute.

This composes naturally with policy-aware AI cloud governance. The policy graph already knows which teams exist, which accounts they own, and which exceptions are valid. Adding “is this account orphan” is one more rule. The detection runs against the same governance state that powers the rest of the autonomous-cloud loop.

The shadow cloud spend is not a vendor problem or a tooling problem. It is an organizational lifecycle problem with a tooling-shaped fix. AWS Organizations + tag enforcement + annual revalidation + Deny SCPs are all native primitives. The structural cost saving is in the policy, not the cleanup, because the cleanup happens once and the policy holds the line every year after.

Amanpreet Kaur

Written by

Amanpreet Kaur Author

Engineer at Zop.Dev

ZopDev Resources

Stay in the loop

Get the latest articles, ebooks, and guides
delivered to your inbox. No spam, unsubscribe anytime.