Skip to content
KostrixBeta, home

Unused EBS volumes: how to find them in every region, and what they cost

An EBS volume keeps billing after the instance it was attached to is gone, a snapshot keeps billing after its volume is deleted, and both do it quietly, per gigabyte, per month, in whichever region they were created in. This page is how Kostrix approaches EBS cost optimization: how it finds them, what it checks beyond the obvious ones, and how it puts a price on each finding that you can recompute by hand.
EBS checks6 of 235 rules
  • EBS volumes unattached or attached with zero I/Oebs-unattached
  • Orphaned or aged EBS snapshotsebs-snapshot-orphans
  • gp2 volumes cheaper as gp3ebs-gp2-to-gp3
  • io1/io2 volumes that fit inside gp3's performance envelopeebs-io-rightsize
  • Fast Snapshot Restore enabled on snapshots nothing has been restored fromebs-fsr-idle
  • Long-retained standalone EBS snapshots in the standard tier that are archive-tier candidatesebs-snapshot-archive-candidates

Why unattached EBS volumes are usually the first finding

Volumes outlive instances. An instance is terminated, an autoscaling group is torn down, a migration finishes, and unless somebody ticked “delete on termination” the root and data volumes stay behind in the available state. AWS bills provisioned EBS storage by the GB-month whether or not anything is attached to it, and a snapshot taken “just in case” before a deletion is billed for as long as it exists.

Individually the volumes are small: 8 GB here, 16 GB there. In an account that has been running for a few years they are the single largest line of pure waste, because nothing depends on them and nothing alerts on them. On WhizzyGeeks' own account the largest single finding Kostrix has ever raised was 2,113 unattached volumes in one region.

The console and CLI way, and why it misses most of them

The AWS console lists volumes one region at a time. The CLI does the same: aws ec2 describe-volumes --filters Name=status,Values=available answers for the region in the profile and no other.

Unused volumes accumulate in exactly the regions nobody looks at: the one a proof of concept ran in two years ago, the one a disaster-recovery test was done in once. A script that loops over every region, filters on status, checks the attachment of the rest for zero I/O, walks the snapshots for ones whose source volume no longer exists, and then prices each result from the regional rate is the job. Kostrix is that script, maintained, with 6 EBS checks rather than one, run on a schedule under a read-only policy.

The 6 EBS checks Kostrix runs

Each one is a rule in the scanner with the identifier it stamps on its findings. The wording is the rule's own description.

ebs-unattached
EBS volumes unattached or attached with zero I/O
ebs-snapshot-orphans
Orphaned or aged EBS snapshots
ebs-gp2-to-gp3
gp2 volumes cheaper as gp3
ebs-io-rightsize
io1/io2 volumes that fit inside gp3's performance envelope
ebs-fsr-idle
Fast Snapshot Restore enabled on snapshots nothing has been restored from
ebs-snapshot-archive-candidates
Long-retained standalone EBS snapshots in the standard tier that are archive-tier candidates

Unattached volumes keep their lineage: the finding names the snapshot a volume was created from, the AMI that snapshot backs, and whether a launch template still references it, so the decision to delete is made with the facts rather than guessed. The full list of 235 AWS cost optimization checks covers the storage family's other checks too: S3 lifecycle gaps, EFS file systems with no connections, AWS Backup recovery points whose source is gone.

Evidenceebs-unattached / ap-south-1
Terms behind the estimated monthly saving for unattached EBS volumes
Unattached volumes2,113volumes
Mean provisioned size16.00GB
Provisioned total33,808GB
gp3 storage rate, ap-south-10.0800USD / GB-month
Estimated monthly saving2,704.64USD / month

2,113 x 16.00 GB = 33,808 GB
33,808 GB x 0.0800 USD/GB-month = 2,704.64 USD/month

Figures from one real scan of WhizzyGeeks' own AWS account; the resource ids are redacted. The rate comes from the AWS Price List API for the region in question. Kostrix never guesses a price: if the rate cannot be fetched, the finding is reported without a figure rather than with an invented one.

Count, times mean size, times the regional rate

The count and the provisioned sizes come from the account. The rate comes from the AWS Price List API for that volume type in that region, fetched at scan time. The product of the three is the monthly figure, and all three terms are printed on the finding so anyone can check it on a calculator.

2,113 volumes at a mean of 16.00 GB is 33,808 GB provisioned; at the gp3 storage rate in ap-south-1 of 0.0800 USD per GB-month that is 2,704.64 USD a month. Where a rate cannot be fetched the finding is still raised, without a figure: Kostrix never falls back to a remembered or averaged price.

Pooled findingsgrouped by required action

Delete unattached EBS volumes

2,113 volumes · ap-south-1 · $2,704.64/month

1 decision

Pooling is by account, region, rule and resource, because a resource id is not globally unique. The individual resources stay attached to the row and export with it.

2,113 volumes is one decision, not 2,113 rows

Findings pool by the action they require, so a queue of near-identical volumes arrives as a single priced line with the count, the total size and the saving. The individual resources are still there underneath, keyed by account, region, rule and resource, for the engineer who has to act.

Read-only, by construction

Kostrix never deletes a volume or a snapshot. The IAM policy it runs under holds no ec2:DeleteVolume, no ec2:DeleteSnapshot and no other mutating action; it is published in full on the security page. You delete, in your own console, with your own audit trail.

Find the unused volumes in your own account: 30 days free.