Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add support for System Manager Run Command notification format #212

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Doing serverless with Terraform? Check out [serverless.tf framework](https://ser
- AWS CloudWatch Alarms
- AWS CloudWatch LogMetrics Alarms
- AWS GuardDuty Findings

- AWS System Manager Run Command Notifications

## Usage

Expand Down
9 changes: 9 additions & 0 deletions functions/events/ssm_run_command_event_failed.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"commandId": "6f69316a-e502-5a20-99bc-2408825b6dee",
"documentName": "AWS-RunPatchBaseline",
"instanceId": "i-99999999999999999",
"requestedDateTime": "2023-12-14T10:48:47.127Z",
"status": "Failed",
"detailedStatus": "Failed",
"eventTime": "2023-12-14T10:52:22.114Z"
}
9 changes: 9 additions & 0 deletions functions/events/ssm_run_command_event_success.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"commandId": "6f69316a-e502-5a20-99bc-2408825b6dee",
"documentName": "AWS-RunPatchBaseline",
"instanceId": "i-99999999999999999",
"requestedDateTime": "2023-12-14T10:48:47.127Z",
"status": "Success",
"detailedStatus": "Success",
"eventTime": "2023-12-14T10:52:22.114Z"
}
9 changes: 9 additions & 0 deletions functions/events/ssm_run_command_event_timedout.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"commandId": "6f69316a-e502-5a20-99bc-2408825b6dee",
"documentName": "AWS-RunPatchBaseline",
"instanceId": "i-99999999999999999",
"requestedDateTime": "2023-12-14T10:48:47.127Z",
"status": "TimedOut",
"detailedStatus": "DeliveryTimedOut",
"eventTime": "2023-12-14T10:52:22.114Z"
}
22 changes: 22 additions & 0 deletions functions/messages/ssm_run_command_event.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"Records": [
{
"EventSource": "aws:sns",
"EventVersion": "1.0",
"EventSubscriptionArn": "arn:aws:sns:us-east-1::ExampleTopic",
"Sns": {
"Type": "Notification",
"MessageId": "d3cece60-336d-5967-844b-9394d3cb44ba",
"TopicArn": "arn:aws:sns:us-east-1:123456789012:ExampleTopic",
"Subject": "EC2 Run Command Notification us-east-1",
"Message": "{\"commandId\":\"6f69316a-e502-5a20-99bc-2408825b6dee\",\"documentName\":\"AWS-RunPatchBaseline\",\"instanceId\":\"i-99999999999999999\",\"requestedDateTime\":\"2023-12-14T10:48:47.127Z\",\"status\":\"Success\",\"detailedStatus\":\"Success\",\"eventTime\":\"2023-12-14T10:52:22.114Z\"}",
"Timestamp": "2023-12-14T10:52:22.173Z",
"SignatureVersion": "1",
"Signature": "EXAMPLE",
"SigningCertUrl": "EXAMPLE",
"UnsubscribeUrl": "EXAMPLE",
"MessageAttributes": {}
}
}
]
}
68 changes: 68 additions & 0 deletions functions/notify_slack.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,70 @@ def format_aws_health(message: Dict[str, Any], region: str) -> Dict[str, Any]:
],
}

class SSMRunCommandStatus(Enum):
"""Maps System Manager Run Command status to Slack message format color"""

Success = "good"
TimedOut = "danger"
Failed = "danger"

def format_ssm_run_command(message: Dict[str, Any], region: str) -> Dict[str, Any]:
"""
Format AWS System Manager Run Document event into Slack message format

:params message: SNS message body containing AWS Health event
:params region: AWS region where the event originated from
:returns: formatted Slack message payload
"""

return {
"color": SSMRunCommandStatus[message.get('status')].value,
"text": f"EC2 Run Command Notification {region}",
"fallback": f"EC2 Run Command Notification {region}",
"fields": [
{
"title": "Command Id",
"value": f"`{message.get('commandId')}`",
"short": True
},
{
"title": "Region",
"value": f"`{region}`",
"short": True,
},
{
"title": "Document Name",
"value": f"`{message.get('documentName')}`",
"short": False,
},
{
"title": "Instance Id",
"value": f"`{message.get('instanceId')}`",
"short": False,
},
{
"title": "Requested Time",
"value": f"`{message.get('requestedDateTime')}`",
"short": True,
},
{
"title": "Event Time",
"value": f"`{message.get('eventTime')}`",
"short": True,
},
{
"title": "Status",
"value": f"`{message.get('status')}`",
"short": False,
},
{
"title": "Detailed Status",
"value": f"`{message.get('detailedStatus')}`",
"short": False,
}
],
}


def format_default(
message: Union[str, Dict], subject: Optional[str] = None
Expand Down Expand Up @@ -344,6 +408,10 @@ def get_slack_message_payload(
notification = format_aws_health(message=message, region=message["region"])
attachment = notification

elif "documentName" in message:
notification = format_ssm_run_command(message=message, region=region)
attachment = notification

elif "attachments" in message or "text" in message:
payload = {**payload, **message}

Expand Down
Loading