This AWS Lambda function takes CloudWatch Events and tries to format them using custom templates before publishing them to an SNS Topic. This will produce an email that is much easier to read than the default, and also deliver to other endpoints the same as before.
- License: University of Illinois/NCSA Open Source License
- Organization: University of Illinois at Urbana-Champaign, Technology Services
- Author: Stephen J. Butler
You can choose to build and deploy this app with terraform.
This is a NodeJS 20.x project that builds using a Makefile. Building should be as simple as running these commands from the project directory:
make dist
This produces a file in the dist
directory called cweventFormat.zip
.
The terraform module will create and manage these resources for you:
- SNS Topic: if you do not pass in the ARN of an SNS Topic then one will be created for you.
- Lambda Role and Policies: IAM role and policies used by the Lambda function to publish to the SNS Topic and write CloudWatch Logs. No other permissions are needed at this time.
- Lambda Function: part that does all the work to format events for
publishing, deployed from the
deploy_localzip
path ordeploy_s3zip
. - CloudWatch Log Group: for logs generated by the Lambda function.
- CloudWatch Metric Alarm: alarm that alerts on errors in the Lambda function. This publishes to the SNS Topic.
These variables are used by the project and are common to many of the components it manages.
Name | Default | Description |
---|---|---|
environment | Deployment environment (dev, test, prod, devtest, qa). |
These variables configure specific parameters for the Lambda's operation. This is most likely what you want to customize.
Name | Default | Description |
---|---|---|
event_rule_patterns | {} |
CloudWatch Event Rules patterns in a map of NAME = PATTERN. You do not need to specify patterns here, and can instead do them in your own terraform code. If you do, you will need a aws_cloudwatch_event_rule , aws_cloudwatch_event_target , and aws_lambda_permission resources for each pattern. |
notifications_topic_arn | null |
SNS Topic to send formatted notifications to. If you do not specify a value here then an SNS Topic is created for you. |
These variables are used to configure the Lambda Function.
Name | Default | Description |
---|---|---|
name | "cweventFormat" |
Base name (without the project) to use for the lambda function name. The project and revision will be added as a prefix to this. |
description | "Format CloudWatch Events for email delivery." |
Description of the function. |
deploy_localzip | null |
Path to the zip file to deploy. |
deploy_s3zip | null |
S3 bucket and prefix to the cweventFormat/environment.zip file to deploy. |
timezone | "UTC" |
Timezone name to set when running the lambda function ("America/Chicago", "UTC", etc). |
These variables control where the Lambda Function logs are sent. You will always have a copy of the logs in CloudWatch Logs, but you can also have a copy sent to another Lambda Function or a Log Destination (for cross-account logging).
Name | Default | Description |
---|---|---|
log_encryption_arn | null |
KMS Key ARN to encrypt to this log group. |
log_subscription_arn | null |
Lambda function ARN to subscribe to this log group. |
These outputs are useful for other parts of your terraform.
- lambda
- notifications_topic_arn
Take a look at the terraform/1.0-aws4/example
directory for how to use this
module.
You can choose to build and deploy this app with AWS SAM and CloudFormation.
After building you will deploy the packaged-template.yaml
and one or more
template-event.yaml
stacks.
This is a NodeJS 20.x project that builds with AW SAM. Building should be as simple as running these commands from the project directory:
sam build
sam package \
--s3-bucket your-sam-package-bucket \
--s3-prefix cweventFormat \
--output-template-file packaged-template.yaml
This will build the project and upload the code zip files into an S3 package
bucket (--s3-bucket your-sam-package-bucket
) that you specify. You can also
change the --s3-prefix
if you want to place the files somewhere else in the
bucket. The ouput is a packaged-template.yaml
file that you can use to create
a CloudFormation stack.
Since you might need the packaged-template.yaml
and template-event.yaml
files you might want to include commands like these in your build script:
aws s3 cp packaged-template.yaml s3://your-sam-package-bucket/cweventFormat/packaged-template.yaml
aws s3 cp template-event.yaml s3://your-sam-package-bucket/cweventFormat/template-event.yaml
The terraform module will create and manage these resources for you:
- SNS Topic: if you do not pass in the ARN of an SNS Topic then one will be created for you.
- Lambda Role and Policies: IAM role and policies used by the Lambda function to publish to the SNS Topic and write CloudWatch Logs. No other permissions are needed at this time.
- Lambda Function: part that does all the work to format events for
publishing, deployed from the
s3://your-sam-package-bucket/cweventFormat
. The Lambda function also uses the SNS Topic as a Dead Letter Queue (DLQ) for failed events. - CloudWatch Log Group: for logs generated by the Lambda function.
- CloudWatch Metric Alarm: alarm that alerts on errors in the Lambda function. This publishes to the SNS Topic.
These parameters are used by the stack and are common to many of the components it manages.
Name | Default | Description |
---|---|---|
NotificationTopicARN | "" |
SNS Topic to send formatted notifications to. If you do not specify a value here then an SNS Topic is created for you. |
These parameters are used to configure the Lambda Function.
Name | Default | Description |
---|---|---|
LambdaName | "cweventFormat" |
Base name (without the stack prefix) to use for the lambda function name. |
LambdaTimezone | "UTC" |
Timezone name to set when running the lambda function ("America/Chicago", "UTC", etc). |
These parameters control where the Lambda Function logs are sent and how long they are retained. You will always have a copy of the logs in CloudWatch Logs, but you can also have a copy sent to another Lambda Function or a Log Destination (for cross-account logging).
Name | Default | Description |
---|---|---|
LogRetentionInDays | 30 |
Number of days to retain log streams in CloudWatch Logs. |
LogSubscriptionARN | "" |
Lambda function ARN or CloudWatch Logs Destination to subscribe to this log group. |
There is a companion template file called template-event.yaml
that you can
use to connect this Lambda to various CloudWatch Events, using
Event Patterns.
You can deploy this companion template multiple times, for each event pattern type you want to listen to.
Name | Default | Description |
---|---|---|
LambdaStackName | Name of the CloudFormation Stack used to deploy the cweventFormat Lambda. | |
EventPattern | CloudWatch Event pattern to trigger the lambda on. |
These outputs are useful for other parts of your CloudFormation stacks.
- ${StackName}:LambdaRoleName
- ${StackName}:LambdaRoleARN
- ${StackName}:LambdaFunctionName
- ${StackName}:LambdaFunctionARN
- ${StackName}:NotificationTopicARN
Here is an example template you can use to deploy the cweventFormat with a couple sample events:
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: Send emails about certain events in the AWS Account.
Resources:
CWEventFormat:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.amazonaws.com/your-sam-package-bucket/cweventFormat/packaged-template.yaml
Parameters:
LambdaTimezone: America/Chicago
AWSHealthEvents:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.amazonaws.com/your-sam-package-bucket/cweventFormat/template-event.yaml
Parameters:
LambdaStackName: !Select [ 1, !Split [ "/", !Ref CWEventFormat ] ]
EventPattern: |
{
"source": [ "aws.health" ],
"detail-type": [ "AWS Health Event" ]
}
GuardDutyFindingEvents:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.amazonaws.com/uiuc-sbutler1-sandbox/cweventFormat/sam/template-event.yaml
Parameters:
LambdaStackName: !Select [ 1, !Split [ "/", !Ref CWEventFormat ] ]
EventPattern: |
{
"source": [ "aws.guardduty" ],
"detail-type": [ "GuardDuty Finding" ]
"detail": {
"severity": [ { "numeric": [ ">=", 7 ] } ]
}
}
EC2StateChangeEvents:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.amazonaws.com/your-sam-package-bucket/cweventFormat/template-event.yaml
Parameters:
LambdaStackName: !Select [ 1, !Split [ "/", !Ref CWEventFormat ] ]
EventPattern: |
{
"source": [ "aws.ec2" ],
"detail-type": [ "EC2 Instance State-change Notification" ]
}
EC2InstanceConnectEvents:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.amazonaws.com/your-sam-package-bucket/cweventFormat/template-event.yaml
Parameters:
LambdaStackName: !Select [ 1, !Split [ "/", !Ref CWEventFormat ] ]
EventPattern: |
{
"detail-type": [ "AWS API Call via CloudTrail" ],
"detail": {
"eventSource": [ "ec2-instance-connect.amazonaws.com" ],
"eventName": [ "SendSSHPublicKey" ]
}
}