How to create automatic Cloudwatch alarm on New EC2 instance creation - amazon-web-services

I want to create a lambda function that gets triggered whenever a new EC2 instance is created, this Lambda function should configure StatusCheck alarm on this new instance automatically. So that I don't have to manually configure cloudwatch alarm each time a new instance is created. Can someone help with code for lambda function that accomplishes this?
I have something like this:
response = client.put_metric_alarm(
AlarmName='StatusCheckFailed-Alarm-for-i-1234567890abcdef0',
AlarmActions=[
'arn:aws:sns:us-west-2:111122223333:my-sns-topic',
],
MetricName='StatusCheckFailed',
Namespace='AWS/EC2',
Statistic='Maximum',
Dimensions=[
{
'Name': 'InstanceId',
'Value': 'i-1234567890abcdef0'
},
],
Period=300,
Unit='Count',
EvaluationPeriods=2,
Threshold=1,
ComparisonOperator='GreaterThanOrEqualToThreshold')
But I have to map instance ID from cloudwatch rule as an input to Lambda. Because the function would trigger automatically so there is no way to put instance ID manually each time.

You will need two cloud watch rule to handle this as
One for instance launch from auto-scaling group
One for instance launch with EC2
Also, I am going to add Launch and Terminatioin
On Launch (add alarm)
On termination (delete alarm) to avoid reaching max limit
Autoscaling group CW rule:
{
"source": [
"aws.autoscaling"
],
"detail-type": [
"EC2 Instance Launch Successful",
"EC2 Instance Terminate Successful"
]
}
Autoscaling Event:
{
"version": "0",
"id": "3e3c153a-8339-4e30-8c35-687ebef853fe",
"detail-type": "EC2 Instance Launch Successful",
"source": "aws.autoscaling",
"account": "123456789012",
"time": "2015-11-11T21:31:47Z",
"region": "us-east-1",
"resources": [
"arn:aws:autoscaling:us-east-1:123456789012:autoScalingGroup:eb56d16b-bbf0-401d-b893-d5978ed4a025:autoScalingGroupName/sampleLuanchSucASG",
"arn:aws:ec2:us-east-1:123456789012:instance/i-b188560f"
],
"detail": {
"StatusCode": "InProgress",
"AutoScalingGroupName": "sampleLuanchSucASG",
"ActivityId": "9cabb81f-42de-417d-8aa7-ce16bf026590",
"Details": {
"Availability Zone": "us-east-1b",
"Subnet ID": "subnet-95bfcebe"
},
"RequestId": "9cabb81f-42de-417d-8aa7-ce16bf026590",
"EndTime": "2015-11-11T21:31:47.208Z",
"EC2InstanceId": "i-b188560f",
"StartTime": "2015-11-11T21:31:13.671Z",
"Cause": "At 2015-11-11T21:31:10Z a user request created an AutoScalingGroup changing the desired capacity from 0 to 1. At 2015-11-11T21:31:11Z an instance was started in response to a difference between desired and actual capacity, increasing the capacity from 0 to 1."
}
}
EC2 CW Rule:
{
"source": [
"aws.ec2"
],
"detail-type": [
"EC2 Instance State-change Notification"
],
"detail": {
"state": [
"running",
"terminated"
]
}
}
EC2 Event:
{
"version": "0",
"id": "ee376907-2647-4179-9203-343cfb3017a4",
"detail-type": "EC2 Instance State-change Notification",
"source": "aws.ec2",
"account": "123456789012",
"time": "2015-11-11T21:30:34Z",
"region": "us-east-1",
"resources": [
"arn:aws:ec2:us-east-1:123456789012:instance/i-abcd1111"
],
"detail": {
"instance-id": "i-abcd1111",
"state": "running"
}
}
So you can do rest of the logic base on the event, below example is base on javascript
If the event from the auto-scaling group
if (event["source"] == "aws.autoscaling") {
if (event["detail-type"] === "EC2 Instance Launch Successful"){
let EC2_ID=event.detail.EC2InstanceId
// Add alarm here
// use EC2 instance ID
}
}
Same logic can be applied for EC2 events, where you can check the status
if (event["source"] == "aws.ec2") {
if (event.detail === "running"){
let EC2_ID=event.detail.EC2InstanceId
// Add alarm here
// use EC2 instance ID
}
// same can be check for termination
if (event.detail === "terminated"){
let EC2_ID=event.detail.EC2InstanceId
// remove alarm for this instance
// use EC2 instance ID here to remove/delete alaram
}
}

What you are looking for is AWS CloudTrail. It's a service that is used to monitor any and every API calls made to AWS for a given account.
Pro Tip: AWS is API driven, everything you do, even on the console (UI) is translated into an API call to get the desired result.
The scenario described a very common one and AWS has addressed it in Automating Amazon EC2 with CloudWatch Events - Amazon Elastic Compute Cloud. You can create a CloudTrail event trail for EC2 and configure it to trigger a lambda function. As you have described, this function can then do the necessary configurations.
I use this setup for a similar use case wherein monitoring for disk utilization and memory is configured for any new instance that any user or system spins up. This is just an additional check that makes sure if the correct/recommended AMI is not used, there is some process that goes in and makes sure the monitoring tools are in place.
A note from my experience:
I prefer using S3 in between CloudTrail and Lambda i.e. CloudTrail would write the events to S3 and then the lambda function would be triggered via S3 events. This has the added benefit of persisting the events for later reference. If the data is not sensitive, you can choose to use S3 Lifecycle hooks to delete the data in some time or even use a cheaper storage option to keep the cost down.

Not sure if you were able to get an answer to your question about getting the instance id of the instance. here is how i did it:
def lambda_handler(event, context):
cloudwatchclient = boto3.client('cloudwatch')
eventdata = json.load(event)
thisInstanceID = eventdata['detail']['instance-id']

Related

Cloudwatch rule not being triggered as event pattern is deployed in lexicographic order usung terraform

I'm trying to write a config where lambda function is being triggered if there is an instance class change in AWS RDS resource.
This is the custom event pattern:
{
"source": [
"aws.rds"
],
"detail-type": [
"RDS DB Instance Event"
],
"detail": {
"EventID": [
"RDS-EVENT-0014"
]
}
}
The following is my terraform config for cloud watch event rule resource:
resource "aws_cloudwatch_event_rule" "rds_instance_event" {
name = "${var.region}-rds-instance-event"
description = "This event trigger is for RDS instance events"
event_pattern = <<EOF
{
"source": [
"aws.rds"
],
"detail-type": [
"RDS DB Instance Event"
],
"detail": {
"EventID": [
"RDS-EVENT-0014"
]
}
}
EOF
}
The problem is that event_patter get's uploaded in lexicographical order and the cloud watch event is not being triggered. When I change the event_pattern manually to the original order, it works.
Does anyone know how to fix this?
I tried rendering it from a data template as following, still didn't work.
data "template_file" "event_pattern" {
template = file("${path.module}/manifests/rds-notification-event-rule.json")
}
resource "aws_cloudwatch_event_rule" "rds_instance_event" {
name = "${var.region}-rds-instance-event"
description = "This event trigger is for RDS instance events"
event_pattern = data.template_file.event_pattern.rendered
}

AWS CloudWatch State Change rule and schedule

I have a CloudWatch alarm for state change with the following code:
{
"source": [
"aws.ec2"
],
"detail-type": [
"EC2 Instance State-change Notification"
],
"detail": {
"state": [
"shutting-down",
"stopping"
]
}
}
It is working fine, but it also triggers events for AWS Instance Scheduler. Is there any way to prevent scheduled state changes from triggering this alarm? I googled for it, but no success.

How to send scheduled custom message using Amazon EventBridge

I'm trying to build an Amazon EventBridge rule that runs on a schedule(weekly), to put an event in the SQS.
There are multiple options to choose from, as to what message is to be sent as an event.
I understand that it's essentially a JSON object, which can be set to a custom JSON, or the default(or some seletive fields from this) Something like:
{
"version": "0",
"id": "6a7e8feb-b491-4cf7-a9f1-bf3703467718",
"detail-type": "EC2 Instance State-change Notification",
"source": "aws.ec2",
"account": "111122223333",
"time": "2017-12-22T18:43:48Z",
"region": "us-west-1",
"resources": [
"arn:aws:ec2:us-west-1:123456789012:instance/i-1234567890abcdef0"
],
"detail": {
"instance-id": " i-1234567890abcdef0",
"state": "terminated"
}
}
AWS EventBridge: https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-create-rule-schedule.html
EB Events: https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-events.html
My question is: How can I send a JSON Object that has a different parameters every time?
Say I want to publish this object, with a date-range different, with
activeFrom: Today-7 days
activeTill: Today's date.
{
"dummyId": "xyz",
"activeFrom": "2021-07-09T18:43:48Z",
"activeTill": "2021-07-15T18:43:48Z"
}
You can let the EventBridge trigger a lambda function on schedule. In that lambda, you can bake your JSON and send the event to SQS.

Can you trigger an AWS Lambda from the creation of an AWS Lambda?

I've written an AWS Lambda that's triggered by the creation of an EC2 instance that checks if the required tags have been set. From the Terraform file:
resource "aws_cloudwatch_event_rule" "check-ec2-tags" {
description = "Capture each EC2 instance creation"
event_pattern = <<PATTERN
{
"source": [ "aws.ec2" ],
"detail-type": [ "EC2 Instance State-change Notification" ],
"detail": {
"state": [ "running" ]
}
}
PATTERN
}
I want to do the same thing for AWS Lambdas - whenever a new lambda is created I want to make sure it has the required tags. Is this possible?
You can store the .tfstate file in s3 and a lambda can be triggered on the S3Event. This lambda function can extract the resource name from the .tfstate file and can validate any resource available in .tfstate file.

create email notification when an ec2 instance is terminated. The Email should contain the instance details.eg:Instance Name

I have created cloudwatch alarms for cloudtrail events. I am getting the email notification whenever there is a state change. But It is tough for me to search for the instance which is deleted among hundreds of instances. It will be easier if I get the instance name in the notification Email. Have anyone tried this?
The best method is:
Create an Amazon SNS topic to receive the notification
Subscribe to the topic to receive notifications (eg via Email)
Create a rule in Amazon CloudWatch Events to trigger when an instance is terminated:
The result will be a message like this sent via email (or however you subscribed to the topic):
{
"version": "0",
"id": "0c921724-d932-9cc2-b620-4053a0ad3f73",
"detail-type": "EC2 Instance State-change Notification",
"source": "aws.ec2",
"account": "123456789012",
"time": "2018-01-09T07:04:42Z",
"region": "ap-southeast-2",
"resources": [
"arn:aws:ec2:ap-southeast-2:123456789012:instance/i-0a32beef35b8da342"
],
"detail": {
"instance-id": "i-0a32beef35b8da342",
"state": "terminated"
}
}