forked from pulumi/examples
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add 'aws-go-console-slack-notification' example. (pulumi#587)
* Add a Go example to notify Slack when changes are made via the AWS Console. * Use `regions` config list to provision multiple regions. * Use the AWS SDK instead of config to get list of regions. * Format Slack message values as code with backticks. * Update README.md about multi-region deployment. * Ignore changes on eventSelectors due to upstream Terraform bug. hashicorp/terraform-provider-aws#11712 * Minor casing and function name change. * Change logical name of AWS provider. * Add bucket lifecycle support and create `getRegions` function. * Allow regions to be specified in config, otherwise use AWS SDK. * Update `aws-go-console-slack-notification` for additional user agents and include errorCode. * Add Bucket Public Access Block, configurable resource name prefix. Move to Go modules. * Update for Pulumi 2.0. * Re-order resource options to be consistent. Remove `dep` references.
- Loading branch information
Cameron Stokes
committed
Apr 22, 2020
1 parent
24343b7
commit f0ba1c8
Showing
8 changed files
with
752 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
handler/dist |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
build:: | ||
GOOS=linux GOARCH=amd64 go build -o ./handler/dist/handler ./handler/handler.go | ||
zip -j ./handler/dist/handler.zip ./handler/dist/handler |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
name: aws-go-console-slack-notification | ||
runtime: go | ||
description: Deploy necessary resources to notify Slack when an operation is performed via the AWS Console. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
# AWS Console Change Slack Notifier in Go | ||
|
||
This example deploys a Lambda function and relevant CloudTrail and CloudWatch resources to send a | ||
Slack notification for any resource operation that is performed via the AWS Console. | ||
|
||
Note: This application sets up the necessary infrastructure across _each_ AWS region in your | ||
account that is `opt-in-not-required` or `opted-in`. The Pulumi application uses the | ||
[DescribeRegions](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeRegions.html) API | ||
via [aws-sdk-go](https://github.com/aws/aws-sdk-go) to query for available regions. | ||
|
||
## Deploying the App | ||
|
||
To deploy your infrastructure, follow the below steps. | ||
|
||
### Prerequisites | ||
|
||
1. [Install Pulumi](https://www.pulumi.com/docs/get-started/install/) | ||
1. [Configure AWS Credentials](https://www.pulumi.com/docs/intro/cloud-providers/aws/setup/) | ||
|
||
### Steps | ||
|
||
After cloning this repo, run these commands from the working directory: | ||
|
||
1. Build the handler: | ||
|
||
- For developers on Linux and macOS: | ||
|
||
```bash | ||
make | ||
``` | ||
- For developers on Windows: | ||
- Get the `build-lambda-zip` tool: | ||
```bash | ||
set GO111MODULE=on | ||
go.exe get -u github.com/aws/aws-lambda-go/cmd/build-lambda-zip | ||
``` | ||
- Use the tool from your GOPATH: | ||
```bash | ||
set GOOS=linux | ||
set GOARCH=amd64 | ||
set CGO_ENABLED=0 | ||
go build -o handler\dist\handler handler\handler.go | ||
%USERPROFILE%\Go\bin\build-lambda-zip.exe -o handler\dist\handler.zip handler\dist\handler | ||
``` | ||
|
||
1. Create a new Pulumi stack, which is an isolated deployment target for this example: | ||
|
||
```bash | ||
pulumi stack init | ||
``` | ||
|
||
1. Set the required configuration variables for this program: | ||
|
||
```bash | ||
pulumi config set slackWebhookURL 'YOUR_SLACK_WEBHOOK_URL' | ||
``` | ||
|
||
1. Execute the Pulumi program to create our lambda: | ||
|
||
```bash | ||
pulumi up | ||
``` | ||
|
||
1. Perform a change in the AWS Console and look for a notification in your Slack channel. Note: you | ||
must perform a _write_ such as adding or removing tags from a resource, launching an instance, or | ||
deleting a resource. | ||
|
||
1. From there, feel free to experiment. Simply making edits, rebuilding your handler, and running | ||
`pulumi up` will update your lambda. Customize the Slack message username or text with the following | ||
configuration values: | ||
|
||
```bash | ||
pulumi config set slackMessageUsername 'Console Change Monitor' | ||
pulumi config set slackMessageText ':warning: Somebody made a change in the console!' | ||
``` | ||
|
||
1. Afterwards, destroy your stack and remove it: | ||
|
||
```bash | ||
pulumi destroy --yes | ||
pulumi stack rm --yes | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
module github.com/pulumi/examples/aws-go-console-slack-notification | ||
|
||
go 1.14 | ||
|
||
require ( | ||
github.com/aws/aws-lambda-go v1.16.0 // indirect | ||
github.com/aws/aws-sdk-go v1.30.8 | ||
github.com/pulumi/pulumi-aws/sdk/v2 v2.1.0 | ||
github.com/pulumi/pulumi/sdk/v2 v2.0.0 | ||
) |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"log" | ||
"net/http" | ||
"os" | ||
"strings" | ||
|
||
"github.com/aws/aws-lambda-go/events" | ||
"github.com/aws/aws-lambda-go/lambda" | ||
) | ||
|
||
func handler(ctx context.Context, event events.CloudWatchEvent) { | ||
var eventDetail eventDetail | ||
if err := json.Unmarshal(event.Detail, &eventDetail); err != nil { | ||
panic(err) | ||
} | ||
|
||
// see https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-event-reference-record-contents.html | ||
if eventDetail.UserAgent != "signin.amazonaws.com" && | ||
eventDetail.UserAgent != "console.ec2.amazonaws.com" && | ||
!strings.HasPrefix(eventDetail.UserAgent, "[S3Console/0.4, aws-internal/3 ") { | ||
fmt.Printf("Skipping event [%s] from user agent [%s]", eventDetail.EventName, eventDetail.UserAgent) | ||
return | ||
} | ||
|
||
fmt.Printf("Processing event [%s] from user [%s]", eventDetail.EventName, eventDetail.UserIdentity.UserName) | ||
fmt.Printf("%s", event.Detail) | ||
|
||
slackMessageUsername := os.Getenv("SLACK_WEBHOOK_USERNAME") | ||
slackMessageText := os.Getenv("SLACK_MESSAGE_TEXT") | ||
if slackMessageText == "" { | ||
slackMessageText = ":rotating_light: A change was made via the AWS Console." | ||
} | ||
|
||
message := &slackMessage{ | ||
Username: slackMessageUsername, | ||
Text: slackMessageText, | ||
Attachments: []slackMessageAttachment{ | ||
slackMessageAttachment{ | ||
Fields: []slackMessageAttachmentField{ | ||
getSlackMessageAttachmentField("AWS Account", eventDetail.UserIdentity.AWSAccountID), | ||
getSlackMessageAttachmentField("Region", eventDetail.AWSRegion), | ||
getSlackMessageAttachmentField("Event Source", eventDetail.EventSource), | ||
getSlackMessageAttachmentField("Event Name", eventDetail.EventName), | ||
getSlackMessageAttachmentField("User", eventDetail.UserIdentity.UserName), | ||
getSlackMessageAttachmentField("Result", getResultText(eventDetail.ErrorCode)), | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
bytesRepresentation, err := json.Marshal(message) | ||
if err != nil { | ||
log.Fatalln(err) | ||
} | ||
|
||
_, err = http.Post(os.Getenv("SLACK_WEBHOOK_URL"), "application/json", bytes.NewBuffer(bytesRepresentation)) | ||
if err != nil { | ||
log.Fatalln(err) | ||
} | ||
} | ||
|
||
func getSlackMessageAttachmentField(title string, value string) slackMessageAttachmentField { | ||
return slackMessageAttachmentField{ | ||
Title: title, | ||
Value: fmt.Sprintf("`%s`", value), | ||
Short: true, | ||
} | ||
} | ||
|
||
func getResultText(errorCode string) string { | ||
if errorCode != "" { | ||
return errorCode | ||
} | ||
return "Success" | ||
} | ||
|
||
type eventDetail struct { | ||
UserIdentity userIdentity `json:"userIdentity"` | ||
UserAgent string `json:"userAgent"` | ||
EventSource string `json:"eventSource"` | ||
EventName string `json:"eventName"` | ||
AWSRegion string `json:"awsRegion"` | ||
ErrorCode string `json:"errorCode"` | ||
} | ||
|
||
type userIdentity struct { | ||
AWSAccountID string `json:"accountId"` | ||
UserName string `json:"userName"` | ||
} | ||
|
||
type slackMessage struct { | ||
Username string `json:"username"` | ||
Text string `json:"text"` | ||
Attachments []slackMessageAttachment `json:"attachments"` | ||
} | ||
|
||
type slackMessageAttachment struct { | ||
Pretext string `json:"pretext"` | ||
Text string `json:"text"` | ||
Fields []slackMessageAttachmentField `json:"fields"` | ||
} | ||
|
||
type slackMessageAttachmentField struct { | ||
Title string `json:"title"` | ||
Value string `json:"value"` | ||
Short bool `json:"short"` | ||
} | ||
|
||
func main() { | ||
lambda.Start(handler) | ||
} |
Oops, something went wrong.