Managed disks unattached for a week and still billing full price
What does ZopNight detect here?
An unattached managed disk bills 100% of its provisioned storage, and a P30 costs the same attached or not. ZopNight requires the authoritative diskState to read Unattached, a 7-day dwell since detachment, and passes on ASR replica disks and Kubernetes CSI volumes before recommending deletion.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-212 |
| Category | orphan |
| Severity | low |
| Metric | none — pure configuration read |
| Source | orphan_disk.go |
Where it applies
Deleting a VM does not delete its disks
Unless explicitly configured otherwise, Azure detaches and keeps a deleted VM’s managed disks. Each one then bills its full provisioned tier rate (size and performance class, not actual data) with zero compute attached. A 1 TB Premium SSD left behind by a decommissioned VM costs as much as it did in production. Fleets accumulate these quietly; they are consistently among the highest-value orphan findings in an Azure estate.
The exact state, not a substring
The gate is Azure’s own diskState property surfaced by the discoverer, matched exactly against Unattached. Other states never fire: Attached, Reserved, ActiveSAS, ActiveUpload, Frozen. An earlier implementation substring-matched a free-form status and could flag an attached disk; the exact-match design makes that impossible.
Three protections against deleting the wrong disk
A 7-day dwell: when Azure supplies the last-ownership-change timestamp, a disk detached less than a week ago is skipped, because mid-rebuild and mid-migration disks look identical to orphans on day one. An ASR veto: Azure Site Recovery replica and seed disks (ASRReplica, asrseeddisk prefixes) are intentionally unattached and stay exempt. A Kubernetes veto: disks carrying kubernetes.io tags or kubernetes-dynamic-pvc names belong to AKS persistent volume claims; deleting one out from under its PVC strands the pod that owns it.
Inventory your unattached disks now
az disk list \ --query "[?diskState=='Unattached'].{name:name, rg:resourceGroup, gb:diskSizeGb, sku:sku.name}" \ -o tableSnapshot first, then delete
A snapshot before deletion converts an irreversible call into a reversible one at a fraction of the disk’s cost, since snapshots bill on data written, not provisioned size. Take the snapshot, delete the disk, and set a reminder to delete the snapshot after a quiet quarter.
Scope of the check
Reader alone reproduces the detection: attachment state is resource metadata, no metrics involved. The priced saving is the disk’s full monthly storage charge; disks whose tier rate is unavailable are skipped rather than reported at $0.