Skip to content

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

5 minute read
3

I want to use the Amazon EventBridge Scheduler to automatically stop and start my Amazon Elastic Compute Cloud (Amazon EC2) instances.

Short description

To automatically stop and start EC2 instances, use the EventBridge Scheduler to directly call the StartInstances and StopInstances Amazon EC2 APIs. Or, you can use the scheduler to invoke an AWS Lambda function to stop and start instance. It's a best practice to use Amazon EC2 APIs as the scheduler target to avoid the need to create additional Lambda functions.

For a more advanced solution, use the Instance Scheduler on AWS.

Resolution

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

Use the scheduler to directly call the Amazon EC2 APIs

Create an IAM policy and role for EventBridge Scheduler

Complete the following steps:

  1. Use the JSON policy editor to create an AWS Identity and Access Management (IAM) policy that allows EventBridge Scheduler to stop and start your instance.
    Example policy:
    {    
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "ec2:Start*",
                    "ec2:Stop*"
                ],
                "Resource": "*"
            }
        ]
    }
    Note: If you encrypted your Amazon Elastic Block Store (Amazon EBS) volume with a customer managed AWS Key Management Service (AWS KMS) key, then add kms:CreateGrant to the policy. If the Lambda function doesn't have access to the encryption key, then it can only stop but not restart the instance. For more information, see Required AWS KMS key policy for use with encrypted volumes.
  2. Open the IAM console.
  3. Choose Roles, and then choose Create role.
  4. For Trusted entity type, choose Custom trust policy.
  5. Enter the following IAM policy:
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": {
                    "Service": "scheduler.amazonaws.com"
                },
                "Action": "sts:AssumeRole",
                "Condition": {
                    "StringEquals": {
                        "aws:SourceAccount": "AWS_ACCOUNT_ID"
                    }
                }
            }
        ]
    }
    Note: Replace AWS_ACCOUNT_ID with your AWS account ID.
  6. Choose Next.
  7. For Permissions policies, select the IAM policy that you created in step 1.
  8. For Role name, enter a name such as EventBridge_Scheduler_Role.
  9. Choose Create role.

Create the EventBridge Scheduler schedule

Create a schedule for the StopInstances API and another for the StartInstances API. Configure the following settings when you create the schedule:

  • For Target API, select All APIs, and then search for Amazon EC2.
  • Select StopInstances or StartInstances, and then enter the instance IDs.
  • For Settings - optional, under Permissions, choose Select an existing role, and then choose the IAM role that you created.

Use the scheduler to invoke Lambda functions

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 that allows Lambda to stop and start your instance.
    Example policy:
    {    "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": "*"
            }
        ]
    }
    Note: If you use an Amazon EBS volume that's encrypted with a customer-managed AWS KMS key, then add kms:CreateGrant to the policy. If the Lambda function doesn't have access to the encryption key, then it can only stop but not restart the instance. For more information, see Required AWS KMS key policy for use with encrypted volumes.
  2. Create an IAM role for Lambda.
  3. Attach the IAM policy to the IAM role.

Create Lambda functions to stop and start your instances

Complete the following steps:

  1. Open the Lambda console.
  2. Choose Create function, and then choose Author from scratch.
  3. Under Basic information, configure the following settings:
    For Function name, enter a name that describes the function, such as StopEC2Instances or StartEC2Instances.
    For Runtime, choose Python 3.14.
    Under Permissions, expand Change default execution role.
    Under Execution role, choose Use an existing role.
    Under Existing role, choose the IAM role that you created.
  4. Choose Create function.
  5. Choose the Code tab, and then choose the lambda_funciton.py tab.
  6. For Code source, enter the following code into the code editor to configure the instance stop:
    import boto3  
    region = 'us-west-1'
    instances = ['i-12345acdb12345abcd', 'i-12345acdb12345abcd']
    ec2 = boto3.client('ec2', region_name=region)
    
    def lambda_handler(event, context):
        ec2.stop_instances(InstanceIds=instances)
        print('stopped your instances: ' + str(instances))
    To configure the instance start, enter the following code into the code editor:
    import boto3  
    region = 'us-west-1'
    instances = ['i-12345acdb12345abcd', 'i-12345acdb12345abcd']
    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 of your instances and i-12345acdb12345abcd with the IDs of your instances.
  7. Choose Deploy.
  8. Choose the Configuration tab, and then choose General configuration.
  9. Choose Edit.
  10. For Timeout, select 10 seconds, and then choose Save.

Note: If you associated the function with Amazon Virtual Private Cloud (Amazon VPC), then validate that the function can reach the Amazon EC2 endpoint through the internet. Or, configure a virtual private cloud (VPC) endpoint for Amazon EC2.

Test your Lambda functions

Test the Lambda functions for instance stop and for instance start.

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

To 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. In the Lookup attributes dropdown list, choose Event name.
  4. In the search bar, enter StopInstances to review the results. Then, enter StartInstances.
    Note: If there are no results, then the Lambda function didn't stop or start the instances.

Create a EventBridge Scheduler schedule to run your Lambda functions

Create a schedule to run your Lambda functions. For Select target, select Templated targets, and then choose AWS Lambda Invoke. Use the Lambda functions that you created.

19 Comments

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

replied 3 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 3 years ago

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

AWS
MODERATOR
replied 3 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 3 years ago

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

AWS
MODERATOR
replied 3 years ago

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

replied 3 years ago

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

replied 3 years ago

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

AWS
MODERATOR
replied 3 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 2 years 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 2 years 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 a year ago

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

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

Here is my fully working solution for EC2 Auto Stop/Start per cron Schedule on Terraform: https://github.com/adv4000/aws-ec2-scheduler

EXPERT
replied 6 months ago

Great job! Congrats on the article.

replied 5 months ago