🚀 Executive Summary
TL;DR: Orphaned AWS EBS volumes accumulate unnecessary costs after EC2 instance termination. A Boto3 Python script automates the identification and deletion of these ‘available’ volumes, significantly cutting AWS bills and eliminating tedious manual cleanup.
🎯 Key Takeaways
- Automating unused AWS EBS volume deletion with Boto3 significantly reduces cloud costs and manual toil.
- A secure IAM policy granting `ec2:DescribeVolumes` and `ec2:DeleteVolume` is essential, adhering to the principle of least privilege.
- Implement a ‘dry run’ mode and a tag-based safety check (e.g., ‘Protected: True’) in the script to prevent accidental deletion of critical volumes.
- The script is region-specific; it must be executed for each AWS region where unused volumes exist.
- Schedule the automation using cron jobs on a management server or, preferably, via AWS Lambda triggered by Amazon EventBridge for a serverless approach.
Automate Unused AWS EBS Volume Deletion with Boto3
Hey there, Darian Vance here. Let’s talk about something that used to be a real thorn in my side: orphaned EBS volumes. You know the ones—they get detached from an EC2 instance that’s been terminated, and then they just sit there, quietly racking up costs. I used to spend a couple of hours every month manually combing through the AWS console to find and delete these. It was a tedious, error-prone process. That is, until I realized a simple Python script could do the job for me in seconds. Automating this wasn’t just a time-saver; it was a direct cut to our monthly AWS bill.
So, if you’re tired of that manual cleanup, let’s walk through how to build a reliable, automated solution using Boto3. This is a set-and-forget script that will save you time and money.
Prerequisites
Before we dive in, make sure you have the following ready:
- An AWS Account with permissions to manage IAM and EC2.
- Python 3 installed on your system.
- The Boto3 library. If you don’t have it, you can install it using pip. I’m going to skip the usual virtual environment setup and installation commands, as I’m sure you have your preferred way of managing Python projects. Let’s get straight to the logic.
- AWS Credentials configured. The script will pick them up automatically if you’ve run `aws configure` or have them set as environment variables.
The Step-by-Step Guide
Step 1: Craft a Secure IAM Policy
First things first: security. We never want to run scripts with more permissions than they absolutely need. This is the principle of least privilege in action. For this task, we need a policy that allows our script to describe volumes to find the unused ones, and then delete them. Nothing more.
Create an IAM policy with the following JSON. I recommend attaching this policy to a dedicated IAM user or role that will be used exclusively for this automation.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:DescribeVolumes"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ec2:DeleteVolume"
],
"Resource": "arn:aws:ec2:*:*:volume/*"
}
]
}
Step 2: The Python Script – Identifying and Deleting
Now for the fun part. We’ll write a Python script that connects to AWS, finds volumes in the `available` state (meaning they aren’t attached to any instance), and then deletes them. I’ve added plenty of comments to explain what’s happening at each stage.
Pro Tip: Implement a “Dry Run” Mode
In my production setups, I always build a “dry run” feature. The first time you run the script, you don’t want it to actually delete anything. You just want a list of what it would have deleted. This gives you a chance to sanity-check the output and make sure you aren’t about to remove a critical, temporarily-detached volume.
Here’s the complete script. Save this as something like `cleanup_ebs.py`.
import boto3
# --- Configuration ---
# Set to False to actually delete the volumes.
# Set to True to only print which volumes would be deleted.
DRY_RUN = True
AWS_REGION = "us-east-1" # Change this to your target region
def find_and_delete_unused_volumes(region):
"""
Finds all EBS volumes in the 'available' state and deletes them.
Includes a safety check for a 'do-not-delete' tag.
"""
ec2 = boto3.client('ec2', region_name=region)
print(f"Checking for unused EBS volumes in region: {region}...")
# We are looking for volumes that are not attached to any instance.
volumes = ec2.describe_volumes(
Filters=[
{
'Name': 'status',
'Values': ['available']
}
]
)
if not volumes['Volumes']:
print("No unused volumes found. All clean!")
return
for volume in volumes['Volumes']:
vol_id = volume['VolumeId']
tags = {tag['Key']: tag['Value'] for tag in volume.get('Tags', [])}
# --- CRITICAL SAFETY CHECK ---
# I always add a tag check to prevent accidental deletion.
# If a volume has a tag 'Protected' with value 'True', we skip it.
if tags.get('Protected') == 'True':
print(f"SKIPPING protected volume: {vol_id}")
continue
print(f"Found unused volume: {vol_id} ({volume['Size']} GiB)")
if DRY_RUN:
print(f"[DRY RUN] Would have deleted volume: {vol_id}")
else:
try:
print(f"DELETING volume: {vol_id}...")
ec2.delete_volume(VolumeId=vol_id)
print(f"Successfully deleted volume: {vol_id}")
except Exception as e:
print(f"Error deleting volume {vol_id}: {e}")
if __name__ == '__main__':
find_and_delete_unused_volumes(AWS_REGION)
Step 3: Scheduling the Automation
A script is only useful if it runs automatically. You have a few options here:
- Cron Job: For a simple setup, you can run this on a management server using cron. A weekly run is usually sufficient. Remember to set `DRY_RUN` to `False` in your script! A cron entry might look like this (no absolute paths needed if the script and python are in the system’s PATH):
`0 2 * * 1 python3 cleanup_ebs.py` - AWS Lambda: This is my preferred, cloud-native method. You can create a Lambda function with the Python code, assign it the IAM role we created earlier, and set up an Amazon EventBridge (CloudWatch Events) rule to trigger it on a schedule. It’s serverless, so you don’t need to manage a dedicated machine to run the script.
Common Pitfalls (Where I’ve Messed Up Before)
Trust me, I’ve made a few mistakes along the way. Here are the big ones to watch out for:
- Forgetting About Regions: The script is region-specific. If you operate in multiple AWS regions, you’ll need to run this script for each one. My example script can be easily modified to loop through a list of regions.
- Accidentally Deleting Important Volumes: A volume might be `available` because an engineer detached it for maintenance. This is why the tag-based safety check is non-negotiable for me. It provides a human override to the automation.
- IAM Permission Errors: If the script fails with an `AccessDeniedException`, it’s almost always a problem with the IAM policy. Double-check that the policy is attached to the user/role running the script and that it contains both `ec2:DescribeVolumes` and `ec2:DeleteVolume` actions.
Conclusion
And that’s it. With a small amount of setup, you’ve created a powerful automation that eliminates a tedious manual task, reduces the risk of human error, and directly saves money on your AWS bill. It’s a classic DevOps win: we’ve replaced manual toil with a reliable, automated process. Now you can use those hours you’ve saved on more important challenges.
Happy automating!
– Darian Vance
🤖 Frequently Asked Questions
âť“ How can I automate the deletion of unused AWS EBS volumes?
You can automate this using a Python script with Boto3 to list volumes in the ‘available’ state and then delete them. Ensure you have appropriate IAM permissions and incorporate safety features like a ‘dry run’ mode and tag-based protection.
âť“ How does automating EBS volume deletion compare to manual cleanup?
Automating EBS volume deletion with Boto3 is a set-and-forget solution that saves significant time, reduces human error, and directly cuts monthly AWS costs, unlike tedious and error-prone manual cleanup processes.
âť“ What is a common implementation pitfall when deleting EBS volumes?
A common pitfall is accidentally deleting important, temporarily-detached volumes. This can be mitigated by implementing a tag-based safety check (e.g., a ‘Protected: True’ tag) that the script respects, preventing deletion of critical volumes.
Leave a Reply