Exploring Amazon GuardDuty ETD in Practice
Why talk about GuardDuty ETD now
Cloud security is not just "alerts on a screen". What separates maturity from attempt is understanding the chain of events and responding automatically.
Amazon GuardDuty Extended Threat Detection (ETD) correlates multiple signals (APIs, logs, findings) to identify attack sequences and generate a single critical finding that represents the complete attack story.What is ETD, in 30 seconds
- Detects multi-stage attacks (e.g.: compromised credentials → policy changes → S3 exfiltration).
- Correlates signals across foundational sources (CloudTrail, VPC Flow Logs, DNS) and protection plans (S3, EKS, Runtime), when enabled.
- Generates "AttackSequence:*" findings (e.g.:
AttackSequence:S3/CompromisedData,AttackSequence:IAM/CompromisedCredentials,AttackSequence:EKS/CompromisedCluster) — all with "Critical" severity.
Important: when you enable GuardDuty in a Region, ETD is already enabled by default at no additional cost; enabling S3/EKS/Runtime expands coverage by adding more signals.
Use cases that matter to you
- Credential compromise (IAM) → Enumeration, escalation, and lateral movement culminating in unauthorized access. ETD consolidates the sequence.
- S3 data compromise → From undue permissiveness to exfiltration; with S3 Protection ETD recognizes the complete chain.
- EKS compromise → From container exploitation to persistence/crypto-mining; with EKS Protection/Runtime Monitoring ETD generates
AttackSequence:EKS/CompromisedCluster.
Enable the base and expand coverage (step by step)
- Enable GuardDuty (per account/Region or via Organizations).
- (Optional, recommended) Enable protection plans for more signals and sequences:
- S3 Protection (data/S3).
- EKS Protection and/or Runtime Monitoring (control + runtime).
- Malware/RDS/Lambda according to your scope.
In the console: GuardDuty → Extended Threat Detection (you will see Status: Enabled by default), and EKS Protection / Runtime / S3 Protection → Enable.
Generate sample findings (useful for testing automations)
Console: Settings → Sample findings → Generate. CLI: (example of any type)Discover your detector
aws guardduty list-detectors
Generate a specific sample finding
aws guardduty create-sample-findings \
--detector-id \
--finding-types AttackSequence:S3/CompromisedData
Connect with automated response (EventBridge + Lambda)
1) EventBridge rule filtering AttackSequence
{
"source": ["aws.guardduty"],
"detail-type": ["GuardDuty Finding"],
"detail": {
"findings": {
"type": [{ "prefix": "AttackSequence:" }],
"severity": [{ "numeric": [">=", 7] }]
}
}
}
2) Lambda (Python/boto3) — example for compromised credentials (IAM)
import json, os
import boto3
iam = boto3.client("iam")
sns = boto3.client("sns")
TOPIC_ARN = os.environ["TOPIC_ARN"]
def handler(event, context):
detail = event["detail"]
finding = detail["findings"][0]
ftype = finding["type"]
principal_arns = []
for res in finding.get("resources", []):
if res.get("type") == "AwsIamAccessKey":
arn = res.get("details", {}).get("awsIamAccessKey", {}).get("principalArn")
if arn: principal_arns.append(arn)
for arn in set(principal_arns):
if ":user/" in arn:
user = arn.split(":user/")[1]
for meta in iam.list_access_keys(UserName=user)["AccessKeyMetadata"]:
if meta["Status"] == "Active":
iam.update_access_key(UserName=user,
AccessKeyId=meta["AccessKeyId"],
Status="Inactive")
sns.publish(TopicArn=TOPIC_ARN,
Subject=f"[GuardDuty ETD] Action taken for {ftype}",
Message=json.dumps(finding, indent=2))
return {"ok": True}
3) Lambda — example for S3/CompromisedData
import json
import boto3
s3control = boto3.client("s3control")
account_id = boto3.client("sts").get_caller_identity()["Account"]
def handler(event, context):
finding = event["detail"]["findings"][0]
buckets = []
for res in finding.get("resources", []):
if res.get("type") == "AwsS3Bucket":
name = res.get("id") or res.get("resourceDetails", {}).get("s3BucketDetails", [{}])[0].get("name")
if name: buckets.append(name)
for bucket in set(buckets):
s3control.put_public_access_block(
AccountId=account_id,
PublicAccessBlockConfiguration={
"BlockPublicAcls": True,
"IgnorePublicAcls": True,
"BlockPublicPolicy": True,
"RestrictPublicBuckets": True
}
)
return {"quarantined_buckets": list(set(buckets))}
Conclusion
- Enable GuardDuty (ETD is already included) and expand coverage with S3/EKS/Runtime.
- Automate responses to reduce MTTD/MTTR.
- Educate your team: a single AttackSequence tells the attack story — and guides the response.