Skip to content

How do I use Lambda to stop and start Amazon EC2 instances at regular intervals?

5 minute read
3

I want to automatically stop and start my Amazon Elastic Compute Cloud (Amazon EC2) instances to reduce my Amazon EC2 usage.

Short description

Use AWS Lambda and Amazon EventBridge to automatically stop and start EC2 instances.

Note: The following resolution is a simple example solution. For a more advanced solution, use Instance Scheduler on AWS. For more information, see Automate starting and stopping AWS instances.

To use Lambda to stop and start EC2 instances at regular intervals, complete the following steps:

  1. Create a custom AWS Identity and Access Management (IAM) policy and IAM role for your Lambda function.
  2. Create Lambda functions that stop and start your EC2 instances.
  3. Test your Lambda functions.
  4. Create EventBridge schedules that run your function on a schedule.

Sometimes, a Lambda function stops an instance and can't start it again. This occurs when an Amazon Elastic Block Store (Amazon EBS) volume is encrypted, and the Lambda role isn't authorized to use the encryption key. For more information, see Required AWS KMS key policy for use with encrypted volumes.

Resolution

Prerequisite: Get the IDs of the EC2 instances that you want to stop and start.

Create an IAM policy and role for your Lambda function

Complete the following steps:

  1. Use the JSON policy editor to create an IAM policy. Enter the following JSON policy document into the policy editor:

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "logs:CreateLogGroup",
                    "logs:CreateLogStream",
                    "logs:PutLogEvents"
                ],
                "Resource": "arn:aws:logs:*:*:*"
            },
            {
                "Effect": "Allow",
                "Action": [
                    "ec2:Start*",
                    "ec2:Stop*"
                ],
                "Resource": "*"
            }
        ]
    }
  2. Create an IAM role for Lambda.

  3. Attach the IAM policy to the IAM role.

Note: If you use an Amazon Elastic Block Store (Amazon EBS) volume, then additional configuration might be required. If the Amazon EBS volume is encrypted with a customer-managed AWS Key Management Service (AWS KMS) key, then add kms:CreateGrant to the IAM policy.

Create Lambda functions that stop and start your instances

Complete the following steps:

  1. Open the Lambda console, and then choose Create function.

  2. Choose Author from scratch.

  3. Under Basic information, enter the following information:
    For Function name, enter a name that describes the function, such as StopEC2Instances or StartEC2Instances.
    For Runtime, choose Python 3.9.
    Under Permissions, expand Change default execution role.
    Under Execution role, choose Use an existing role.
    Under Existing role, choose the IAM role.

  4. Choose Create function.

  5. Choose the Code tab.

  6. On the lambda_funciton.py tab under Code source, enter the following code into the code editor to stop_instances:

    import boto3  
    region = 'us-west-1'
    instances = ['i-12345cb6de4f78g9h', 'i-08ce9b2d7eccf6d26']
    ec2 = boto3.client('ec2', region_name=region)
    
    def lambda_handler(event, context):
        ec2.stop_instances(InstanceIds=instances)
        print('stopped your instances: ' + str(instances))

    To start_instances, enter the following code into the code editor:

    import boto3  
    region = 'us-west-1'
    instances = ['i-12345cb6de4f78g9h', 'i-08ce9b2d7eccf6d26']
    ec2 = boto3.client('ec2', region_name=region)
    
    def lambda_handler(event, context):
        ec2.start_instances(InstanceIds=instances)
        print('started your instances: ' + str(instances))

    Note: Replace us-west-1 with the AWS Region that your instances are in and InstanceIds with the IDs of the instances that you want to stop and start.

  7. Choose Deploy.

  8. On the Configuration tab, choose General configuration, and then choose Edit.

  9. Set Timeout to 10 seconds, and then choose Save.

Test your Lambda functions

Complete the following steps:

  1. Open the Lambda console, and then choose Functions.
  2. Choose one of the functions.
  3. Choose the Code tab.
  4. In the Code source section, choose Test.
  5. In the Configure test event dialog box, choose Create new test event.
  6. Enter an event name, and then choose Create.
    Note: Don't change the JSON code for the test event.
  7. Choose Test to run the function.
  8. Repeat steps 1-7 for the other function.

Check the status of your instances

Amazon EC2 console

Before and after you test, check the status of your instances to confirm that your functions work.

CloudTrail

You can also use AWS CloudTrail to confirm that the Lambda function stopped or started the instance.

Complete the following steps:

  1. Open the CloudTrail console.
  2. In the navigation pane, choose Event history.
  3. On the Lookup attributes dropdown list, choose Event name.
  4. In the search bar, enter StopInstances to review the results. Then, enter StartInstances.

If there are no results, then the Lambda function didn't stop or start the instances.

Create EventBridge rules that run your Lambda functions

Complete the following steps:

  1. Open the EventBridge console.
  2. Choose Create rule.
  3. Enter a name for your rule, such as StopEC2Instances or StartEC2Instances.
  4. (Optional) For Description, enter a description for the rule.
  5. For Rule type, choose Schedule, and then choose Continue in EventBridge Scheduler.
  6. In the Schedule pattern, for Occurrence, choose Recurring schedule.
  7. For Schedule type, choose either rate-based schedule or cron-based schedule, and then complete one of the following steps:
    For Rate-based schedule, enter a rate value, and then choose an interval of time in minutes, hours, or days.
    -or-
    For Cron-based schedule, enter an expression that tells Lambda when to stop or start your instance.
    Note: Cron expressions are evaluated in UTC. Make sure that you adjust the expression for your time zone.
  8. On the Select targets page, choose Lambda function from the Target dropdown list.
  9. For Function, choose the function that stops or starts your instances.
  10. Choose Skip to review and create, and then choose Create.

Note: You can also create rules that react to events in your AWS account.

Related information

Tutorial: Create an EventBridge scheduled rule for AWS Lambda functions

Events from AWS services

Amazon EC2 billing and purchasing options

AWS OFFICIALUpdated a year ago
17 Comments

Wow, Thank you very much, I needed exactly that! Great guide and also thanks to Preetika!

replied 2 years ago

I am getting below error while creating lambda function although I followed exactly same steps for creating policy n role:

Request failed with status code 403

Please suggest on it

replied 2 years ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

AWS
MODERATOR
replied 2 years ago

Hi there, I read carefully this article and followed all instructions but I receive this error:

[ERROR] EndpointConnectionError: Could not connect to the endpoint URL: "https://ec2.eu-west-3c.amazonaws.com/"

I am trying to stop an instance on eu-west-3c but no way

Can anyone help me to understanf why ?

Thanks in advance, Vincenzo

replied 2 years ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

AWS
MODERATOR
replied 2 years ago

The Python code is incorrect. There needs to be a return before region

replied 2 years ago

@Dipti you have to choose the created Role in the Lambda function under Permissions

replied 2 years ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

AWS
MODERATOR
replied 2 years ago

Thank you for sharing

replied 2 years ago

Why do I need to have the below code block defined before the start of the function?

region = 'us-west-1'
instances = ['i-12345cb6de4f78g9h', 'i-08ce9b2d7eccf6d26']
ec2 = boto3.client('ec2', region_name=region)
replied 2 years ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

AWS
EXPERT
replied 2 years ago

This was super helpful and worked as advertised, following the step by step instructions for ca-central-1.

Thanks, Rick

replied 2 years ago

Thanks for the demo and blog. Deployed and tested.

replied a year ago

There seems to be some confusion on the trust relationship instructions to allow Lambda / Scheduler to access the manually created role. Following the instructions here gives an error: The execution role you provide must allow AWS EventBridge Scheduler to assume the role.

I think the issue is this step: Under Execution role, choose Use an existing role.

I tried instead to use the option to create a new role. The following was generated

Role: Amazon_EventBridge_Scheduler_LAMBDA_abcdef1234 Trust Relationship { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "scheduler.amazonaws.com" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals": { "aws:SourceAccount": "123456789012" } } } ] }

See https://docs.aws.amazon.com/scheduler/latest/UserGuide/setting-up.html for more info

replied a year ago

Hello! Just one error that I found when working with a customer and using this guide. For the code, should be formatted as follows:

import boto3
region = 'us-west-1'
instances = ['i-12345cb6de4f78g9h', 'i-08ce9b2d7eccf6d26']
ec2 = boto3.client('ec2', region_name=region)

def lambda_handler(event, context):
    ec2.stop_instances(InstanceIds=instances)
    print('stopped your instances: ' + str(instances))
import boto3
region = 'us-west-1'
instances = ['i-12345cb6de4f78g9h', 'i-08ce9b2d7eccf6d26']
ec2 = boto3.client('ec2', region_name=region)

def lambda_handler(event, context):
    ec2.start_instances(InstanceIds=instances)
    print('started your instances: ' + str(instances))

The region being on the same line as import boto3 was where we were running into errors. Simple fix, but thought I'd share for anyone in the future that maybe didnt catch it at first.

AWS
replied 9 months ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

AWS
MODERATOR
replied 9 months ago

can we still consider this solution over Instance Scheduler on AWS ? Will using this approach saves more as compared to built-in Instance Scheduler on AWS? Please suggest.

replied 8 months ago