TL;DR: When an EC2 instance terminates, its root volume is deleted — but any additional volume defaults to DeleteOnTermination=false and lives on, invisible and billing, in "available" state. AWS never reminds you. Auto Scaling groups mass-produce these orphans. The fix is one boolean in your launch templates, plus a one-time sweep of what already leaked.
The numbers
- Ten forgotten 100 GB gp3 volumes: 10 × 100 × $0.08 = $80/month, $960/year — and that's a small shop.
- Teams with ASG churn routinely accumulate hundreds of orphans; real-world cleanups in the digest's source workflow dropped $400/month (startup, 40 orphans) and $2,000+/month (enterprise, 200+ orphans).
- Snapshots as a safety net cost ~$0.05/GB-month incremental — cheaper than keeping full volumes around "just in case."
Do this
-
Sweep existing orphans:
aws ec2 describe-volumes --filters Name=status,Values=available \ --query 'Volumes[].{id:VolumeId,size:Size,created:CreateTime,tags:Tags}'Triage by age and tags. Snapshot anything questionable, then delete. (Volumes older than 30 days with no owner tag are almost always dead weight.)
-
Stop making new ones — fix the source. In launch templates / Terraform / CloudFormation, set the flag on every non-stateful secondary volume:
ebs_block_device { device_name = "/dev/sdf" delete_on_termination = true } -
Fix already-running instances live (no reboot needed):
aws ec2 modify-instance-attribute --instance-id i-0abc... \ --block-device-mappings \ '[{"DeviceName":"/dev/sdf","Ebs":{"DeleteOnTermination":true}}]' -
Find the future orphans before they happen — attached volumes whose flag is off:
aws ec2 describe-instances --query 'Reservations[].Instances[]. BlockDeviceMappings[?Ebs.DeleteOnTermination==`false`]' -
Enforce it so it stays fixed: an AWS Config custom rule or a tfsec/OPA check in CI that flags non-prod instances launching with the flag off. Engineers forget; automation doesn't.
Gotchas
- The asymmetric default: root volume deletes, secondary volumes don't. That's deliberate on AWS's part ("don't destroy user data") — the cost of the caution is yours.
- No notifications exist. No email, no console nag. The only signal is the bill.
- Deregistering an AMI does not delete its snapshots — a related leak worth sweeping in the same audit.
- Blanket
trueis dangerous on stateful workloads. Decide by role, not by account.
Skip this if
…the volume genuinely should outlive its instance:
- Self-managed databases on EC2 (Postgres, Kafka, Elasticsearch) — termination shouldn't kill the data store; use snapshots/AWS Backup for lifecycle instead.
- Detach-and-reattach patterns (some blue/green deployments move a data volume to the new instance).
- Any data that can't be rebuilt and where a snapshot isn't an acceptable recovery path.
For everything else — dev, test, CI, stateless app servers — the flag should be true.