How to Configure Automated Incident Response for Amazon GuardDuty Findings with Terraform
In this tutorial, you will learn how to configure an AWS Security solution using Terraform. You will make use of Amazon GuardDuty, Amazon SNS, AWS Lambda, and Amazon EvenBridge services.
Step 1. Load the Initial Configuration
Step 2. Access Cloud9 and Initialize Terraform
Step 3: Create an S3 Bucket to Store a Threat List
Step 4: Create the GuardDuty Terraform Modules
Step 5: Create the SNS Terraform Module
Step 6: Create the EventBridge Terraform Module
Step 7: Create the Lambda Terraform Module
Step 8: Apply The Configuration to your AWS Account
About | |
---|---|
β AWS experience | 200 - Intermediate |
β± Time to complete | 60 minutes |
π° Cost to complete | < $2.00 USD |
𧩠Prerequisites | - AWS Account |
π’ Feedback | Any feedback, issues, or just a π / π ? |
πΎ Code | Download the code |
β° Last Updated | 2023-04-20 |
- A "malicious" host interacts with a "compromised" host causing GuardDuty to report a finding.
- The finding will be matched in an EventBridge rule that you will create using Terraform. The EventBridge rule does the following two things:
- It triggers an SNS rule that you will create using Terraform. This SNS rule will send an email to a defined admin with easy to read text explaining the finding.
- It triggers a Lambda function that you will create using Terraform. The Lambda function moves the compromised host to a forensic security group where it is isolated for further investigation.
create stack
button.gd-iac-initial.yml
file from the sample code repo provided above. Then click Next.Terraform will apply configuration in US-WEST-2. The Cloudformation template created the Cloud9 instance in US-WEST-1. This is intentional. The idea is that you can do your verifications seeing only what you create with Terraform.
modules/s3/variables.tf
for the vpc_id
.modules/s3/main.tf
file, get the current AWS user account number and create an S3 bucket resource.The following code will create two S3 buckets. One bucket will store flow logs. We won't use them in this tutorial, but they will be generated, and you can explore them if you wish. Flow log data is what GuardDuty uses, but you don't have to enable them for GuardDuty to use the data. We only enable them here so you can see them. The other bucket we create will be used to store our Threat List.
bucket_id
and bucket_arn
values in the modules/s3/outputs.tf
file.root/main.tf
file and add the S3 bucket.Why are you creating an S3 bucket? You are primarily creating an S3 bucket to hold a text file that will be referred to by GuardDuty. As mentioned before, GuardDuty uses two types of lists: a Trusted IP list and a Threat IP list. Our S3 bucket will host the Threat IP List. The secondary reason is to store VPC flow logs. GuardDuty uses VPC flow logs, but you do not need to enable them for GuardDuty to use them. Here, we enable VPC FLow Logs so that we can use the data in other tools if we want to later on.
modules/guardduty/variables.tf
file. Here you will need to create two variables. The first is a variable called bucket
which we will use to define the S3 bucket threat list details. The second will be for the malicious IP that we will have added to the bucket.modules/guardduty/main.tf
file.enabled
value to true
in our example and also change the finding_publishing_frequency
to 15 minutes. The default is one hour.var.malicious_ip
.aws_guardduty_threatintelset
, that tells GuardDuty that it should use (this is what activate = true
does) the file located at the location
defined.For GuardDuty, we don't need to output anything at this time.
root/main.tf
file and call the GuardDuty module. We need to provide the bucket ID and the malicious IP. You can see that these are coming from the S3 module and the compute module.modules/sns/variables.tf
file, you will need to create two variables:sns_name
to name the SNS topic that we will create.email
to hold the email address we will use to subscribe to our notifications.
modules/sns/main.tf
file.gd_sns_topic
by Terraform. In the AWS console, this will be called "GuardDuty-Example." This is because we are calling the variable var.sns_name
, and it has a default set to "GuardDuty-Example."arn
and policy
are required values. The policy being created here is an AWS IAM Policy Document. This policy document is allowing the service principal events.amazonaws.com
to publish to the topic.endpoint_auto_confirm
being set to false
means that the owner of the email will get an email with a link that they must click to subscribe to the notifications.modules/sns/outputs.tf
file, we want to output the ARN of the topic so we can reference that in the EventBridge configuration we will perform later.root/main.tf
file and add the SNS topic. This is where you will set the email address to be subscribed.Note that you will need to enter your email address in the code below.
modules/eventbridge/variables.tf
file.modules/eventbridge/main.tf
file. You will need to define the source and the type of event we are looking for.The event pattern defined above looks at events from the source service, in this case GuardDuty, and looks for a finding with the detail type of "UnauthorizedAccess:EC2/MaliciousIPCaller.Custom."
This finding will not show up; it's primarily there for you to practice creating the resources.
root/main.tf
file and add the EventBridge rule.modules/lambda/main.tf
by creating the IAM policy document. This is the trust relationship for the policy.The Python code we will use for the Lambda function has been created for you. The code can be found in the /modules/lambda/code folder, and it's called index.py.
modules/lambda/variables.tf
file with the following variables:modules/lambda/main.tf
file and create the Lambda function resource. Note that in the code block below, we are using Python 3.9. Also, we are referencing the python code we zipped in index.zip. And lastly we are setting a few environment variables in the resource: INSTANCE_ID
, FORENSICS_SG
, and TOPIC_ARN
. These will be passed into our Lambda function environment from the variables that we created.root/main.tf
file call the Lambda module, set the SNS topic ARN, the Compromised Instance ID, and the Forensic Security group. Note that these values are coming from the GuardDuty Module, the Compute Module, and the VPC Module.forensic-security-group
, we need to output it. In the root/outputs.tf
file and output the Security group ID.modules/eventbridge/main.tf
file. Add an event target resource for the Lambda Function that looks at the aws_cloudwatch_event_rule.GuardDuty-Event-EC2-MaliciousIPCaller.name
rule and sets the target ID to GuardDuty-Example-Remediation
. You will need the ARN of the Lambda Function here. This can be output from the Lambda Module.modules/lambda/outputs.tf
) if you haven't done so already.modules/eventbridge/variables.tf
).lambda_remediation_function_arn
to the root/main.tf
file. This goes in the EventBridge Rule which is already created. The output below is the entire code block, some of which already exists. Be sure to only add the lambda_remediation_function_arn = module.lambda.lambda_remediation_function_arn
code to the existing block.terraform init
. This will initialize all of the modules that you have added code to in this tutorial. The output should resemble the following.Note that if you already have GuardDuty enabled in your account the apply will fail. If this happens, you can disable GuardDuty and run the terraform apply again.
terraform plan
.terraform apply
to push the changes to AWS. Once applied your should have an output that resembles the following:Depending on how long you have waited, if the remediation Lambda function is already applied you may not see them in the same group.
terraform destroy
command from the CLI of our Cloud9 instance.Any opinions in this post are those of the individual author and may not reflect the opinions of AWS.