Trigger Actions Inside EC2 Instance on Cloudwatch Events using AWS Systems Manager

Amazon CloudWatch Events enables you to react selectively to events in the cloud as well as in your applications. Using simple rules you can easily route each type of event to one or more targets including but not limited to AWS Lambda functions, Amazon SNS topics etc. AWS Systems Manager Run Command lets you remotely and securely manage the configuration of your EC2 instances that has been configured for Systems Manager. Run Command enables you to automate common administrative tasks and perform ad hoc configuration changes at scale.

In this blog post, we will trigger sample bash command inside an EC2 instance on the uploading an object to S3 (PutObject).

  1. Create a CloudwatchEvents Rule with the Event pattern defined below:
{
  "source": [
    "aws.s3"
  ],
  "detail-type": [
    "AWS API Call via CloudTrail"
  ],
  "detail": {
    "eventSource": [
      "s3.amazonaws.com"
    ],
    "eventName": [
      "PutObject"
    ],
    "requestParameters": {
      "bucketName": [
        "<your-bucket-name>"
      ]
    }
  }
}
  1. Create a Lambda function with the following code:
const AWS = require('aws-sdk');

exports.handler = (event, context, callback) => {
    let ssm = new AWS.SSM();

    var params = {
      DocumentName: 'AWS-RunShellScript', 
      DocumentVersion: "\$DEFAULT",
      MaxConcurrency: '50',
      MaxErrors: '0',
      OutputS3BucketName: '<your-bucket-name>',
      OutputS3Region: 'us-east-1',
      Parameters: {
        'workingDirectory': [""],
        'executionTimeout': ["3600"],
        'commands': ["echo \"Hello\" >> /home/ec2-user/a.txt","echo \"World\""]
      },
      Targets: [
        {
          Key: 'instanceids',
          Values: [
            'i-xxxxxxxxxxxxxxxxx'
          ]
        }
      ],
      TimeoutSeconds: 600
    };
    ssm.sendCommand(params, function(err, data) {
      if (err) {
        const response = {
        statusCode: 400,
          body: JSON.stringify(err),
        };
        callback(response);
      }
      else {
        const response = {
          statusCode: 200,
          body: JSON.stringify(data),
        };
        callback(null, response);
      }
    });
};
  1. Add the above Lambda function as a Target for the Cloudwatch Event.

Alternatively, if the use case is to only execute a command based on no specific conditions, you may directly use the SSM RunCommand as the Target; shown in the below screenshot.

Screen Shot 2019-02-04 at 7.55.45 PM


© 2019 | Ujjwal Bhardwaj. All Rights Reserved.