Unused Amazon EBS volumes contribute to AWS costs. The lifecycle of EBS volumes can be independent of Amazon EC2 compute instances. Therefore, even if the EC2 instance associated with the EBS volumes is terminated, the EBS volumes tend to persist unless you select the Delete on Termination option at launch. Also, instances spun up and down as part of development and testing cycles may leave orphaned EBS volumes if there are no workflows in use to delete them automatically. These orphaned EBS volumes accrue charges while unattached.
In this post, we walk you through an automated process using a Lambda Function and SNS, to identify all the EBS volumes that are unused and detached from an EC2 instance.
Create an Amazon SNS topic
1- In the AWS Management Console, navigate to Simple Notification Service in your region of choice and create a topic. Provide a Name and accept all the default settings. Note the topic’s ARN, which you need in subsequent steps.
2- In the SNS console, create an email subscription for the SNS topic created in the above step 1.
Create a Iam role
1- Navigate to the IAM Console and create a role for Lambda function execution with the below JSON policy. This policy grants the Lambda function the basic Lambda execution role, the ability to send a SNS email, and the ability to access EC2 resources such as EBS volumes.
{ "Version": "2012-10-17", "Statement": [ { "Action": [ "ec2:Describe*" ], "Resource": "*", "Effect": "Allow", "Sid": "WorkWithInstances" }, { "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents", "logs:DescribeLogStreams" ], "Resource": "*", "Effect": "Allow", "Sid": "WorkWithLogGroup" }, { "Action": [ "sns:Publish" ], "Resource": "*", "Effect": "Allow", "Sid": "WorkWithSnsTopics" } ] }
Create an AWS Lambda function
1- Navigate to the Lambda console and create a function with following basic details as shown in the following screenshot:
- For Function name, enter UnusedEBSVolumeFinder.
- For Runtime, from the dropdown list, select Python 3.9.
- Under Permissions:
- For Execution role, from the dropdown list, select Use an existing role.
- For Existing role, select the role created in the previous step for the Lambda function.
- Choose Create Function.
2- Next, in the Lambda console of the newly created function, scroll down to the Environment variables section and enter the following key-value parameter, also shown in the following screenshot:
- For SNSTOPIC_ARN, provide the ARN of the SNS topic you created in step 1
3- Enter the following code to the Lambda function and then choose Deploy:
# Copyright 2021 Lotfi Waderni # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import json from os import getenv, environ import boto3 from datetime import datetime region = environ['AWS_REGION'] sns_topic_arn = getenv("SNSTOPIC_ARN") #define the connection ec2 = boto3.resource('ec2', region_name=region) sns = boto3.client('sns', region_name=region) #set the date to today today = datetime.now().date() def get_volumes(): #report header EbsReport = "The Following Ebs Volumes are Unused: \n" Number = 0 #collect all aws ebs volumes in a region volumes = ec2.volumes.all() for vol in volumes: if vol.state == "available": EbsReport = EbsReport + "- " + str(vol.id) + " - Size: " + str(vol.size) + " - Created: " + str(vol.create_time.strftime('%Y/%m/%d %H:%M')) + "\n" Number= Number + 1 #Send a report only if there are Unused ebs volumes if Number == 0: print ("Nothing to Report") else: response = sns.publish( TargetArn=sns_topic_arn, Message=EbsReport, Subject='Unused EBS Volumes Report: ' + str(today), MessageStructure='string', ) def lambda_handler(event, context): # TODO implement get_volumes() return
Schedule the Lambda Function
You can now schedule the Lambda function to be automatically invoked at your preferred frequency using a CloudWatch Events rule.
1- Navigate to the CloudWatch service console and in the left panel, under the Events option, select Rules. Choose Create Rule.
2- select the Schedule option and specify a Cron expression. You can use the following expression to trigger every day at 23:00 UTC: 0 23 * * ? *
3- In the Targets section, select the Lambda function created earlier for identifying unused EBS volumes, then choose Configure details.
4- Under Rule definition, specify a name and description, make sure the State is enabled, and then choose Create rule.
The Lambda function will now automatically get triggered every day to identify the unused EBS volumes and publish a notification to the SNS topic like the below.
Conclusion
In this post, we demonstrated how to identify automatically any unattached (unused) Elastic Block Store (EBS) volumes available in your AWS account and to consider removing them in order to lower the cost of your monthly AWS bill.