CloudTrail & GuardDuty

๐Ÿ”ฅ Vibe Prompt

"Set up CloudTrail for all accounts, create an organization trail. Enable GuardDuty with automated response."

CloudTrail Setup

resource "aws_cloudtrail" "org_trail" {
  name                          = "org-trail"
  s3_bucket_name                = aws_s3_bucket.cloudtrail.id
  include_global_service_events = true
  is_multi_region_trail         = true
  enable_log_file_validation    = true
  is_organization_trail         = true
  
  event_selector {
    read_write_type           = "All"
    include_management_events = true
  }
}

resource "aws_s3_bucket" "cloudtrail" {
  bucket = "myorg-cloudtrail-logs"
}

resource "aws_s3_bucket_policy" "cloudtrail" {
  bucket = aws_s3_bucket.cloudtrail.id
  policy = jsonencode({
    Statement = [{
      Effect = "Allow"
      Principal = { Service = "cloudtrail.amazonaws.com" }
      Action = "s3:PutObject"
      Resource = "${aws_s3_bucket.cloudtrail.arn}/AWSLogs/*"
      Condition = {
        StringEquals = { "s3:x-amz-acl" = "bucket-owner-full-control" }
      }
    }]
  })
}

Key CloudTrail Events

# Console login (without MFA)
{ "eventName": "ConsoleLogin", "userIdentity": { ... }, "responseElements": { "ConsoleLogin": "Failure" } }

# Root activity
{ "userIdentity": { "type": "Root" }, "eventName": "..." }

# IAM policy change
{ "eventSource": "iam.amazonaws.com", "eventName": "PutRolePolicy" }

# S3 public access change
{ "eventSource": "s3.amazonaws.com", "eventName": "PutBucketAcl" }

GuardDuty

resource "aws_guardduty_detector" "main" {
  enable = true
  datasources {
    s3_logs {
      enable = true
    }
    kubernetes {
      audit_logs {
        enable = true
      }
    }
  }
}

GuardDuty Finding Types

| Finding | Severity | What It Means | |---------|----------|---------------| | CryptoCurrency:EC2/BitcoinTool.B!DNS | High | EC2 mining crypto | | Backdoor:EC2/C&CActivity.B!DNS | High | Malware C&C | | UnauthorizedAccess:IAM/User.IAMUser | Medium | Suspicious IAM | | Policy:IAM/User/RootCredentialUsage | High | Root user activity | | Recon:EC2/PortProbeUnprotected | Low | Port scanning |

Automated Response

import boto3

def lambda_handler(event, context):
    finding = event['detail']['finding']
    finding_type = finding['type']
    resource_arn = finding['resource']['arn']
    severity = finding['severity']
    
    if severity >= 7:  # HIGH or CRITICAL
        if 'EC2' in finding_type:
            # Isolate the instance
            ec2 = boto3.client('ec2')
            instance_id = resource_arn.split('/')[-1]
            ec2.modify_instance_attribute(
                InstanceId=instance_id,
                Groups=['sg-quarantine']
            )
            print(f"Isolated {instance_id} in quarantine SG")
        
        elif 'IAM' in finding_type:
            # Disable the key
            iam = boto3.client('iam')
            iam.update_access_key(
                UserName=finding['resource']['accessKeyDetails']['userName'],
                AccessKeyId=finding['resource']['accessKeyDetails']['accessKeyId'],
                Status='Inactive'
            )
            print("Disabled compromised access key")

GuardDuty + Security Hub

GuardDuty โ†’ Security Hub โ†’ EventBridge โ†’ Lambda (auto-remediate)
                                            โ†“
                                       Slack notification
                                            โ†“
                                       PagerDuty (SEV-1/2)

Best Practices

  • Enable CloudTrail in all regions
  • Create organization trail (single log bucket)
  • Enable log file validation (integrity)
  • Enable GuardDuty in all accounts
  • Set up automated response for critical findings
  • Integrate with Security Hub for dashboard

Unlock Full Tutorial

This chapter is paid content. Join the project to unlock over 5000 words of deep analysis, including 10+ god-tier Prompts and real Source Code examples!