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

6 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 Amazon EC2 instances.

Note: The following resolution is a simple example solution. For a more advanced solution, use the AWS Instance Scheduler. 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.
    Note: You can also create rules that react to events in your AWS account.

Resolution

Note: After you complete the following steps, you might receive a Client error on launch error. For more information, see When I start my instance with encrypted volumes attached, the instance immediately stops with the error "client error on launch."

Get the IDs of the EC2 instances that you want to stop and start. Then, complete the following steps.

Create an IAM policy and IAM role for your Lambda function

  1. Use the JSON policy editor to create an IAM policy. Paste 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.
    Important: When you attach a permissions policy to Lambda, make sure that you choose the IAM policy.

Note: If you use an Amazon Elastic Block Store (Amazon EBS) volume that's encrypted by 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

  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".
    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. On the Code tab, under Code source, paste the following code into the editor pane of the code editor on the lambda_function tab. This code stops the instances that you identify:
    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))
    Replace us-west-1 with the AWS Region that your instances are in. Replace InstanceIds with the IDs of the instances that you want to stop and start.
  6. Choose Deploy.
  7. On the Configuration tab, choose General configuration, and then choose Edit.
  8. Set Timeout to 10 seconds, and then choose Save.
    Note: (Optional) You can adjust the Lambda function settings. For example, to stop and start multiple instances, you might use a different value for Timeout and Memory.
  9. Repeat steps 1-7 to create another function. Complete the following steps so that this function starts your instances:
    In step 3, enter a different Function name. For example, "StartEC2Instances".
    In step 5, paste the following code into the editor pane of the code editor on the lambda_function tab:
    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))

          Use your Region and the same instances IDs.

Test your Lambda functions

  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. 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

AWS Management Console

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

CloudTrail

To confirm that the Lambda function stopped or started the instance, use AWS CloudTrail to check for events.

  1. Open the CloudTrail console.
  2. In the navigation pane, choose Event history.
  3. Choose the Lookup attributes dropdown list, and then 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

  1. Open the EventBridge console.
  2. Select Create rule.
  3. Enter a name for your rule, such as "StopEC2Instances". (Optional) In Description, enter a description for the rule.
  4. For Rule type, choose Schedule, and then choose Continue in EventBridge Scheduler.
  5. For Schedule pattern, choose Recurring schedule.
  6. Under Schedule pattern, for Occurrence, choose Recurring schedule.
  7. For Schedule type, choose a schedule type, and then complete 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 your instance. For information on expression syntax, see Creating an Amazon EventBridge rule that runs on a schedule.
    Note: Cron expressions are evaluated in UTC. Make sure that you adjust the expression for your time zone.
  8. In Select targets, choose Lambda function from the Target dropdown list.
  9. For Function, choose the function that stops your instances.
  10. Choose Skip to review and create, and then choose Create.
  11. Repeat steps 1-10 to create a rule to start your instances. Complete the following steps:
    Enter a name for your rule, such as "StartEC2Instances".
    (Optional) In Description, enter a description for your rule, such as "Starts EC2 instances every morning at 7 AM."
    In step 7, for Cron expression, enter an expression that tells Lambda when to start your instances.
    In step 9, for Function, choose the function that starts your instances.

Note: 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 and Key policies in AWS KMS.

Related information

Tutorial: Schedule AWS Lambda functions using EventBridge

Events from AWS services

Adding stop actions to Amazon CloudWatch alarms

Instance purchasing options

AWS OFFICIAL
AWS OFFICIALUpdated a year ago
14 Comments

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

Phill
replied a year 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

Dipti
replied a year ago

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

profile pictureAWS
MODERATOR
replied a year 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 a year ago

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

profile pictureAWS
MODERATOR
replied a year ago

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

nrawal
replied a year ago

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

nrawal
replied a year ago

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

profile pictureAWS
MODERATOR
replied a year ago

Thank you for sharing

profile picture
ilyes
replied a year 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)
Jas
replied 8 months ago

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

profile pictureAWS
MODERATOR
replied 8 months ago

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

Thanks, Rick

profile picture
replied 7 months ago

Thanks for the demo and blog. Deployed and tested.

Atiq
replied a month 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

Paul
replied a month ago