├── .github
└── workflows
│ └── validate.yml
├── .gitignore
├── .markdownlintrc
├── .pre-commit-config.yaml
├── .terraform-docs.yml
├── LICENSE
├── README.md
├── bin
└── make-test
├── event-pattern.json
├── examples
├── no-pagerduty
│ ├── main.tf
│ ├── providers.tf
│ └── variables.tf
└── simple
│ ├── main.tf
│ ├── providers.tf
│ └── variables.tf
├── main.tf
├── renovate.json
├── variables.tf
└── versions.tf
/.github/workflows/validate.yml:
--------------------------------------------------------------------------------
1 | name: validate-tf
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 | branches:
9 | - main
10 |
11 | jobs:
12 | validate-tf:
13 | uses: trussworks/shared-actions/.github/workflows/validate-tf.yml@main
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .terraform
3 | terraform.tfstate
4 | terraform.tfstate.backup
5 | terraform.tfstate.*.backup
6 |
--------------------------------------------------------------------------------
/.markdownlintrc:
--------------------------------------------------------------------------------
1 | {
2 | "default": true,
3 | "first-header-h1": false,
4 | "first-line-h1": false,
5 | "line_length": false,
6 | "no-multiple-blanks": false,
7 | "no-inline-html": false
8 | }
9 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: https://github.com/pre-commit/pre-commit-hooks
3 | rev: v4.4.0
4 | hooks:
5 | - id: check-json
6 | - id: check-merge-conflict
7 | - id: check-yaml
8 | - id: detect-private-key
9 | - id: pretty-format-json
10 | args:
11 | - --autofix
12 | - id: trailing-whitespace
13 | - id: check-symlinks
14 | - id: end-of-file-fixer
15 | - id: mixed-line-ending
16 |
17 | - repo: https://github.com/executablebooks/mdformat
18 | rev: 0.7.16
19 | hooks:
20 | - id: mdformat
21 | additional_dependencies:
22 | - mdformat-gfm
23 | - mdformat-toc
24 | # mdformat fights with terraform_docs
25 | exclude: README.m(ark)?d(own)?
26 |
27 | - repo: https://github.com/igorshubovych/markdownlint-cli
28 | rev: v0.33.0
29 | hooks:
30 | - id: markdownlint
31 |
32 | - repo: https://github.com/detailyang/pre-commit-shell
33 | rev: 1.0.5
34 | hooks:
35 | - id: shell-lint
36 |
37 | - repo: https://github.com/antonbabenko/pre-commit-terraform
38 | rev: v1.77.1
39 | hooks:
40 | - id: terraform_fmt
41 |
--------------------------------------------------------------------------------
/.terraform-docs.yml:
--------------------------------------------------------------------------------
1 | settings:
2 | html: false
3 | anchor: false
4 | formatter: "markdown table"
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2020, TrussWorks, Inc.
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Enable AWS GuardDuty and configures any findings to be sent to and SNS topic.
2 |
3 | Creates the following resources:
4 |
5 | - CloudWatch event rule to filter GuardDuty Findings
6 | - CloudWatch event target to send to SNS topic formatted as `GuardDuty finding:
`
7 |
8 | Optionally, it can also create the GuardDuty detector as well.
9 |
10 | ## Usage
11 |
12 | ```hcl
13 | module "guardduty-notifications" {
14 | source = "trussworks/guardduty-notifications/aws"
15 | version = "5.0.0"
16 |
17 | sns_topic_slack_arn = aws_sns_topic.slack.arn
18 | sns_topic_pagerduty_arn = aws_sns_topic.pagerduty.arn
19 | }
20 | ```
21 |
22 | ## Upgrade Notice v4.x.x to v5.x.x
23 |
24 | - The `sns_topic_slack` and `sns_topic_pagerduty` variables have been
25 | renamed to `sns_topic_slack_arn` and `sns_topic_pagerduty_arn`; they
26 | are also taking ARNs as values, and not `aws_sns_topic` objects. We
27 | made this change to better handle the outputs of the `notify-slack`
28 | Terraform module, which outputs names and ARNs, but not objects.
29 |
30 | ## Upgrade Notice v2.x.x to v3.x.x
31 |
32 | Version 3 makes a number of changes to the module that will break if it
33 | is updated in place. Specifically:
34 |
35 | - The GuardDuty detector is now an optional part of the module, and
36 | defaults to off; if you are leaving the GuardDuty detector in this
37 | module, you will need to add "create_detector = true" as a parameter
38 | and do a `terraform state mv` of the detector like so:
39 |
40 | ```console
41 | terraform state mv module.module_name.aws_guardduty_detector.main module.module_name.aws_guardduty_detector.main[0]
42 | ```
43 |
44 | - The `sns_topic_name_slack` and `sns_topic_name_pagerduty` variables
45 | have been renamed `sns_topic_slack` and `sns_topic_pagerduty` because
46 | they are not actually names, but the actual SNS topic objects.
47 |
48 |
49 | ## Requirements
50 |
51 | | Name | Version |
52 | |------|---------|
53 | | terraform | >= 1.0 |
54 | | aws | >= 3.0 |
55 |
56 | ## Providers
57 |
58 | | Name | Version |
59 | |------|---------|
60 | | aws | >= 3.0 |
61 |
62 | ## Modules
63 |
64 | No modules.
65 |
66 | ## Resources
67 |
68 | | Name | Type |
69 | |------|------|
70 | | [aws_cloudwatch_event_rule.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource |
71 | | [aws_cloudwatch_event_target.pagerduty](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource |
72 | | [aws_cloudwatch_event_target.slack](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource |
73 | | [aws_guardduty_detector.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/guardduty_detector) | resource |
74 |
75 | ## Inputs
76 |
77 | | Name | Description | Type | Default | Required |
78 | |------|-------------|------|---------|:--------:|
79 | | create\_detector | Create GuardDuty detector | `bool` | `false` | no |
80 | | pagerduty\_notifications | Enable PagerDuty notifications for GuardDuty findings | `bool` | `true` | no |
81 | | slack\_notifications | Enable Slack notifications for GuardDuty findings | `bool` | `true` | no |
82 | | sns\_topic\_pagerduty\_arn | PagerDuty SNS Topic ARN | `string` | `""` | no |
83 | | sns\_topic\_slack\_arn | Slack SNS Topic ARN | `string` | `""` | no |
84 |
85 | ## Outputs
86 |
87 | No outputs.
88 |
89 |
90 | ## Developer Setup
91 |
92 | Install dependencies (macOS)
93 |
94 | ```shell
95 | brew install pre-commit go terraform terraform-docs
96 | pre-commit install --install-hooks
97 | ```
98 |
--------------------------------------------------------------------------------
/bin/make-test:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -eu -o pipefail
4 |
5 | go_test_output="/tmp/go-test.out"
6 |
7 | go test -short -count 1 -v -timeout 90m github.com/trussworks/terraform-aws-guardduty-notifications/test/... | tee "${go_test_output}"
8 |
9 | # Check if we are running tests inside of CircleCI by checking for a $CIRCLECI
10 | # environment variable. The dash after $CIRCLECI substitutes a null value if
11 | # CIRCLECI is unset. This prevents unbound variable errors
12 | if [[ -n ${CIRCLECI-} ]]; then
13 | mkdir -p "${TEST_RESULTS}"/gotest
14 | go-junit-report < "${go_test_output}" \
15 | > "${TEST_RESULTS}/gotest/go-test-report.xml"
16 | fi
17 |
--------------------------------------------------------------------------------
/event-pattern.json:
--------------------------------------------------------------------------------
1 | {
2 | "detail-type": [
3 | "GuardDuty Finding"
4 | ],
5 | "source": [
6 | "aws.guardduty"
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/examples/no-pagerduty/main.tf:
--------------------------------------------------------------------------------
1 | resource "aws_sns_topic" "slack" {
2 | name = var.sns_topic_name_slack
3 | }
4 |
5 | module "guardduty-notifications" {
6 | source = "../../"
7 |
8 | create_detector = false
9 |
10 | pagerduty_notifications = false
11 |
12 | sns_topic_slack_arn = aws_sns_topic.slack.arn
13 | }
14 |
--------------------------------------------------------------------------------
/examples/no-pagerduty/providers.tf:
--------------------------------------------------------------------------------
1 | provider "aws" {
2 | version = "~> 3.0"
3 | }
4 |
--------------------------------------------------------------------------------
/examples/no-pagerduty/variables.tf:
--------------------------------------------------------------------------------
1 | variable "sns_topic_name_slack" {
2 | type = string
3 | }
4 |
--------------------------------------------------------------------------------
/examples/simple/main.tf:
--------------------------------------------------------------------------------
1 | resource "aws_sns_topic" "slack" {
2 | name = var.sns_topic_name_slack
3 | }
4 |
5 | resource "aws_sns_topic" "pagerduty" {
6 | name = var.sns_topic_name_pagerduty
7 | }
8 |
9 |
10 | module "guardduty-notifications" {
11 | source = "../../"
12 |
13 | create_detector = false
14 |
15 | sns_topic_slack_arn = aws_sns_topic.slack.arn
16 | sns_topic_pagerduty_arn = aws_sns_topic.pagerduty.arn
17 | }
18 |
--------------------------------------------------------------------------------
/examples/simple/providers.tf:
--------------------------------------------------------------------------------
1 | provider "aws" {
2 | version = "~> 3.0"
3 | }
4 |
--------------------------------------------------------------------------------
/examples/simple/variables.tf:
--------------------------------------------------------------------------------
1 | variable "sns_topic_name_slack" {
2 | type = string
3 | }
4 |
5 | variable "sns_topic_name_pagerduty" {
6 | type = string
7 | }
8 |
--------------------------------------------------------------------------------
/main.tf:
--------------------------------------------------------------------------------
1 | #
2 | # GuardDuty
3 | #
4 |
5 | resource "aws_guardduty_detector" "main" {
6 | count = var.create_detector ? 1 : 0
7 |
8 | enable = true
9 | }
10 |
11 | #
12 | # CloudWatch Event
13 | #
14 |
15 | resource "aws_cloudwatch_event_rule" "main" {
16 | name = "guardduty-finding-events"
17 | description = "AWS GuardDuty event findings"
18 | event_pattern = file("${path.module}/event-pattern.json")
19 | }
20 |
21 | # More details about the response syntax can be found here:
22 | # https://docs.aws.amazon.com/guardduty/latest/ug/get-findings.html#get-findings-response-syntax
23 | resource "aws_cloudwatch_event_target" "slack" {
24 | count = var.slack_notifications ? 1 : 0
25 |
26 | rule = aws_cloudwatch_event_rule.main.name
27 | target_id = "send-to-sns-slack"
28 | arn = var.sns_topic_slack_arn
29 |
30 | input_transformer {
31 | input_paths = {
32 | title = "$.detail.title"
33 | description = "$.detail.description"
34 | eventTime = "$.detail.service.eventFirstSeen"
35 | region = "$.detail.region"
36 | }
37 |
38 | input_template = "\"GuardDuty finding in first seen at : \""
39 | }
40 | }
41 |
42 | resource "aws_cloudwatch_event_target" "pagerduty" {
43 | count = var.pagerduty_notifications ? 1 : 0
44 |
45 | rule = aws_cloudwatch_event_rule.main.name
46 | target_id = "send-to-sns-pagerduty"
47 | arn = var.sns_topic_pagerduty_arn
48 | }
49 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "config:base",
4 | ":disableDependencyDashboard"
5 | ],
6 | "labels": [
7 | "dependencies"
8 | ],
9 | "packageRules": [
10 | {
11 | "automerge": true,
12 | "description": "Automerge all updates except major versions",
13 | "matchUpdateTypes": [
14 | "patch",
15 | "pin",
16 | "digest",
17 | "minor"
18 | ]
19 | },
20 | {
21 | "description": "Tag the waddlers Github Team for major updates",
22 | "matchUpdateTypes": [
23 | "major"
24 | ],
25 | "reviewers": [
26 | "team:waddlers"
27 | ]
28 | },
29 | {
30 | "automerge": true,
31 | "description": "Group minor and patch updates into a single PR",
32 | "groupName": "dependencies",
33 | "managers": [
34 | "terraform",
35 | "pre-commit",
36 | "dockerfile",
37 | "github-actions"
38 | ],
39 | "matchUpdateTypes": [
40 | "minor",
41 | "patch"
42 | ]
43 | }
44 | ],
45 | "schedule": [
46 | "every weekend"
47 | ],
48 | "separateMinorPatch": true,
49 | "timezone": "America/Los_Angeles"
50 | }
51 |
--------------------------------------------------------------------------------
/variables.tf:
--------------------------------------------------------------------------------
1 | variable "create_detector" {
2 | description = "Create GuardDuty detector"
3 | type = bool
4 | default = false
5 | }
6 |
7 | variable "pagerduty_notifications" {
8 | description = "Enable PagerDuty notifications for GuardDuty findings"
9 | type = bool
10 | default = true
11 | }
12 |
13 | variable "slack_notifications" {
14 | description = "Enable Slack notifications for GuardDuty findings"
15 | type = bool
16 | default = true
17 | }
18 |
19 | variable "sns_topic_slack_arn" {
20 | description = "Slack SNS Topic ARN"
21 | type = string
22 | default = ""
23 | }
24 |
25 | variable "sns_topic_pagerduty_arn" {
26 | description = "PagerDuty SNS Topic ARN"
27 | type = string
28 | default = ""
29 | }
30 |
--------------------------------------------------------------------------------
/versions.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.0"
3 |
4 | required_providers {
5 | aws = ">= 3.0"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------