Summary
- Client: A technology startup running on Azure (anonymized).
- Problem: The monthly Azure bill reached $51,200, nearly double its normal level.
- Finding: 89 virtual machines from an acquired company’s development and staging environments had run at near-zero CPU for more than six months, costing $18,400 a month.
- Outcome: All 89 VMs were removed over 30 days, with snapshots taken first and no operational impact. Savings: $18,400 a month, or $220,800 a year.
- Root cause: Nobody owned the resources after the acquisition, so nobody was responsible for removing them.
The situation
When the client’s Azure bill reached $51,200 in a single month, nearly double its usual level, the CFO asked us to find out why. Within the first few hours, the cause was clear: 89 virtual machines that were fully provisioned, with premium storage and static public IP addresses, but doing no useful work.
The VMs had averaged close to 0% CPU for more than six months. Nobody on the current engineering team had created them, and nobody could say what they were for.
What we found
The VMs themselves were easy to identify. The more useful question was how they had come to exist, and why nothing had caught them. Three factors explained it:
- They were left over from an acquisition. The VMs belonged to the development and staging environments of a company the client had acquired eight months earlier. They were supposed to be decommissioned during the technical migration, and weren’t.
- They had no environment tags. Without tags marking them as development or staging, the VMs were excluded from the regular dev/test auto-shutdown schedules.
- Nobody owned them. The team that created the VMs had left during the acquisition, and no one on the client’s side had taken over responsibility for them.
The evidence
Azure Monitor’s historical performance data showed a clear difference between these VMs and the rest of the estate:
VM CPU utilization (6-month average)
------------------------------------
Production fleet: 47.3%
Marketing cluster: 38.1%
Idle acquired VMs: 0.2% (mostly from automated patching)
The cost breakdown for the 89 VMs:
- VM compute: $12,400/month
- Premium storage: $4,200/month
- Static public IPs and networking: $1,800/month
- Total: $18,400/month
Resolution
After documenting the findings and confirming the VMs were unused, we carried out the cleanup in three phases.
Phase 1: Immediate cost control
- Took snapshots of every disk, in case any of the data was needed later
- Stopped and deallocated all 89 VMs, which removed the $12,400 a month in compute charges immediately
Phase 2: Verification and removal
- Confirmed with every department head that none of the VMs or their data were needed
- Released the static public IP addresses and moved the remaining disks off Premium SSD
- Followed a 30-day decommissioning plan before final deletion
Phase 3: Prevention
- Introduced mandatory tagging policies for new resources
- Set up a weekly report of orphaned and unowned resources
- Required an owner to be assigned for every new resource
- Added cloud resources to the company’s acquisition integration checklist
Outcome
The client saved $18,400 a month, or $220,800 a year, with no impact on operations. The prevention measures are now part of the client’s standard cloud governance process.
Traditional monitoring hadn’t caught the problem because nothing was failing. The VMs were healthy and responsive. They just weren’t doing anything useful, and no alert is designed to detect that.
Lessons for your organization
If this situation sounds familiar, three steps are worth taking now:
- Run a VM utilization report across your whole cloud estate, looking for VMs with consistently low CPU and memory use over several months.
- Require an owner and a purpose for every resource, with tags or, better, with ownership rules that apply even when tags are missing.
- Audit for orphaned and unowned resources at least monthly, and after every acquisition, reorganization or migration.
Find idle resources in your own subscriptions
These 89 VMs ran idle for more than six months because their original team had left during the acquisition, and nobody on the current team could say who owned them or what they were for. Cloud Sleuth is being built as the ownership and context layer for cloud infrastructure, so every resource has a clear answer to who owns it, what it’s actually for and whether it should still exist. The Cloud Sleuth CLI will run on your machine or in your VPC, so nothing leaves your environment, and will cover Azure and AWS from launch, showing unowned resources, common orphans and basic allocation gaps in your own subscriptions and accounts. Both the local tool and Cloud Sleuth Cloud are pre-launch. Get early access.