Skip to main content

Here is a quick guide to send AWS Guardduty notifications to your Slack Channel. In this example, we will link a main AWS Account with its members by using Terraform.

AWS Account Data flow

AWS Guardduty is a threat detection service provided by AWS, cost effective and easily implemented. The following guide is using terraform files which are stored in the following GitHub repository.

I. First off

By using Terraform 12, start by declaring all your AWS Accounts and their aliases into a specific file ( in this case):

Once completed, add your

terraform {
  required_version = "~> 0.12.0"

  backend "s3" {
    acl     = "bucket-owner-full-control"
    bucket  = "tf-state-bucket-guardduty"
    encrypt = true
    key     = "aws.tfstate"
    region  = "eu-west-1"
}Code language: JavaScript (javascript)

The acl bucket-owner-full-control allow the main AWS account to keep control over the state file, especially when you assume multiple profile, you can be quite handy.

II. Modules

This project is using multiples modules as follow:

  • AWS Guardduty Master
  • AWS Guardduty Members
  • AWS Guardduty Invitations
  • AWS Guardduty Slack notifications

III. Lambda function

This project is using a bash script for installing / testing and packaging the lambda function:

#!/usr/bin/env bash
# Create python packages for lambda
#description    :This script will install pip packages, run pylint and pytest and finally zip python scripts
#author         :Oli
#date           :07/01/2020
#version        :0.1
#bash_version   :3.2.57(1)-release

set -o errexit
set -o pipefail
set -o nounset

function install_packages() {
  pip install -r requirements_test.txt

function zip_python() {
  pushd sns-guardduty-slack/
  zip -r ../
  mv ../

function test_python() {
  pushd sns-guardduty-slack/
}Code language: PHP (php)

Before applying Terraform plan, the zip file would have to be present on the local file system.

Prepare a virtual environment for python before running this on your terminal:

$ virtualenv -p python3 venv
Running virtualenv with interpreter /usr/local/bin/python3
Using base prefix '/usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7'
New python executable in /Users/oli/Documents/venv/bin/python3.7
Also creating executable in /Users/oli/Documents/venv/bin/python
Installing setuptools, pip, wheel...
done.$ source venv/bin/activate

IV. Slack configuration

Slack has now shifted to Slack API for creating and installing your applications, it’s really easy to get started

Enable Incoming Webhooks
Once you select your channel, you’ll receive this message

V. SSM parameters

This system is using SSM parameters to fetch the 3 following variables:

  • Slack Channel
  • Slack Incoming webhook
  • Email address used by the root account

Just create these three variables in the main account:

AWS System Manager

VI. Deploy!

Package your lambda script first:

21:50 $ ./
Collecting pylint
Downloading pylint-2.4.4-py3-none-any.whl (302 kB)
|████████████████████████████████| 302 kB 1.4 MB/s
Collecting mccabe<0.7,>=0.6
Using cached mccabe-0.6.1-py2.py3-none-any.whl (8.6 kB)
Collecting astroid<2.4,>=2.3.0
Downloading astroid-2.3.3-py3-none-any.whl (205 kB)
|████████████████████████████████| 205 kB 1.9 MB/s
Collecting isort<5,>=4.2.5
Using cached isort-4.3.21-py2.py3-none-any.whl (42 kB)
Processing /Users/oli/Library/Caches/pip/wheels/d7/de/2e/efa132238792efb6459a96e85916ef8597fcb3d2ae51590dfd/wrapt-1.11.2-cp37-cp37m-macosx_10_14_x86_64.whl
Collecting six~=1.12
Downloading six-1.14.0-py2.py3-none-any.whl (10 kB)
Collecting typed-ast<1.5,>=1.4.0; implementation_name == "cpython" and python_version < "3.8"
Downloading typed_ast-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl (223 kB)
|████████████████████████████████| 223 kB 9.4 MB/s
Collecting lazy-object-proxy==1.4.*
Using cached lazy_object_proxy-1.4.3-cp37-cp37m-macosx_10_13_x86_64.whl (19 kB)
Installing collected packages: mccabe, wrapt, six, typed-ast, lazy-object-proxy, astroid, isort, pylint
Successfully installed astroid-2.3.3 isort-4.3.21 lazy-object-proxy-1.4.3 mccabe-0.6.1 pylint-2.4.4 six-1.14.0 typed-ast-1.4.1 wrapt-1.11.2
~/Documents/AWS_Guardduty_Slack_integration/modules/sns-guardduty-slack ~/Documents/AWS_Guardduty_Slack_integration/modules------------------------------------
Your code has been rated at 10.00/10~/Documents/AWS_Guardduty_Slack_integration/modules
~/Documents/AWS_Guardduty_Slack_integration/modules/sns-guardduty-slack ~/Documents/AWS_Guardduty_Slack_integration/modules
adding: (deflated 68%)

Then, run terraform init command:

17:17 $ terraform init
Initializing modules...
- aws_guardduty_invite_member in modules/guardduty-invitation
- aws_guardduty_master in modules/guardduty-master
- aws_guardduty_member in modules/guardduty-member
- aws_guardduty_sns_notifications in modules/sns-guardduty-slackInitializing the backend...Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "aws" (hashicorp/aws) 2.55.0...Terraform has been successfully initialized!You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

Finally, apply the changes with Terraform:

17:39 $ terraform apply Refreshing state... Refreshing state... Refreshing state...An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
<= read (data resources)Terraform will perform the following actions:# module.aws_guardduty_invite_member.aws_guardduty_member.members will be created
+ resource "aws_guardduty_member" "members" {
+ account_id = "123456789012"
+ detector_id = (known after apply)
+ email = "[email protected]"
+ id = (known after apply)
+ invitation_message = "please accept guardduty invitation"
+ invite = true
+ relationship_status = (known after apply)
}# module.aws_guardduty_master.aws_cloudwatch_event_rule.main will be created
+ resource "aws_cloudwatch_event_rule" "main" {
+ arn = (known after apply)
+ description = "AWS GuardDuty event findings"
+ event_pattern = jsonencode(
+ detail = {
+ severity = [
+ 3,
+ 3,
+ 3.1,
+ 3.2,
+ 3.3,
+ 3.4,
+ 3.5,
+ 3.6,
+ 3.7,
+ 3.8,
+ 3.9,
+ 4,
+ 4,
+ 4.1,
+ 4.2,
+ 4.3,
+ 4.4,
+ 4.5,
+ 4.6,

This code 👆is a truncated output when you use the apply command, just confirm by typing “yes” if you’re happy with what you see.

Apply complete! Resources: 0 added, 16 changed, 0 destroyed.

Congratulation 🎉 a state file should be present in your bucket following this stage:

Terraform state file appears after applying the plan

VII. Testing your deployment

After logging to AWS Console, search for Guardduty tabs and go into settings. You can generate sample event from this window by clicking on “Generate sample finding” as follow:

Generate finding for testing your deployment

Once triggered, you should start to see some messages appearing in Slack as follow: