Amazon GuardDuty: Threat Detection Across Your AWS Environment

Most security incidents in AWS leave traces long before they become obvious. API calls from unusual geographic locations. IAM credentials being used at odd hours. EC2 instances querying known command-and-control endpoints. S3 buckets being enumerated by an entity that has never accessed them before. Catching these signals manually is not practical at scale.

GuardDuty monitors your AWS account for threats continuously without agents to install or traffic to route through it. It analyzes CloudTrail API logs, VPC flow logs, DNS query logs, S3 data events, and EKS audit logs. In this article I will walk through enabling GuardDuty across a multi-account AWS Organization, configuring automated response for high-severity findings, and the suppression rules that reduce noise without hiding real threats.

Enabling GuardDuty at the Organization Level

In a multi-account organization, enable GuardDuty in the management account as the delegated administrator. All member accounts are automatically enrolled and their findings are aggregated in the administrator account. You manage one GuardDuty configuration and see all findings across every account.

resource "aws_guardduty_detector" "main" {
  enable = true

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

  finding_publishing_frequency = "FIFTEEN_MINUTES"

  tags = {
    Environment = "production"
    ManagedBy   = "terraform"
  }
}

resource "aws_guardduty_organization_configuration" "main" {
  auto_enable_organization_members = "ALL"
  detector_id                      = aws_guardduty_detector.main.id

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

resource "aws_guardduty_organization_admin_account" "main" {
  admin_account_id = var.security_account_id
}

auto_enable_organization_members = ALL ensures that any new account added to the organization automatically has GuardDuty enabled. Without this, new accounts start unprotected until someone remembers to enable it manually. In practice, that manual step gets missed and you end up with blind spots in accounts created for new projects or acquired teams.

Malware protection with EBS volume scanning is the feature most teams skip. When GuardDuty finds a suspicious finding on an EC2 instance, it can automatically create a snapshot of attached EBS volumes and scan them for malware without interrupting the running instance. Enable it from the start.

Automated Response with EventBridge and Lambda

GuardDuty findings publish to EventBridge. You can route high-severity findings to a Lambda function that takes automated action, and route all findings to SNS for human review.

resource "aws_cloudwatch_event_rule" "guardduty_high_severity" {
  name        = "guardduty-high-severity"
  description = "Capture GuardDuty findings with severity 7 or higher"

  event_pattern = jsonencode({
    source      = ["aws.guardduty"]
    detail-type = ["GuardDuty Finding"]
    detail = {
      severity = [{ numeric = [">=", 7] }]
    }
  })
}

resource "aws_cloudwatch_event_rule" "guardduty_all" {
  name        = "guardduty-all-findings"
  description = "All GuardDuty findings for review"

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

resource "aws_cloudwatch_event_target" "high_severity_lambda" {
  rule = aws_cloudwatch_event_rule.guardduty_high_severity.name
  arn  = aws_lambda_function.guardduty_responder.arn
}

resource "aws_cloudwatch_event_target" "all_findings_sns" {
  rule = aws_cloudwatch_event_rule.guardduty_all.name
  arn  = aws_sns_topic.security_alerts.arn
}

The automated responder Lambda for high-severity findings:

import boto3
import json
import logging

logger = logging.getLogger()
ec2    = boto3.client("ec2")
iam    = boto3.client("iam")

def lambda_handler(event, context):
    finding    = event["detail"]
    find_type  = finding["type"]
    severity   = finding["severity"]
    account_id = finding["accountId"]
    region     = finding["region"]

    logger.info(f"Processing finding: {find_type} severity {severity} in {account_id}/{region}")

    if "UnauthorizedAccess:IAMUser" in find_type or "CredentialAccess:IAMUser" in find_type:
        handle_compromised_iam(finding)
    elif "CryptoCurrency:EC2" in find_type or "Backdoor:EC2" in find_type:
        handle_compromised_ec2(finding)
    elif "Stealth:S3" in find_type or "Discovery:S3" in find_type:
        handle_s3_threat(finding)

def handle_compromised_iam(finding):
    service    = finding.get("service", {})
    action     = service.get("action", {})
    user_name  = action.get("awsApiCallAction", {}).get("remoteAccountDetails", {}).get("accountId")

    resource   = finding.get("resource", {})
    access_key = resource.get("accessKeyDetails", {}).get("accessKeyId")

    if access_key:
        logger.warning(f"Disabling access key {access_key} due to GuardDuty finding")
        iam.update_access_key(
            AccessKeyId=access_key,
            Status="Inactive"
        )

def handle_compromised_ec2(finding):
    resource    = finding.get("resource", {})
    instance_id = resource.get("instanceDetails", {}).get("instanceId")

    if instance_id:
        logger.warning(f"Isolating EC2 instance {instance_id} due to GuardDuty finding")
        ec2.modify_instance_attribute(
            InstanceId=instance_id,
            Groups=["sg-isolation-only"]
        )

def handle_s3_threat(finding):
    logger.warning(f"S3 threat detected: {finding['type']}")
    pass

The EC2 isolation function replaces the instance’s security groups with an isolation security group that allows no inbound or outbound traffic. The instance stays running so memory forensics are possible, but it cannot communicate with anything. Test this function in a non-production environment before enabling it for automatic execution on production findings.

Suppression Rules to Reduce Noise

resource "aws_guardduty_filter" "suppress_trusted_ips" {
  name        = "suppress-trusted-ip-pentest"
  action      = "ARCHIVE"
  detector_id = aws_guardduty_detector.main.id
  rank        = 1

  finding_criteria {
    criterion {
      field  = "service.action.networkConnectionAction.remoteIpDetails.ipAddressV4"
      equals = var.pentest_ip_ranges
    }
  }
}

resource "aws_guardduty_filter" "suppress_nat_gateway" {
  name        = "suppress-nat-gateway-scanning"
  action      = "ARCHIVE"
  detector_id = aws_guardduty_detector.main.id
  rank        = 2

  finding_criteria {
    criterion {
      field  = "resource.instanceDetails.tags.value"
      equals = ["nat-gateway"]
    }
    criterion {
      field  = "type"
      equals = ["Recon:EC2/PortProbeUnprotectedPort"]
    }
  }
}

Suppression rules archive findings that match known-safe patterns rather than deleting them. The archived findings are still visible and still count toward your finding history. You are telling GuardDuty to not alert you for these, not to ignore them entirely. Build your suppression rules conservatively and review archived findings monthly to confirm you are not suppressing real threats.

Closing Thoughts

GuardDuty is one of the highest-value security services on AWS relative to its cost. At roughly $4 per million CloudTrail events and $1 per GB of VPC flow logs analyzed, it is inexpensive for most accounts and the threat coverage is extensive.

Enable it in every account from day one. Enable all data sources including S3, Kubernetes, and malware protection. Route findings to EventBridge and automate responses for your most critical finding types. Review all findings weekly and build suppression rules conservatively over time as you identify legitimate false positives. The investment in setup pays back quickly when it catches the credential compromise or cryptominer that would otherwise go unnoticed for weeks.

Enjoy the cloud.

Osama


#AWS #GuardDuty #CloudSecurity #ThreatDetection #SecurityEngineering #CloudArchitecture #Terraform #InfrastructureAsCode #AmazonWebServices #SolutionsArchitect #CloudComputing #DevSecOps #SecurityAutomation #TechBlog #CloudInfrastructure #EventBridge #Lambda #IAM #Compliance #SIEM

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.