Turn off/on EC2 instances on schedule

Ed Reinoso
4 min readJul 15, 2020

--

Before reading

  • Lambda functions need IAM permissions to interact with other services.
  • Best practice is to allow only the permissions necessary for functions to work with other services.

Tech Stack

Similar to the previous automation articles, the tech stack to accomplish this tool is the following:

  • AWS Lambda
  • Python using Boto3
  • AWS CloudWatch

Once again, the purpose of this article is not to give a thorough explanation from these services, but rather to provide their applied use cases. The main functions that will be used from Boto3 are:

ec2.describe_instances(),
ec2.start_instances(),
ec2.stop_instances()

Goal

One of the best ways to minimize cost in AWS is by turning off instances that do not have a critical workload when they are not being used. This is particularly useful in lower environments when a proof of concept needs to be done for quicker tests in upper environments.

If instances are left on the running state 24/7, the bill could tend to be very high depending on the EC2 type. Obviously, the higher the instance, the more expensive it is going to be.

Hence, the best solution to adopt in these situations is to have a strategy to turn on and off instances during a certain period of time when they are not needed. Normally, it is best to turn instances off at night, while not being used, and turn them back on in day time.

Permissions

Since I have not discussed the IAM permissions in any of the previous articles, it is important to dedicate a small section before actually proceeding to the main logic of the function.

Permissions are what make Lambda functions work with other services, in this case EC2. Within itself, IAM permissions is a sea of complexity. However, best practice is to always have only the minimum permission possible. Here is a small example of how this can be applied to this function specifically:

1. Login to AWS console
2. Go to IAM service
3. Click on Policies: will allow certain actions to be taken on other services
3.a. Select JSON and paste the following JSON script

{
“Version”: “2012–10–17”,
“Statement”: [
{
“Sid”: “VisualEditor0”,
“Effect”: “Allow”,
“Action”: [
“ec2:StartInstances”,
“ec2:StopInstances”
],
“Resource”: “*”
}
]
}

4. Click on Policies: need to create this with the policy from Step 3
4.a. Among the options for use case, select Lambda
5. Go to Lambda service
6. Create a new Lambda function with the role specified on Step 4

This is just an example on how creating a policy/role works for this specific automation tool. Managing IAM permissions can be a full time job since there’s a whole world behind these policies and roles. I will certainly leave some reference to this topic down below.

Logic

These are the general steps:

Step 1: Filtering

This step will be in charge of filtering EC2 instances that need to be turn off/on based on their tag key/value pair. So for instance, let’s say that for the purpose of reducing cost, there’s a requirement to turn off EC2 instances that have a Tag key as Critical and a value as None. Then in the scheduling step, we can specify these attributes to be passed to the functions as events.

Step 2: Scheduling

This step will make sure that these events are executed on a regular basis based on the timeframe that we set in CloudWatch. The way data is passed to lambda functions is by configuring JSON inputs into the events. Hence, functions will be able to filter out instances by doing step 1.

Note: in order to turn on and off instances, two CloudWatch events are required. One that would be in the evening- for shutting down, and one in the morning- for bringing them up

This should be the mental map that needs to be followed in order to understand this event data passing:

Step 3: Turning on/off

This step is the most important part of the function since it will carry the actual execution on starting/stopping instances based on the previous two steps above. One thing to notice is that there are two separate classes, start.py and stop.py, which will be in charge of the action that the function will carry.

It is also important to know that an attribute “action” should be placed inside of the JSON input configuration when creating the CloudWatch event. The code will need to determine with an If-else statement whether this “action” is a start or stop.

Complete code 💻

Start.py

Stop.py

Reference

AWS IAM Permissions: https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction_access-management.html

AWS Lambda: https://docs.aws.amazon.com/lambda/latest/dg/welcome.html

AWS CloudWatch Events: https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/WhatIsCloudWatchEvents.html

Boto3: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html

Github: https://github.com/edreinoso/aws_devops/tree/master/start-stop/pi-stop-start-ec2

--

--

Ed Reinoso

Cloud Engineer with a passion for AWS automation