Manual security reviews don't scale. Learn how to combine AWS GuardDuty, Security Hub, and CloudTrail into an automated threat detection and compliance pipeline that catches issues before they become incidents.
Most AWS accounts I audit have CloudTrail turned on but nobody watching the logs. GuardDuty might be enabled but findings pile up unread. Security Hub is collecting data from six sources and sending it nowhere.
The tools exist. The automation doesn't. That's the gap this post fills.
Why Manual Security Reviews Fail
If your security process is "check the console when something feels wrong," you've already lost. Here's what actually happens:
- CloudTrail generates thousands of events per hour in a moderately active account
- GuardDuty findings arrive at random times — 3 AM on a Saturday doesn't care about your on-call schedule
- Security Hub aggregates findings from multiple services, but the default view is overwhelming
- By the time a human notices something, the attacker has had hours (or days) of dwell time
The answer isn't more dashboards. It's automation that triages, prioritizes, and responds — and only pages a human when it actually matters.
The Three Pillars: What Each Service Does
Before wiring them together, understand what each service actually provides.
CloudTrail: The Audit Log
CloudTrail records every API call in your AWS account. Every RunInstances, every PutObject, every AssumeRole. It's the raw material — the security camera footage.
What it catches:
- Who did what, when, and from where (IP, user agent)
- Console logins vs. programmatic access
- Cross-account role assumptions
- Root account usage (this should be near zero)
What it doesn't do:
- Analyze patterns
- Detect anomalies
- Alert on threats
CloudTrail is passive. It records. That's it. You need something watching those recordings.
GuardDuty: The Threat Detector
GuardDuty uses machine learning, anomaly detection, and threat intelligence feeds to analyze CloudTrail logs, VPC Flow Logs, and DNS logs. It generates findings — specific, prioritized security alerts.
What it catches:
- Cryptocurrency mining on your EC2 instances
- Compromised credentials being used from unusual locations
- Port scanning and brute force attempts
- Data exfiltration patterns (unusual outbound data volumes)
- Reconnaissance activity (API calls probing for permissions)
- Malicious IP communication
Finding severity levels:
- High (7.0-8.9): Active compromise — needs immediate response
- Medium (4.0-6.9): Suspicious activity — investigate within hours
- Low (1.0-3.9): Informational — review during regular security checks
Security Hub: The Aggregator
Security Hub pulls findings from GuardDuty, Inspector, Macie, IAM Access Analyzer, Firewall Manager, and third-party tools into a single pane. It also runs automated compliance checks against standards like CIS AWS Foundations Benchmark and AWS Foundational Security Best Practices.
What it provides:
- Unified findings from all security services
- Compliance scoring against industry benchmarks
- Automated security checks (controls)
- Cross-account aggregation for organizations
- Integration point for custom actions and automation
Setting Up the Pipeline
Here's the architecture that actually works in production:
CloudTrail → S3 Bucket (encrypted, access-logged)
↓
GuardDuty (analyzes CloudTrail + VPC Flow + DNS logs)
↓
Security Hub (aggregates GuardDuty + Inspector + Macie findings)
↓
EventBridge Rule (filters by severity)
↓
├── SNS → Slack/PagerDuty (for HIGH severity)
├── Lambda → Auto-remediation (for known patterns)
└── Step Functions → Investigation workflow (for MEDIUM severity)
Step 1: Enable CloudTrail Properly
Most accounts have a default trail, but it's often misconfigured.
# Create an organization trail with log file validation
aws cloudtrail create-trail \
--name security-audit-trail \
--s3-bucket-name my-cloudtrail-logs \
--is-multi-region-trail \
--enable-log-file-validation \
--include-global-service-events \
--kms-key-id arn:aws:kms:ap-south-1:123456789:key/your-key-id
# Start logging
aws cloudtrail start-logging --name security-audit-trail
Critical settings:
- Multi-region: Attackers don't limit themselves to your primary region
- Log file validation: Detects if someone tampers with your audit logs
- KMS encryption: Protects logs at rest (use a CMK, not the default key)
- S3 bucket policy: Lock down the log bucket — no public access, no delete without MFA
Step 2: Enable GuardDuty
# Enable GuardDuty (do this in every region you use)
aws guardduty create-detector \
--enable \
--finding-publishing-frequency FIFTEEN_MINUTES \
--data-sources '{
"S3Logs": {"Enable": true},
"Kubernetes": {"AuditLogs": {"Enable": true}},
"MalwareProtection": {"ScanEc2InstanceWithFindings": {"EbsVolumes": true}}
}'
Enable all data sources. The cost is minimal compared to what a missed finding costs you. GuardDuty pricing is based on the volume of data analyzed — for most accounts, it's under $50/month.
Step 3: Enable Security Hub
# Enable Security Hub with recommended standards
aws securityhub enable-security-hub \
--enable-default-standards
# Also enable the CIS benchmark
aws securityhub batch-enable-standards \
--standards-subscription-requests '[
{"StandardsArn": "arn:aws:securityhub:::ruleset/cis-aws-foundations-benchmark/v/1.4.0"}
]'
Security Hub starts running automated compliance checks immediately. Give it 24 hours to generate a baseline compliance score.
Step 4: Wire Up EventBridge for Automated Response
This is where most teams stop — they enable the services but never build the automation. Here's the EventBridge rule that catches high-severity GuardDuty findings:
{
"source": ["aws.guardduty"],
"detail-type": ["GuardDuty Finding"],
"detail": {
"severity": [{ "numeric": [">=", 7] }]
}
}
And the Lambda function that auto-remediates common threats:
import { EC2Client, StopInstancesCommand } from "@aws-sdk/client-ec2";
import { IAMClient, PutUserPolicyCommand } from "@aws-sdk/client-iam";
const ec2 = new EC2Client({});
const iam = new IAMClient({});
export async function handler(event: any) {
const finding = event.detail;
const findingType = finding.type;
// Auto-isolate compromised EC2 instances
if (findingType.startsWith("CryptoCurrency:") ||
findingType.startsWith("Trojan:")) {
const instanceId = finding.resource.instanceDetails?.instanceId;
if (instanceId) {
await ec2.send(new StopInstancesCommand({
InstanceIds: [instanceId],
}));
console.log(`Stopped compromised instance: ${instanceId}`);
}
}
// Deny all access for compromised IAM users
if (findingType.startsWith("UnauthorizedAccess:IAMUser")) {
const userName = finding.resource.accessKeyDetails?.userName;
if (userName) {
await iam.send(new PutUserPolicyCommand({
UserName: userName,
PolicyName: "EmergencyDenyAll",
PolicyDocument: JSON.stringify({
Version: "2012-10-17",
Statement: [{
Effect: "Deny",
Action: "*",
Resource: "*",
}],
}),
}));
console.log(`Quarantined IAM user: ${userName}`);
}
}
// Always notify the security team
// SNS notification happens via a separate EventBridge target
}
Important: Auto-remediation should be conservative. Stop instances, quarantine users, revoke sessions — but don't delete anything. You need the evidence for investigation.
Compliance Monitoring That Actually Works
Security Hub's compliance checks are useful, but the default dashboard buries the signal in noise. Here's how to focus on what matters.
The Checks That Matter Most
From the CIS AWS Foundations Benchmark, these are the findings I always prioritize:
| Control | What It Checks | Why It Matters |
|---|
| 1.4 | Root account has MFA | Root = god mode — must be locked down |
| 1.10 | MFA for console users | Credential theft is the #1 attack vector |
| 2.1 | CloudTrail in all regions | Attackers use regions you're not watching |
| 2.6 | S3 bucket access logging | Know who accessed your data |
| 3.1-3.14 | CloudWatch log metric filters | Detect IAM changes, console sign-in failures, etc. |
| 4.1-4.4 | Security group restrictions | No 0.0.0.0/0 on SSH, RDP, or admin ports |
Automated Compliance Reporting
Set up a weekly compliance summary that goes to your team:
import {
SecurityHubClient,
GetFindingsCommand,
} from "@aws-sdk/client-securityhub";
const client = new SecurityHubClient({});
async function getComplianceSummary() {
const response = await client.send(new GetFindingsCommand({
Filters: {
ComplianceStatus: [
{ Value: "FAILED", Comparison: "EQUALS" },
],
RecordState: [
{ Value: "ACTIVE", Comparison: "EQUALS" },
],
SeverityLabel: [
{ Value: "CRITICAL", Comparison: "EQUALS" },
{ Value: "HIGH", Comparison: "EQUALS" },
],
},
MaxResults: 100,
}));
return {
totalFailedControls: response.Findings?.length ?? 0,
criticalFindings: response.Findings?.filter(
(f) => f.Severity?.Label === "CRITICAL"
).length ?? 0,
findings: response.Findings?.map((f) => ({
title: f.Title,
severity: f.Severity?.Label,
resource: f.Resources?.[0]?.Id,
standard: f.Compliance?.SecurityControlId,
})),
};
}
Run this as a scheduled Lambda and post the summary to Slack. Teams that see their compliance score weekly fix issues faster than teams that check quarterly.
CloudTrail Log Analysis: Beyond the Basics
Raw CloudTrail logs are JSON events in S3. Useful for forensics, terrible for real-time detection. Here's how to make them actionable.
CloudTrail Lake for SQL Queries
CloudTrail Lake lets you query your audit logs with SQL — far more powerful than sifting through S3 objects:
-- Find all root account activity in the last 7 days
SELECT eventTime, eventName, sourceIPAddress, userAgent
FROM your-event-data-store-id
WHERE userIdentity.type = 'Root'
AND eventTime > '2026-04-16 00:00:00'
ORDER BY eventTime DESC
-- Find IAM policy changes
SELECT eventTime, eventName, requestParameters, userIdentity.arn
FROM your-event-data-store-id
WHERE eventName IN (
'PutUserPolicy', 'AttachUserPolicy',
'PutRolePolicy', 'AttachRolePolicy',
'CreatePolicyVersion'
)
AND eventTime > '2026-04-16 00:00:00'
ORDER BY eventTime DESC
-- Detect unusual cross-region API calls
SELECT awsRegion, eventName, COUNT(*) as call_count
FROM your-event-data-store-id
WHERE awsRegion NOT IN ('ap-south-1', 'us-east-1')
AND eventTime > '2026-04-16 00:00:00'
GROUP BY awsRegion, eventName
ORDER BY call_count DESC
CloudWatch Metric Filters for Real-Time Alerts
For specific patterns you want to catch immediately, set up CloudWatch metric filters on your CloudTrail log group:
# Alert on root account usage
aws logs put-metric-filter \
--log-group-name CloudTrail/SecurityAuditTrail \
--filter-name RootAccountUsage \
--filter-pattern '{ $.userIdentity.type = "Root" && $.userIdentity.invokedBy NOT EXISTS && $.eventType != "AwsServiceEvent" }' \
--metric-transformations \
metricName=RootAccountUsageCount,metricNamespace=SecurityMetrics,metricValue=1
# Alert on console login without MFA
aws logs put-metric-filter \
--log-group-name CloudTrail/SecurityAuditTrail \
--filter-name ConsoleLoginWithoutMFA \
--filter-pattern '{ $.eventName = "ConsoleLogin" && $.additionalEventData.MFAUsed = "No" }' \
--metric-transformations \
metricName=NoMFALoginCount,metricNamespace=SecurityMetrics,metricValue=1
# Alert on security group changes
aws logs put-metric-filter \
--log-group-name CloudTrail/SecurityAuditTrail \
--filter-name SecurityGroupChanges \
--filter-pattern '{ ($.eventName = "AuthorizeSecurityGroupIngress") || ($.eventName = "AuthorizeSecurityGroupEgress") || ($.eventName = "RevokeSecurityGroupIngress") || ($.eventName = "RevokeSecurityGroupEgress") || ($.eventName = "CreateSecurityGroup") || ($.eventName = "DeleteSecurityGroup") }' \
--metric-transformations \
metricName=SecurityGroupChangeCount,metricNamespace=SecurityMetrics,metricValue=1
Then create CloudWatch alarms on these metrics with appropriate thresholds. Root account usage should alarm on >= 1. Security group changes might alarm on >= 5 in an hour, depending on your change volume.
Cost Reality Check
People avoid enabling these services because they assume it's expensive. Here's what it actually costs for a typical small-to-medium AWS account:
| Service | Typical Monthly Cost | What You Get |
|---|
| CloudTrail | $2-5 (S3 storage) | Complete API audit trail |
| GuardDuty | $30-80 | Continuous threat detection |
| Security Hub | $10-30 | Compliance monitoring + aggregation |
| EventBridge | < $1 | Event routing for automation |
| Lambda (remediation) | < $1 | Auto-response to findings |
| Total | $45-120/month | Automated security pipeline |
Compare that to the cost of a security incident: data breach notification, forensic investigation, downtime, reputation damage. The ROI isn't even close.
Multi-Account Strategy
If you're running an AWS Organization (and you should be, even with just two accounts), use delegated administrator for GuardDuty and Security Hub:
- Management account: Enables GuardDuty and Security Hub across all member accounts
- Security account: Designated as delegated administrator — receives all findings
- Workload accounts: Generate findings, don't manage them
This gives your security team a single pane across all accounts without requiring access to production workloads.
What to Do in the First 24 Hours After Enabling
- Enable CloudTrail with multi-region, log validation, and KMS encryption
- Enable GuardDuty in all active regions with all data sources
- Enable Security Hub with CIS and AWS Foundational Security standards
- Create EventBridge rules for high-severity GuardDuty findings → SNS → your alert channel
- Review the initial Security Hub score — don't panic at the number, just prioritize Critical and High findings
- Set up CloudWatch metric filters for root usage and console logins without MFA
- Schedule a weekly compliance review — even 15 minutes reviewing the Security Hub dashboard makes a difference
Don't try to fix every finding on day one. Triage by severity, fix the Critical and High items first, and work through Medium findings over the following weeks.
Beyond Detection: Building a Security Culture
The tools are the easy part. The hard part is building habits:
- Weekly security standup (15 minutes): Review new findings, compliance score trend, any incidents
- Runbook for each finding type: When GuardDuty fires, who does what? Write it down before the incident
- Quarterly access review: Who has access to what? Are there unused IAM users or roles?
- Annual penetration test: Validate that your detection actually catches real attacks
Automation handles the 99% of routine monitoring. Your team handles the 1% that requires judgment.
If you're running workloads on AWS and don't have automated security monitoring in place, the time to set it up is before the first incident — not after. Let's talk about securing your AWS infrastructure.