Setting up AWS GuardDuty with Terraform

A comprehensive guide to configuring Amazon GuardDuty for threat detection using Terraform Infrastructure as Code

Setting up AWS GuardDuty with Terraform

Amazon GuardDuty is a threat detection service that continuously monitors for malicious activity and unauthorized behavior. This guide shows how to set up GuardDuty using Terraform.

Prerequisites

  • AWS CLI configured
  • Terraform installed
  • Understanding of security monitoring
  • Basic knowledge of AWS Organizations (optional)

Project Structure

aws-guardduty-terraform/
├── main.tf
├── variables.tf
├── outputs.tf
└── terraform.tfvars

Basic GuardDuty Configuration

# main.tf
provider "aws" {
  region = var.aws_region
}

# Enable GuardDuty
resource "aws_guardduty_detector" "main" {
  enable = true

  datasources {
    s3_logs {
      enable = true
    }
    kubernetes {
      audit_logs {
        enable = true
      }
    }
    malware_protection {
      scan_ec2_instance_with_findings {
        enable = true
      }
    }
  }

  finding_publishing_frequency = "FIFTEEN_MINUTES"

  tags = {
    Environment = var.environment
  }
}

# SNS Topic for Notifications
resource "aws_sns_topic" "guardduty_findings" {
  name = "${var.project_name}-guardduty-findings"

  tags = {
    Environment = var.environment
  }
}

# SNS Topic Policy
resource "aws_sns_topic_policy" "guardduty_findings" {
  arn = aws_sns_topic.guardduty_findings.arn

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid    = "AllowGuardDutyPublish"
        Effect = "Allow"
        Principal = {
          Service = "guardduty.amazonaws.com"
        }
        Action   = "SNS:Publish"
        Resource = aws_sns_topic.guardduty_findings.arn
      }
    ]
  })
}

# EventBridge Rule for GuardDuty Findings
resource "aws_cloudwatch_event_rule" "guardduty_findings" {
  name        = "${var.project_name}-guardduty-findings"
  description = "Capture GuardDuty findings"

  event_pattern = jsonencode({
    source      = ["aws.guardduty"]
    detail-type = ["GuardDuty Finding"]
  })
}

# EventBridge Target
resource "aws_cloudwatch_event_target" "sns" {
  rule      = aws_cloudwatch_event_rule.guardduty_findings.name
  target_id = "SendToSNS"
  arn       = aws_sns_topic.guardduty_findings.arn

  input_transformer {
    input_paths = {
      severity    = "$.detail.severity"
      type        = "$.detail.type"
      description = "$.detail.description"
      account     = "$.detail.accountId"
      region      = "$.detail.region"
    }
    input_template = "\"GuardDuty Finding: Severity <severity>, Type <type> in account <account> region <region>. Description: <description>\""
  }
}

Variables Configuration

# variables.tf
variable "aws_region" {
  description = "AWS region"
  type        = string
  default     = "us-west-2"
}

variable "project_name" {
  description = "Project name"
  type        = string
}

variable "environment" {
  description = "Environment name"
  type        = string
  default     = "dev"
}

variable "master_account_id" {
  description = "AWS Organizations master account ID"
  type        = string
  default     = ""
}

variable "member_accounts" {
  description = "List of member account IDs to enable GuardDuty"
  type        = list(string)
  default     = []
}

Best Practices

  1. Detector Management

    • Enable all data sources
    • Set appropriate frequency
    • Configure notifications
    • Regular finding reviews
  2. Security

    • Enable multi-account
    • Use proper IAM roles
    • Configure trusted IPs
    • Regular security reviews
  3. Cost Optimization

    • Monitor usage
    • Filter false positives
    • Use appropriate settings
    • Regular cost reviews
  4. Performance

    • Optimize finding rules
    • Use efficient filters
    • Monitor API limits
    • Regular performance reviews

Multi-Account Configuration

# Organization Admin Account
resource "aws_guardduty_organization_admin_account" "admin" {
  count = var.master_account_id != "" ? 1 : 0

  admin_account_id = var.master_account_id
}

# Organization Configuration
resource "aws_guardduty_organization_configuration" "org" {
  count = var.master_account_id != "" ? 1 : 0

  auto_enable = true
  detector_id = aws_guardduty_detector.main.id

  datasources {
    s3_logs {
      auto_enable = true
    }
    kubernetes {
      audit_logs {
        auto_enable = true
      }
    }
    malware_protection {
      scan_ec2_instance_with_findings {
        auto_enable = true
      }
    }
  }
}

# Member Accounts
resource "aws_guardduty_member" "members" {
  for_each = toset(var.member_accounts)

  account_id  = each.value
  detector_id = aws_guardduty_detector.main.id
  email       = data.aws_organizations_account.members[each.value].email
  invite      = true

  depends_on = [aws_guardduty_organization_configuration.org]
}

# Data source for member accounts
data "aws_organizations_account" "members" {
  for_each = toset(var.member_accounts)
  account_id = each.value
}

Findings Configuration

# Filter for Known False Positives
resource "aws_guardduty_filter" "known_activities" {
  name        = "known-activities"
  action      = "ARCHIVE"
  detector_id = aws_guardduty_detector.main.id
  rank        = 1

  finding_criteria {
    criterion {
      field  = "service.additionalInfo.threatListName"
      equals = ["Known-IP"]
    }
    criterion {
      field  = "severity"
      equals = [1]
    }
  }
}

# IPSet for Trusted IPs
resource "aws_guardduty_ipset" "trusted" {
  activate    = true
  detector_id = aws_guardduty_detector.main.id
  format      = "TXT"
  location    = "s3://${aws_s3_bucket.trusted_ips.id}/trusted-ips.txt"
  name        = "trusted-ips"

  tags = {
    Environment = var.environment
  }
}

# S3 Bucket for Trusted IPs
resource "aws_s3_bucket" "trusted_ips" {
  bucket = "${var.project_name}-trusted-ips"

  tags = {
    Environment = var.environment
  }
}

# S3 Bucket Policy
resource "aws_s3_bucket_policy" "trusted_ips" {
  bucket = aws_s3_bucket.trusted_ips.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid    = "AllowGuardDutyAccess"
        Effect = "Allow"
        Principal = {
          Service = "guardduty.amazonaws.com"
        }
        Action   = "s3:GetObject"
        Resource = "${aws_s3_bucket.trusted_ips.arn}/*"
      }
    ]
  })
}

Monitoring Configuration

# CloudWatch Dashboard
resource "aws_cloudwatch_dashboard" "guardduty" {
  dashboard_name = "${var.project_name}-guardduty-dashboard"

  dashboard_body = jsonencode({
    widgets = [
      {
        type   = "metric"
        x      = 0
        y      = 0
        width  = 12
        height = 6

        properties = {
          metrics = [
            ["AWS/GuardDuty", "FindingsCount", "DetectorId", aws_guardduty_detector.main.id]
          ]
          period = 300
          stat   = "Sum"
          region = var.aws_region
          title  = "GuardDuty Findings"
        }
      }
    ]
  })
}

# CloudWatch Alarms
resource "aws_cloudwatch_metric_alarm" "high_severity_findings" {
  alarm_name          = "${var.project_name}-high-severity-findings"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = "1"
  metric_name         = "FindingsCount"
  namespace           = "AWS/GuardDuty"
  period             = "300"
  statistic          = "Sum"
  threshold          = "0"
  alarm_description  = "This metric monitors high severity GuardDuty findings"
  alarm_actions      = [aws_sns_topic.guardduty_findings.arn]

  dimensions = {
    DetectorId = aws_guardduty_detector.main.id
  }
}

Deployment Steps

  1. Initialize Terraform:
terraform init
  1. Plan the deployment:
terraform plan
  1. Apply the configuration:
terraform apply

Clean Up

Remove all resources when done:

terraform destroy

Common Use Cases

  1. Security Operations Center Integration
# Lambda Function for SOC Integration
resource "aws_lambda_function" "soc_integration" {
  filename         = "soc_integration.zip"
  function_name    = "${var.project_name}-soc-integration"
  role             = aws_iam_role.soc_lambda.arn
  handler          = "index.handler"
  runtime          = "nodejs14.x"

  environment {
    variables = {
      SOC_API_ENDPOINT = var.soc_api_endpoint
      SOC_API_KEY      = var.soc_api_key
    }
  }

  tags = {
    Environment = var.environment
  }
}

# EventBridge Target for SOC
resource "aws_cloudwatch_event_target" "soc" {
  rule      = aws_cloudwatch_event_rule.guardduty_findings.name
  target_id = "SendToSOC"
  arn       = aws_lambda_function.soc_integration.arn
}
  1. Slack Integration
# Lambda Function for Slack Notifications
resource "aws_lambda_function" "slack_notifications" {
  filename         = "slack_notifications.zip"
  function_name    = "${var.project_name}-slack-notifications"
  role             = aws_iam_role.slack_lambda.arn
  handler          = "index.handler"
  runtime          = "nodejs14.x"

  environment {
    variables = {
      SLACK_WEBHOOK_URL = var.slack_webhook_url
      SLACK_CHANNEL     = var.slack_channel
    }
  }

  tags = {
    Environment = var.environment
  }
}

# SNS Topic Subscription
resource "aws_sns_topic_subscription" "slack" {
  topic_arn = aws_sns_topic.guardduty_findings.arn
  protocol  = "lambda"
  endpoint  = aws_lambda_function.slack_notifications.arn
}

Advanced Features

# Custom Threat Intelligence
resource "aws_guardduty_threatintelset" "custom" {
  activate    = true
  detector_id = aws_guardduty_detector.main.id
  format      = "TXT"
  location    = "s3://${aws_s3_bucket.threat_intel.id}/custom-threats.txt"
  name        = "custom-threats"

  tags = {
    Environment = var.environment
  }
}

# S3 Protection
resource "aws_guardduty_detector_s3_logs_configuration" "s3_protection" {
  detector_id = aws_guardduty_detector.main.id
  enable      = true
}

# Kubernetes Protection
resource "aws_guardduty_detector_kubernetes_configuration" "k8s_protection" {
  detector_id = aws_guardduty_detector.main.id
  enable      = true
}

Conclusion

This setup provides a comprehensive foundation for deploying GuardDuty using Terraform. Remember to:

  • Plan your security monitoring carefully
  • Implement proper notification channels
  • Monitor findings and costs
  • Keep your configurations versioned
  • Test thoroughly before production deployment

The complete code can be customized based on your specific requirements and use cases.