# AWS Zero to Hero day 4 - part 4

# Automating EC2 Instance Start/Stop with AWS Lambda and EventBridge

---

## Introduction

In a cost-conscious cloud environment, optimizing resource usage is critical. One effective way to manage EC2 instance costs is to automate the process of starting and stopping instances during business hours. In this blog, we’ll walk through a clean and efficient approach using AWS Lambda and EventBridge, with Python (Boto3) to control instances based on tags.

---

## Objective

To automatically start or stop specific EC2 instances during defined hours using a Lambda function. Instances are identified using a custom tag, enabling flexibility and control.

---

## **Scenario**

You're an AWS expert managing a budget-friendly project with EC2 instances. To save money, you're using AWS Lambda to automatically start and stop instances when they're not needed during non-business hours. 👇

#### **What needs to be done:**

* Create an AWS Lambda function that will start/stop instances based on their instance tag.
    

---

## Prerequisites

Before implementing the solution, ensure the following:

1. **Tagged EC2 Instances**
    
    * Tag Key: `AutoSchedule`
        
    * Tag Value: `true`
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1745462113021/7c3b3b07-978d-4fb2-a709-2810bd14be6a.png align="center")
        
2. **IAM Role for Lambda**  
    Create and assign an IAM role to your Lambda function with the following permissions, or EC2 Full Access:
    
    ```json
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": [
            "ec2:DescribeInstances",
            "ec2:StartInstances",
            "ec2:StopInstances"
          ],
          "Resource": "*"
        }
      ]
    }
    ```
    

---

## Lambda Function Code

Below is the Python code using Boto3 to start or stop EC2 instances based on the `AutoSchedule` tag.

```python
import boto3

ec2 = boto3.client('ec2')

def lambda_handler(event, context):
    action = event.get('action')  # 'start' or 'stop'
    if action not in ['start', 'stop']:
        return {'statusCode': 400, 'body': "Invalid action."}

    filters = [
        {'Name': 'tag:AutoSchedule', 'Values': ['true']},
        {'Name': 'instance-state-name', 'Values': ['stopped'] if action == 'start' else ['running']}
    ]

    instances = ec2.describe_instances(Filters=filters)
    instance_ids = [i['InstanceId'] for r in instances['Reservations'] for i in r['Instances']]

    if not instance_ids:
        return {'statusCode': 200, 'body': f"No instances to {action}."}

    if action == 'start':
        ec2.start_instances(InstanceIds=instance_ids)
    else:
        ec2.stop_instances(InstanceIds=instance_ids)

    return {'statusCode': 200, 'body': f"{action.capitalize()}ed: {instance_ids}"}
```

---

## Manual Testing

Before scheduling, it's important to verify the Lambda function manually.

### Steps:

1. Navigate to your Lambda function in the AWS console.
    
2. Click **Test** &gt; **Create new test event**.
    
3. Use the following test input:
    
    * For starting:
        
        ```json
        {
          "action": "start"
        }
        ```
        
    * For stopping:
        
        ```json
        {
          "action": "stop"
        }
        ```
        
4. Execute the test and check the results in the output logs.
    

---

## Automating with EventBridge

To run this function at specific times daily, use EventBridge (CloudWatch Events).

### Schedule to Start Instances

* Go to **EventBridge** → **Rules** → **Create Rule**
    
* Name: `StartEC2Instances`
    
* Schedule pattern: `cron(0 9 * * ? *)` (Every day at 9 AM UTC)
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1745461784330/b88b83d9-46b6-421c-96fd-1b37b05fb7eb.png align="center")
    
* Target: Your Lambda function
    
* Input JSON:
    
    ```json
    {
      "action": "start"
    }
    ```
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1745461926357/d070fc91-e672-4548-86b7-13f2db81cfed.png align="center")
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1745462191801/3ccdf56f-debe-4d47-959d-c326d8506a6f.png align="center")

### Schedule to Stop Instances

* Name: `StopEC2Instances`
    
* Schedule pattern: `cron(0 18 * * ? *)` (Every day at 6 PM UTC)
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1745462265683/31e22863-5490-491a-9369-427e22ceb031.png align="center")
    
* Input JSON:
    
    ```json
    {
      "action": "stop"
    }
    ```
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1745462299961/46de4263-0992-4ec3-bbd6-c292720b5669.png align="center")
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1745462429345/82de3183-dbee-4b76-80d7-c9ddbb2226f5.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1745466756448/c68743a6-0259-46cb-a2c4-14c5a818eff8.png align="center")

---

## Guide to set up SNS notifications for EC2 start/stop events:

---

### Step 1: Create an SNS Topic

1. Open the [**SNS Console**.](https://us-east-1.console.aws.amazon.com/sns/v3/home)
    
2. Click **Create topic**.
    
3. Select **Standard** as the topic type.
    
4. Enter the following:
    
    * **Name**: `ec2-notifications`
        
5. Leave the default settings for other options and click **Create topic**.
    

### Step 2: Subscribe to the Topic (Email)

1. After the topic is created, click on the topic name.
    
2. Click **Create subscription**.
    
3. Configure the subscription:
    
    * **Protocol**: Email
        
    * **Endpoint**: Enter your email address (e.g., [`you@example.com`](mailto:you@example.com)).
        
4. Click **Create subscription**.
    
5. Check your email inbox and confirm the subscription by clicking the confirmation link in the email.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1745465383153/938c7c15-b685-4c80-bcbd-7e7d695a33ba.png align="center")
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1745465366485/76b0c056-131b-492c-a5ab-73ae53157130.png align="center")
    

### Step 3: Create CloudWatch/EventBridge Rule for EC2 Start & Stop Notifications

You need to create two rules: one for EC2 instance start notifications and another for EC2 instance stop notifications.

#### 1\. Create Rule for EC2 Instance Start Notification

1. Go to the **Amazon CloudWatch Console**.
    
2. In the left sidebar, select **Rules** under **Events/EventBridge** (depending on your UI version). For older UIs, navigate to **Events &gt; Rules**.
    
3. Click **Create Rule**.
    
4. In the **Rule details** section:
    
    * **Name**: `EC2InstanceStartNotify`
        
    * **Description** (optional): `Notify when EC2 instance starts`.
        
5. Under **Event Pattern**, select **Event Pattern** and paste the following:
    

```json
{
  "source": ["aws.ec2"],
  "detail-type": ["EC2 Instance State-change Notification"],
  "detail": {
    "state": ["running"]
  }
}
```

6. Add the target:
    
    * Click **Add target**.
        
    * Select **SNS topic**.
        
    * Choose the **ec2-notifications** topic you created earlier.
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1745465415081/2d7b14d9-0ebc-4bff-8d42-dfb120fa77c2.png align="center")
        
7. Click **Create** to finalize the rule.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1745465429262/f976a29a-6874-4128-bea7-64e306772066.png align="center")
    

#### 2\. Create Rule for EC2 Instance Stop Notification

1. Repeat steps 1–4 to create another rule, but with the following changes:
    
    * **Name**: `EC2InstanceStopNotify`
        
    * **Description** (optional): `Notify when EC2 instance stops`.
        
2. Under **Event Pattern**, paste the following for EC2 stop notifications:
    

```json
{
  "source": ["aws.ec2"],
  "detail-type": ["EC2 Instance State-change Notification"],
  "detail": {
    "state": ["stopped"]
  }
}
```

3. Add the target:
    
    * Click **Add target**.
        
    * Select **SNS topic**.
        
    * Choose the **ec2-notifications** topic you created earlier.
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1745465457693/41c3199a-a297-4dac-bdf4-3cc2236f58d8.png align="center")
        
4. Click **Create** to finalize the rule.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1745465480136/367a27f2-095f-4d3d-9cc1-4c214a3179af.png align="center")
    
5. EC2 Start Email Notification:
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1745465542751/4a5e9409-395e-4231-b5c1-be6267d6941e.png align="center")
    
6. EC2 Stop Email Notification:
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1745465528690/67ebbfd0-7809-45d1-8fc1-9fb3c9bc22ac.png align="center")
    

---

## Conclusion

By combining AWS Lambda, EventBridge scheduling, and SNS notifications, you now have a fully serverless, automated framework for managing your EC2 instance lifecycle:

* **Cost optimization**: Instances only run during business hours, reducing your hourly compute charges.
    
* **Operational visibility**: SNS alerts notify you immediately whenever an instance starts or stops.
    
* **Scalability & maintainability**: EventBridge cron rules and Lambda functions require no servers to manage, and you can adjust tags or schedules without changing infrastructure.
    

Next steps and best practices:

1. Review your CloudWatch Logs and SNS subscription metrics to validate that notifications are delivered as expected.
    
2. Implement IAM least-privilege for your Lambda execution role and refine tag-based permissions.
    
3. Consider adding CloudWatch alarms on Lambda errors or unexpected instance-state counts to proactively detect issues.
    

With these measures in place, you’ll maintain tight cost control and real-time awareness of your EC2 fleet. If you’ve adopted a similar pattern or have other ideas for optimizing AWS resource usage, I’d welcome your insights—let’s continue sharing best practices.
