GuardDuty Detectors & Finding Types
Enabling data sources and interpreting finding severity via SDK.
Busca en todas las páginas de la documentación
Enabling data sources and interpreting finding severity via SDK.
A GuardDuty detector is the single object that turns threat detection on for a region, and its DataSources configuration decides how wide a net it casts. Everything downstream - which findings show up, how quickly, and how serious they are - flows from what the detector is configured to look at. This page covers configuring data sources and reading the finding types and severities that come back.
Quick-reference recipe card - copy-paste ready.
{
"detectorId": "<detector-id>",
"dataSources": {
"s3Logs": { "enable": true },
"kubernetes": { "auditLogs": { "enable": true } },
"malwareProtection": { "scanEc2InstanceWithFindings": { "ebsVolumes": { "enable": true } } }
}
}When to reach for this:
Type strings, not just display them raw.Enable additional data sources on an existing detector, then list and interpret findings by severity.
# --- Python (boto3) ---
import boto3
guardduty = boto3.client("guardduty", region_name="us-east-1")
detector_id = "<detector-id>"
# Widen coverage: S3 data events and EKS audit logs.
guardduty.update_detector(
DetectorId=detector_id,
DataSources={
"S3Logs": {"Enable": True},
"Kubernetes": {"AuditLogs": {"Enable": True}},
},
)
# List findings sorted by severity, highest first.
resp = guardduty.list_findings(
DetectorId=detector_id,
SortCriteria={"AttributeName": "severity", "OrderBy": "DESC"},
MaxResults=25,
)
details = guardduty.get_findings(DetectorId=detector_id, FindingIds=resp["FindingIds"])
for f in details["Findings"]:
sev = f["Severity"]
label = "high" if sev >= 7 else "medium" if sev >= 4 else "low"
print(f["Type"], sev, label)// --- TypeScript (AWS SDK v3) ---
import {
GuardDutyClient, UpdateDetectorCommand, ListFindingsCommand, GetFindingsCommand,
} from "@aws-sdk/client-guardduty";
const guardduty = new GuardDutyClient({ region: "us-east-1" });
const detectorId = "<detector-id>";
// Widen coverage: S3 data events and EKS audit logs.
await guardduty.send(new UpdateDetectorCommand({
DetectorId: detectorId,
DataSources: {
S3Logs: { Enable: true },
Kubernetes: { AuditLogs: { Enable: true } },
},
}));
// List findings sorted by severity, highest first.
const resp = await guardduty.send(new ListFindingsCommand({
DetectorId: detectorId,
SortCriteria: { AttributeName: "severity", OrderBy: "DESC" },
MaxResults: 25,
}));
const details = await guardduty.send(new GetFindingsCommand({
DetectorId: detectorId, FindingIds: resp.FindingIds,
}));
for (const f of details.Findings ?? []) {
const sev = f.Severity ?? 0;
const label = sev >= 7 ? "high" : sev >= 4 ? "medium" : "low";
console.log(f.Type, sev, label);
}What this demonstrates:
UpdateDetector adds data sources to a detector that already exists - you do not need to recreate it to widen coverage.SortCriteria on ListFindings orders by severity (or updatedAt), so triage-by-severity does not need client-side sorting.ListFindings -> GetFindings two-call pattern is required - IDs and full detail are separate calls.low/medium/high) are a convention, not an API field - GuardDuty returns the raw float and leaves labeling to you.CreateDetector runs.S3Logs) - adds S3 data-event analysis, surfacing findings like unusual API calls against a bucket or requests from a Tor exit node.Kubernetes.AuditLogs) - analyzes Kubernetes audit logs for control-plane threats like anonymous access attempts or privilege escalation inside a cluster.MalwareProtection) - triggered by certain EC2/EBS-related findings, it snapshots and scans the volume for malware without needing an agent on the instance.Type string has the shape Threat:ResourceType/ThreatDetail, e.g. UnauthorizedAccess:EC2/SSHBruteForce or Backdoor:EC2/C&CActivity.B.UnauthorizedAccess, Backdoor, CryptoCurrency, Trojan, Recon, Policy, and others) - useful for routing rules that act on a whole category.EC2, S3, IAMUser, Kubernetes) tells you what was affected, which usually maps directly to the remediation target.| Range | Label | Typical Response |
|---|---|---|
| 0 - 3.9 | Low | Log and review periodically; often reconnaissance or informational |
| 4.0 - 6.9 | Medium | Investigate within a defined SLA; may indicate early-stage compromise |
| 7.0 - 10 | High | Investigate immediately; often indicates active compromise or data exfiltration |
UpdatedAt changes) - do not treat the first severity you saw as final.# boto3 paginator for large finding sets instead of manual NextToken handling.
paginator = guardduty.get_paginator("list_findings")
for page in paginator.paginate(DetectorId=detector_id):
print(len(page["FindingIds"]))// SDK v3 loops on NextToken directly - there is no paginator helper for GuardDuty.
let nextToken: string | undefined;
do {
const page = await guardduty.send(new ListFindingsCommand({ DetectorId: detectorId, NextToken: nextToken }));
console.log(page.FindingIds?.length);
nextToken = page.NextToken;
} while (nextToken);Low/Medium/High strings, but the API returns a raw number. Fix: bucket the float yourself at the boundaries your team agrees on.Type with a hardcoded switch statement - new finding types ship regularly, and an exhaustive switch silently drops unknown ones into a default branch. Fix: match on the category prefix and log/handle unrecognized types visibly instead of swallowing them.GetFindings calls - passing more than 50 FindingIds in one call fails. Fix: chunk IDs into batches of 50 before calling GetFindings.UpdateDetector's data source shape with CreateDetector's - both accept a DataSources object, but forgetting nested keys (Kubernetes.AuditLogs.Enable, not Kubernetes.Enable) silently no-ops. Fix: check GetDetector after updating to confirm the source actually enabled.| Alternative | Use When | Don't Use When |
|---|---|---|
| GuardDuty findings via ListFindings/GetFindings | Programmatic triage, dashboards, custom alerting | You only need ad hoc console browsing |
| GuardDuty findings routed through Security Hub | You want findings alongside other services in one aggregated, ASFF-normalized view | You need GuardDuty-specific fields Security Hub's common schema does not carry |
| EventBridge rule directly on GuardDuty finding events | Near-real-time reaction to specific finding types | You need historical querying/filtering, not just new events |
| Third-party SIEM ingestion | Centralizing GuardDuty alongside non-AWS security signals | A pure single-account AWS setup where Security Hub already covers your needs |
VPC Flow Logs, DNS query logs, and CloudTrail management events - all enabled automatically when you create a detector, with no extra configuration or cost decision required.
S3 protection (S3 data events), EKS protection (Kubernetes audit logs), and Malware Protection (EBS volume scanning). Each is enabled via DataSources on CreateDetector or UpdateDetector and billed by volume analyzed.
The prefix (UnauthorizedAccess) is the threat category, the resource (EC2) is what was affected, and the suffix (SSHBruteForce) is the specific behavior detected - here, repeated failed SSH login attempts against an EC2 instance.
It is a float from 0 to 10. A common convention buckets it as low (0-3.9), medium (4-6.9), and high (7-10), but the exact cutoffs are a team decision, not an API-enforced standard.
Yes, with UpdateDetector. You do not need to delete and recreate the detector to widen its coverage.
It is designed for cheap, fast enumeration and filtering; full finding detail is a separate call (GetFindings) so you only pay the cost of fetching detail for the findings you actually want.
No. AWS adds new finding types as threat patterns evolve. Code that handles findings should match on category prefixes rather than assume an exhaustive, hardcoded list.
Stack versions: This page was written for boto3 1.43.x (Python 3.10+) and the AWS SDK for JavaScript v3 (Node.js 18+).
Revisado por Chris St. John·Última actualización: 25 jul 2026