Keep Your EC2 Instances in Check and Prevent Over-provisioning with EventBridge
Introduction
Managing EC2 instances efficiently is crucial for maintaining cost control and optimizing resource usage in your AWS environment. One of the most common issues teams face is over-provisioning EC2 instances, leading to unnecessary operational expenses and resource sprawl. But what if you could automate the enforcement of instance limits, ensuring that no more than a specified number of EC2 instances are running at any given time?
In this tutorial, we’ll walk you through how to use Amazon EventBridge to automatically detect and prevent over-provisioning of EC2 instances in your account. By setting up EventBridge rules and combining them with AWS Lambda, you’ll be able to enforce smart limits on instance launches, keeping your environment streamlined and cost-effective.
We’ll show you how to do this in the following steps:
- Step 0: Create an SNS Topic and subscribe to it
- Step 1: Create a lambda function
- Step 2: Create an EventBridge rule
- Step 3: Add the lambda function as a target
- Step 4: Grant the EventBridge permission to invoke your Lambda function
- Step 5: Test the EventBridge rule
Architecture
Here’s an architecture diagram of what we’ll implement:
Ready to take control of your EC2 provisioning ? Let’s dive in !
Prerequisites
Lambda’s execution role: To allow the Lambda function to manage EC2 instances and send notifications via SNS, you’ll need to create an IAM role with the appropriate permissions.
Here are the necessary permissions:
- EC2 Permissions: “ec2:DescribeInstances”, “ec2:TerminateInstances”
- SNS Permissions: “sns:Publish”
Steps:
Step 0: Create an SNS Topic and subscribe to it
- Create a new SNS Topic
aws sns create-topic --name EC2StatusChangeTopic
Take note of the TopicArn from the output, we’ll need it in future steps.
> Output:
- Subscribe to the topic:
aws sns subscribe \
--topic-arn place_SNS_topic_arn_here \
--protocol email \
--notification-endpoint place_your_email_here
> Output:
Note: The email subscription requires the recipient to click a confirmation link. Until confirmed, the subscription remains in a pending state.
Step 1 : Create a lambda function
We need to create a Lambda function that runs every time a new EC2 instance is launched, ensuring that no more than two instances are running in your AWS account.
The Lambda function performs the following actions:
- Retrieves the instance ID of the newly launched EC2 instance
- Counts the total number of currently running EC2 instances
- Terminates the newly launched instance if there are already two running instances
- Publishes a message to an SNS topic
The flowchart below illustrates this process in detail.
>>Lambda’s code: (Python)
import json
import boto3
# Initialize clients for EC2 and SNS
ec2_client = boto3.client('ec2')
sns_client = boto3.client('sns')
# SNS topic ARN
SNS_TOPIC_ARN = 'place_sns_topic_arn_here'
def lambda_handler(event, context):
# 1. Get the instance ID from the event
instance_id = event['detail']['instance-id']
print(f"Instance ID from event: {instance_id}")
# 2. Get the count of running EC2 instances
response = ec2_client.describe_instances(
Filters=[
{
'Name': 'instance-state-name',
'Values': ['running']
}
]
)
running_instances = []
for reservation in response['Reservations']:
for instance in reservation['Instances']:
running_instances.append(instance['InstanceId'])
running_count = len(running_instances)
print(f"Number of running instances: {running_count}")
# 3. If running instances >= 2, terminate the new instance
if running_count >= 2:
print(f"Terminating instance: {instance_id}")
ec2_client.terminate_instances(InstanceIds=[instance_id])
message = f"Instance {instance_id} has been terminated because there are more than 2 running instances."
else:
message = f"Instance {instance_id} is running. There are currently {running_count} instances running."
# 4. Send an SNS notification
response = sns_client.publish(
TopicArn=SNS_TOPIC_ARN,
Subject='EC2 Instance Status Alert',
Message=message
)
print(f"SNS notification sent: {response['MessageId']}")
return {
'statusCode': 200,
'body': json.dumps('Lambda executed successfully!')
}
Step 2: Create an EventBridge rule
AWS EventBridge Rules enable you to respond to events from AWS services, custom applications, and SaaS partners by directing them to specified target services. In this tutorial, we’re creating a rule that captures EC2 instance launch events, particularly the ‘pending’ state, as every EC2 instance enters this state during the initial launch process.
aws events put-rule \
--name "monitoring-ec2-launch-state" \
--event-pattern '{
"source": ["aws.ec2"],
"detail-type": ["EC2 Instance State-change Notification"],
"detail": {
"state": ["pending"]
}
}' \
--description "Monitors EC2 instances when they are in a pending state"
> Output:
From the AWS console we can see that our eventBridge rule was successfully created
Step 3: Add the lambda function as a target
With the EventBridge rule now properly defined, we need to set up a target that will be triggered whenever an event matches the rule. To achieve this, we’ll run the following command:
aws events put-targets \
--rule "monitoring-ec2-launch-state" \
--targets "Id"="1","Arn"="place_lambda_arn_here"
> Output:
From the AWS console, a new target was added to the lambda function:
Step 4: Grant the EventBridge permission to invoke your Lambda function
To allow EventBridge to invoke your Lambda function, you need to grant the necessary permissions by updating the Lambda function’s resource-based policy. This can be done using the aws lambda add-permission command, which specifies the source as EventBridge and allows it to invoke the function when events match the rule.
aws lambda add-permission \
--function-name place_lambda_function_name_here \
--statement-id "monitoring-ec2-launch-state-permission" \
--action "lambda:InvokeFunction" \
--principal events.amazonaws.com \
--source-arn place_eventbridge_rule_arn_here
> Output:
Step 5: Test the EventBridge rule
To test this solution, we’ll need to launch a new EC2 instance. This action should trigger the EventBridge rule, which will then invoke the Lambda function. Depending on the number of instances currently running in the account, we will encounter one of two scenarios:
- Scenario 1: Launch the first EC2 instance in your AWS account
In this case, the Lambda function should allow the instance to remain active since the condition for termination is not met (not more than two instances are running in the account).
> Email notification:
- Scenario 2: Launch a third EC2 instance in your AWS account
The function will check if there are already two running EC2 instances; if so, it will terminate the newly launched instance and send an SNS email notification.
> Email notification:
Conclusion
In conclusion, using EventBridge rules with a Lambda function provides a robust solution to prevent EC2 over-provisioning in your AWS account. By enforcing a limit of two running instances, this setup ensures that your environment stays within predefined resource limits, helping to control costs and avoid unnecessary usage.
References
- What is Event-Driven Architecture?
https://aws.amazon.com/event-driven-architecture/ - Creating rules that react to events in Amazon EventBridge
https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-create-rule.html - Amazon EC2 instance state changes
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-lifecycle.html - Rules in Amazon EventBridge
https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-rules.html - Create your first Lambda function
https://docs.aws.amazon.com/lambda/latest/dg/getting-started.html