AWS Lambda & EventBridge | Deregister Unused AMI In Account On Weekly Basis And Notify Via Email
In this blog we are going to check for list of Unused AMI on weekly basis and deregister those AMI from account using AWS Lambda function in python.
Create Role For Lambda Using below Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"ec2:DescribeImages",
"ec2:DeregisterImage",
"ec2:DescribeInstances",
"ec2:DescribeTags",
"logs:*",
"ec2:DescribeImageAttribute",
"ec2:DescribeInstanceTypes",
"ec2:DescribeInstanceStatus"
],
"Resource": "*"
}
]
}
Create SNS Topic And Subscribe
- Open the Amazon SNS console, and then choose Topics from the navigation pane.
- Choose Create topic.
- For Name, enter a name for your topic[Notify-Unused-AMI].
- For Display name, enter a display name for your topic and choose create topic
- After topic creation click on the Subscriptions tab, choose Create subscription.
- For Protocol, choose Email -> For Endpoint, enter the email address where you want to receive the notifications -> Choose Create subscription.
- A subscription confirmation email is sent to the address you entered. Choose Confirm subscription in the email.
- When you click on confirm you will get below message which confirms your subscription
- Now go back to Topics->EC2-State-Change-Notify and you can see its status has changed from pending to confirmed. Note the SNS topic ARN you created. You use this topic when creating the EventBridge rule.
Create AWS Lambda Python Function To Find Unused AMI And Deregister it.
- Goto Lambda console and click on create function
- Select "Author From Scratch" , Function name = unused_ami, Runtime= Python and role we created with above policy attached to this blog and click on create function.
- Goto code editor and start writing the code.
- Python code in one module gains access to the code in another module by the process of importing it. The import statement combines two operations it searches for the named module, then it binds the results of that search to a name in the local scope.
import boto3
- We will invoke the client for EC2
ec2 = boto3.client('ec2')
- First we will call describe_instances() function to fetch list of all EC2 instances in our account and save the dictonary returned in variable, you can get the official documentation for this function here
instances = ec2.describe_instances()
- Lets create empty list to save image id's which are in use by instances.
def lambda_handler(event, context): used_ami = [] # Create empty list to save used ami
- Traverse through instances dictionary to fetch instance state [running/stopped]. If ec2 is in running state we will append Image ID of that EC2 to our empty list.
def lambda_handler(event, context): used_ami = [] # Create empty list to save used ami for reservation in instances['Reservations']: for instance in reservation['Instances']: state = instance['State'] state = (state['Name']) if state == 'running': used_ami.append(instance['ImageId'])
- Above code will result in duplicate values into the list, to remove duplicate values we will write below code
# Remove duplicate entries from list used_ami = list(set(used_ami))
- We will call now describe_images() function to get list of custom AMI from our account and save the returned dictionary in variable. You can view this function official documentation here
In areguments for this function we will filter image id's based on its state, if its in available state then only we will fetch it. Owners can be anyone of your choice [Amazon Web Services account IDs, self , amazon , and aws-marketplace]images = ec2.describe_images( Filters=[ { 'Name': 'state', 'Values': ['available'] }, ], Owners=['self'], )
- We will traverse returned dictionaty now from above function and fetch image id's and append them to our custom ami list.
# Traverse dictonary returned and fetch Image ID and append in list custom_ami = [] # Create empty list to save custom ami for image in images['Images']: custom_ami.append(image['ImageId'])
- Now we will check if custom ami id's that we have with used ami list. If its not available in used ami list we will dregister the AMI using deregister_image(ImageId='string') function, you can get the official documentation for this function here
deregister_list = [] for ami in custom_ami: if ami not in used_ami: print("AMI {} has been deregistered".format(ami)) ec2.deregister_image(ImageId=ami) deg = ("-----Unused AMI ID = {} is Deregistered------".format(ami)) deregister_list.append(deg)
- Now we will use publish() function to send email with list of ami ids and configure the email message and subject accordingly, you can get the official documentation for this function here
To view entire github code please click heresns_client = boto3.client('sns') sns_client.publish( TopicArn='<SNS Topic ARN>', Subject='Alert - Unused AMI's Is Deregistered', Message=str(deregister_list) ) return "success"
Using Amazon EventBridge Schedule Lambda On Weekly Basis
- Open Amazon Eventbridge service and open rules. And click on create rule
- Now we will create rule and schedule it. For scheduling you we will have to use cron expression as displayed below. You can find official documentation here
- Now lets create our rule to start EC2 instance. First we will define name and description as below
- Now we will define Cron job expression where we will define that this job should run on 11 am IST only on saturday . Expression would be
0 11 ? * 7 *
- Select target as the lambda function and select our lambda function to start EC2 instance and click on create.
Youtube Tutorial
Resource Cleanup
- Delete EventBridge Rule.
- Delete Lambda
- Delete SNS Topic
- Delete Role Created for Lambda
Conclusion
In this blog we are going to check for list of Unused AMI on weekly basis and deregister those AMI from account using AWS Lambda function in python to save cost.
Stay tuned for my next blog.....
So, did you find my content helpful? If you did or like my other content, feel free to buy me a coffee. Thanks.
ย