Automating AWS EC2 Management with AWS SDK Python Boto3, Lambda and CloudWatch Rule

A comprehensive EC2 management with Boto3 and Lambda

Paul Zhao
Paul Zhao Projects
32 min readMar 1, 2021

--

What is AWS SDK for Python (Boto3) ?

You use the AWS SDK for Python (Boto3) to create, configure, and manage AWS services, such as Amazon Elastic Compute Cloud (Amazon EC2) and Amazon Simple Storage Service (Amazon S3). The SDK provides an object-oriented API as well as low-level access to AWS services

Why using it?

To fully take advantage of Python’s automation in AWS EC2 management, we’ll be exploring the power of Boto3

In this project, we will be touching upon almost all aspects of EC2 management. We’ll starting from single task based project such as how to manage start, stop your EC2 all the way to using Linux crontab to automate the whole process and even more to deploying Lambda Function using CloudWatch rule and more…

Project Infrastructure

Prerequisites

For this walkthrough, you need the following:

  • An AWS account — with non-root user (take security into consideration)
  • In terms of system, we will be using RHEL 8.3 by Oracle Virtual Box on Windows 10 using putty
  • AWSCLI installed
  • Install Terraform

Let us work on them one by one.

Creating a non-root user

Based on AWS best practice, root user is not recommended to perform everyday tasks, even the administrative ones. The root user, rather is used to to create your first IAM user, groups and roles. Then you need to securely lock away the root user credentials and use them to perform only a few account and service management tasks.

Notes: If you would like to learn more about why we should not use root user for operations and more about AWS account, please find more here.

Login as a Root user
Create a user under IAM service
Choose programmatic access
Choose programmatic access
Create user without tags
Keep credentials (Access key ID and Secret access key)

Set up RHEL 8.3 by Oracle Virtual Box on Windows 10 using putty

First, we will download Oracle Virtual Box on Windows 10, please click Windows hosts

Second, we will also download RHEL iso

Let us make it work now!

Click Oracle VirtualBox and open the application and follow instructions here, you will install RHEL 8.3 as shown below

Oracle VM VirtualBox

Notes: In case you are unable to install RHEL 8.3 successfully, please find solutions here. Also, after you create your developer’s account with Red Hat, you have to wait for sometime before register it. Otherwise, you may receive errors as well.

Now it’s time for us to connect to RHEL 8.3 from Windows 10 using VirtualBox.

Login RHEL 8.3

Click activities and open terminal

Open terminal

Notes: In order to be able to connect to RHEL 8.3 from Windows 10 using putty later, we must enable what it is shown below.

Bridged Adapter selectedBridged Adapter selected

Now we will get the ip that we will be using to connect to RHEL 8.3 from Windows 10 using Putty (highlighted ip address for enp0s3 is the right one to use)

IP address

Then we will install Putty.

ssh-keygen with a password

Creating a password-protected key looks something like this:

To find out private key

Notes: You may take advantage of GUI of RHEL to send Private Key as an email, then open the mail and copy the private key from email

Open the Notepad in Windows 10 and save private key as ansiblekey.pem file

Ansiblekey.pem

Then open PuTTY Key Generator and load the private key ansiblekey.pem

Load private key in putty key generator

Then save it as a private key as ansible.ppk file

We now open Putty and input IP address we saved previously as Host Name (or IP address) 192.168.0.18

Load private key in putty

We then move on to Session and input IP address

IP address saved

For convenience, we may save it as a predefined session as shown below

Saved session

You should see the pop up below if you log in for the very first time

First time log in

Then you input your username and password to login. You see below image after log in.

Login successfully

Installing AWS CLI

To install AWS CLI after logging into Redhat8

To verify the installation

To use aws cli, we need to configure it using aws access key, aws secret access key, aws region and aws output format

Installing Terraform

To install terraform, simply use the following command:

Install yum-config-manager to manage your repositories.

Use yum-config-manager to add the official HashiCorp Linux repository.

Install terraform

Notes: In case of a wrong symbolic link set up, please check out this link. Also, you may need to re login after changing the symbolic link.

To check out installation of terraform

For advanced user, please adopt either CloudFormation or Terraform as infrastructure as code (Iac) to create EC2 instance

First, we will be terraforming one instance

Terraforming EC2

After logging into REHL 8.3 via Putty on Windows 10, we will make a folder named ubuntu-instance

vim ubuntu.tf

Then we need to generate a keypair to use from our RHEL 8.3

To use this keypair to logging into our instance later, we need to cp them from default path to our current folder

Since we apply our public key as public_key = file("key.pub") in our ubuntu.tf file, we need rename our id_rsa.pub as key

Next terraform init

After that, terraform validate

terraform plan to plan our infrustructure

Lastly, terraform apply

Double check ubuntu instance created in AWS console

Ubuntu instance created

Notes: Terraform may not be able to provision Amazon Linux instances at this point. I tested multiple Amazon Linux instances. As soon as they were provisioned, they were stopped sponteneously. So please don’t terraform your Amazon Linux instances

Now we may begin working on our project in this EC2 intance

To describe all EC2 instnaces and create file awssutils.py

vim awssutils.py

Execute the file awssutils.py

To Retrieving EC2 Instance Details

Create ec2_instance.py

vim ec2_instance.py

Execute Python ec2_instance.py

To find out instance ami id in case you may need

Create ec2_instance_ami_id.py file

vim ec2_instance_ami_id.py

Execute Python file ec2_instance_ami_id.py

To stop EC2 instance created previously

Create ec2_instance_stop.py file

vim ec2_instance_stop.py

Execute Python file ec2_instance_stop.py

Cross check in AWS Console

ubuntu instance stopped

To start EC2 instance created previously

Create ec2_instance_start.py file

vim ec2_instance_start.py

Execute Python file ec2_instance_start.py

Cross check in AWS consle

ubuntu instance started

Alternative Approach to Fetching, Starting, and Stopping

In addition to the EC2.Client class that we've been working with thus far, there is also a EC2.Instance class that is useful in cases such as this one where I only need to be concerned with one instance at a time

To stop EC2 instance created previously

Create ec2_instance_stop_alternative.py file

vim ec2_instance_stop_alternative.py

Execute Python file ec2_instance_stop.py

Cross check in AWS Console

ubuntu instance stopped

To start EC2 instance created previously

Create ec2_instance_start_alternative.py file

vim ec2_instance_start_alternative.py

Execute Python file ec2_instance_start_alternative.py

Cross check in AWS consle

ubuntu instane started

Creating a Backup Image of an EC2.Instance

Create ec2_instance_ami.py file

vim ec2_instance_ami.py

Execute Python file ec2_instance_ami.py

Cross check in AWS consle

Instance ami created

Alternative Approach to Copying EC2 Instance

Create ec2_instance_ami_alternative.py

vim ec2_instance_ami_alternative.py

Execute Python file ec2_instance_ami_alternative.py

Cross check in AWS consle

instance ami created with alternative

Tagging Images of EC2 Instances

Create ec2_instance_tagging.py

vim ec2_instance_tagging.py

Execute Python file ec2_instance_tagging.py

Cross check in AWS consle

Tagging ami of instance

Creating an EC2 Instance from a Backup Image

Create ec2_instance_new_from_ami.py

vim ec2_instance_new_from_ami.py

Execute Python file ec2_instance_new_from_ami.py

Cross check in AWS consle

New instance from ami up running

Removing Backup Images

Create ec2_instance_remove_ami.py

vim ec2_instance_remove_ami.py

Execute Python file ec2_instance_new_from_ami.py

Cross check in AWS consle

Remove ami tagged

Terminating EC2 Instance

Create ec2_instance_terminate.py

vim ec2_instance_terminate.py

Execute Python file ec2_instance_terminate.py

Cross check in AWS consle

EC2 Instance termiated

Here is the script that backup core ec2 instance for DR. We can run a script to call AWS API, it check the tag of instances to decide if need to take snapshot for backup. And clean up the expired snapshot.

Usage of this script: Set up tags for the instances which need to backup, example : key — backup value — 7. This means backup the server every day and keep 7 snapshot at most. Here will be using our local environment which is Redhat 8 (However, I’ll be diving deep into other crontab options in my post ahead, stay tune!)

vim Ec2BackUpCleanUp.py

Notes: We can definitely put our AWS_ACCESS_KEY and AWS_SECRET_KEY straightly into this file. However, for security and efficiency, we provide with os.envrion[‘AWS_ACCESS_KEY’] and os.envrion[‘AWS_SECRET_KEY’] respectively.

In case you would like execute this .py file straight, we need to do like below in Redhat 8 command line

Here are the real meets: Cronjob using Crontab

First, we need to get access to our crobtab in Redhat 8

Notes: In case this command line doesn’t work, please refer to this post as reference

Using Linux cronjob to excecute this file at 15:16 pm every day

Above is what we need to type into the file opened by crontab -e in Redhat 8

Notes: AWS credentials must be provided in this file to make it work. Also, for more about how to set up the scheduled time in crontab, please refer to this post

finally, the cronjob is set up

Cross check in AWS console at 15:16 pm

Notes: As we introduced previously, we set up tag name for our instance as backup and value of it as 1 in my case. What this means is that, ami will be backed up once at most. Since 3 days were configured for snapshot as default, which indicates that snapshot will be deleted after 3 days

ami created by crontab
Snapshot created by crontab

AWS Lambda Implementation

Now let us do our EC2 back up and clean up using AWS Lambda Function to accomplish serverless EC2 management

To start with, create a file named ec2backup.py

vim ec2backup.py

Then, we need to create an IAM role and attach AWSLambdaBasicExecutionRole to it as shown below

Since Lambda function can’t execute .py file straight, we need to zip it as shown below

Now we will create a Lambda function using AWS CLI shown below

Notes: For python, lambda handler should be set up as <file name>.lambda_handler. For more reference, please visit here

Moving along, we need to create our trigger, here we will be using AWS CLI as we follow along with Iac. However, you are free to use AWS console

We create a CloudWatch rule as shown below

Notes: For more about CloudWatch Cronjob, please refer to this AWS document

Notes: Permission must be added to allow Lambda Function to be triggered by CloudWatch since we created our Lambda Function using AWSCLI. For more reference, please visit here

Then we need to set a targets for the rule

Notes: For the above IAM role and Lambda Function creation, you may refer to AWS documents here in case of any issues

Cross check in AWS console

Lambda function with eventbridge as trigger
CloudWatch rule page — backup
Ami with tag created upon time scheduled
Snapshot with tag created upon time scheduled

Notes: If your Lambda Function is not working to create EC2 AMI, please adjust Basic settings for time out, default 3 seconds should be increased to 1 min 3 seconds.

Now we will be kicking off our AMI cleanup process by creating a file named ec2cleanup.py

vim ec2cleanup.py

Then, we need to create an IAM role and attach AWSLambdaBasicExecutionRole to it as shown below (You may not need to go over this again since we already made it while applying ec2backup.py)

Since Lambda function can’t execute .py file straight, we need to zip it as shown below

Now we will create a Lambda function using AWS CLI shown below

Notes: For python, lambda handler should be set up as <file name>.lambda_handler. For more reference, please visit here

Moving along, we need to create our trigger, here we will be using AWS CLI as we follow along with Iac. However, you are free to use AWS console

We create a CloudWatch rule as shown below

Notes: For more about CloudWatch Cronjob, please refer to this AWS document. Also, upon updating your schedule, you must use AWSCLI. I tried to make adjustment manually, it wouldn’t work

Notes: Permission must be added to allow Lambda Function to be triggered by CloudWatch since we created our Lambda Function using AWSCLI. For more reference, please visit here

Then we need to set a targets for the rule

Notes: For the above IAM role and Lambda Function creation, you may refer to AWS documents here in case of any issues

Cross check in AWS console

Lambda function with eventbridge as trigger
CloudWatch rule page — cleanup
Ami with tag created upon time scheduled
Snapshot with tag created upon time scheduled
Manually adjust time to test cleanup
Before the time scheduled
Upon cleaning up

Notes: If your Lambda Function is not working to clean up ami scheduled, please adjust Basic settings for time out, default 3 seconds should be increased to 1 min 3 seconds.

As a bonus, we will be touching upon our Snapshot cleanup process by creating a file named snapshotcleanup.py

vim snapshotcleanup.py

snapshotcleanup.py

Then, we need to create an IAM role and attach AWSLambdaBasicExecutionRole to it as shown below (You may not need to go over this again since we already made it while applying ec2backup.py)

Since Lambda function can’t execute .py file straight, we need to zip it as shown below

Now we will create a Lambda function using AWS CLI shown below

Notes: For python, lambda handler should be set up as <file name>.lambda_handler. For more reference, please visit here

Moving along, we need to create our trigger, here we will be using AWS CLI as we follow along with Iac. However, you are free to use AWS console

We create a CloudWatch rule as shown below

Notes: For more about CloudWatch Cronjob, please refer to this AWS document. Also, upon updating your schedule, you must use AWSCLI. I tried to make adjustment manually, it wouldn’t work

Notes: Permission must be added to allow Lambda Function to be triggered by CloudWatch since we created our Lambda Function using AWSCLI. For more reference, please visit here

Then we need to set a targets for the rule

Notes: For the above IAM role and Lambda Function creation, you may refer to AWS documents here in case of any issues

Cross check in AWS console

Lambda function with eventbridge as trigger
CloudWatch rule page — snapshocleanup
Snapshots
Snapshot deleted

Notes: If your Lambda Function is not working to clean up snapshot, please adjust Basic settings for time out, default 3 seconds should be increased to 1 min 3 seconds.

Last but not least, we’ll have free give-aways — automate your EC2 server updates using SSM in Boto3 and CloudWatch cron expression

Firstly, since we need to gain access to our EC2 server to check out our installation and update, let us provision a new Linux EC2 using CloudFormation

Create Amazon Linux 2 AMI instance using CloudFormation

CloudFormation yaml file is provided below

vim amazonlinux2ami.yml

Notes: In order to gain access to Amazonlinux 2 instance, we may need to create key pair using AWS CLI before generating CloudFormation Stack

Using AWS CLI to provision Amazonlinux2 EC2 instance

Double check CloudFormation created

CloudFormation created
Amazonlinux2 instance created

Let now login to this server to check out if ansible and docker are preinstalled.

Notes: Here we’ll be applying 3 command lines to install both ansible and docker as well as update our server so that we can easily see that our Lambda Function is working

Notes: If using Putty, you need to save .pem file as .ppk file via Puttygen in order to gain access to EC2 server

Ec2 connect page
Load your .ppk key into putty

Under connection, then SSH, then Auth. Thereafter, input your hostname on port 22 to login to the EC2 server as shown below

Login Page

Both ansible and docker were not preinstalled

vim ec2_daily_update_targets.py

ec2_daily_update_targets.py

Notes: In case you wants to dive deep into How to Run Two or More Terminal Commands at Once in Linux , please visit the blog. It can be handy!

Then, we need to create an IAM role and attach AWSLambdaBasicExecutionRole to it as shown below (You may not need to go over this again since we already made it while applying ec2backup.py)

Since Lambda function can’t execute .py file straight, we need to zip it as shown below

Now we will create a Lambda function using AWS CLI shown below

Notes: For python, lambda handler should be set up as <file name>.lambda_handler. For more reference, please visit here

Moving along, we need to create our trigger, here we will be using AWS CLI as we follow along with Iac. However, you are free to use AWS console

We create a CloudWatch rule as shown below

Notes: For more about CloudWatch Cronjob, please refer to this AWS document. Also, upon updating your schedule, you must use AWSCLI. I tried to make adjustment manually, it wouldn’t work

Notes: Permission must be added to allow Lambda Function to be triggered by CloudWatch since we created our Lambda Function using AWSCLI. For more reference, please visit here

Then we need to set a targets for the rule

Notes: For the above IAM role and Lambda Function creation, you may refer to AWS documents here in case of any issues

To this moment, our game is not done yet. In order to make it work. We need to install SSM agent in our EC2 server. Also we need to grant permission for our resource group. Both of them are going to be invoked by Lambda Function upon time scheduled

Firstly, install SSM agent in our EC2 server (In case that SSM agent was preinstalled)

Secondly, we need to create a policy for our user to gain access to resource group since our Lambda Function requires SSM and resource groups are used for targets

Create a policy file named resourcegrouppolicy.json

vim resourcegrouppolicy.json

Create this policy using the file

We need to attach this policy to our user

Policy attached to our current user

Lastly, we need to attach IAM role with SSM access to EC2 instance in order to allow SSM to manage our EC2 instance (in our case, we’ll be installing a few tools and updating our server)

Notes: Here I attempted to use AWSCLI to create the role and attach the role to EC2 instance. However, the error occured upon creating the role. So I used AWS console to bypass this issue for now.

Please create the role and attach those 2 policies shown below

Role with 2 policies attached

Upon the time scheduled, we ssh to our EC2 server to check out if commands in Lambda Functions were executed

All commands were successfully executed!

Notes: If your Lambda Function is not working to clean up snapshot, please adjust Basic settings for time out, default 3 seconds should be increased to 1 min 3 seconds.

Cleanup:

Before jumping into conclusion, do not forget to terminate our infrastructure. For the instructure created using CloudFormation, we can easily delete the stack using AWS CLI or in AWS console. The infrastructure create by CloudFormation will be removed accordingly. EC2 instance provisioned by Terraform, on the other hand, would be terminted by simply applying terraform destroy. Last but not least, those infrastructure created by AWSCLI needs to be removed either by AWSCLI or inside AWS console. With that said, we can easily tell the power of Iac with Terraform as well as CloudFormation. To provision without hassle and to clean up without hassle either

Conclusion:

Let us recap our project. Below are tasks we accomplish throughout our projects using AWS SDK for Python Boto3

To describe all EC2 instances and create file awssutils.py

To Retrieving EC2 Instance Details

To find out instance ami id in case you may need

To stop EC2 instance created previously

To start EC2 instance created previously

Alternative Approach to Fetching, Starting, and Stopping

To stop EC2 instance created previously

To start EC2 instance created previously

Creating a Backup Image of an EC2.Instance

Alternative Approach to Copying EC2 Instance

Tagging Images of EC2 Instances

Creating an EC2 Instance from a Backup Image

Removing Backup Images

Terminating EC2 Instance

Local Cronjob from Linux

Here is the script that backup core ec2 instance for DR. We can run a script to call AWS API, it check the tag of instances to decide if need to take snapshot for backup. And clean up the expired snapshot

Project Infrastructure

Based on this project infrastructure, we’ll be reiterating our Lambda Function part.

Firstly, by using Cron Expression in AWS CloudWatch rule, we can trigger Lambda at any scheduled time. In this project, we tested at a certain time per day. This trigger can be set up using either AWSCLI or AWS Console. Secondly, the Lambda Function scripted using AWS SDK for Python — Boto3 implements a number of jobs

  • Back up EC2 AMI
  • Update System
  • Clean up EC2 AMI
  • Clean up Snapshot

Final words: This project showcases the power of Python in Automation, especially in terms of EC2 Management in AWS

--

--

Paul Zhao
Paul Zhao Projects

Amazon Web Service Certified Solutions Architect Professional & Devops Engineer