Lab 05 — GuardDuty → EventBridge → Lambda¶
In one sentence
Turn GuardDuty on, let a "compromised" instance produce a real High finding, and have EventBridge trigger a Lambda that quarantines the instance by swapping its security groups — then see how suppression rules and the org-wide delegated admin model change what you get.
The idea¶
sec5-victim (t4g.nano, private subnet, no internet)
│ DNS lookup: guarddutyc2activityb.com (GuardDuty's test C&C domain)
▼
Route 53 Resolver ──► DNS query log ──► GuardDuty detector (reads it on its own, no setup)
│ Backdoor:EC2/C&CActivity.B!DNS severity 8 (High)
▼
EventBridge rule sec5-gd-high (source aws.guardduty, severity >= 7, Instance)
▼
Lambda sec5-isolate ──► ModifyInstanceAttribute: SGs := [sec5-isolation]
└─► tags: sec5:isolated-by, sec5:previous-sgs
What happened in the lab run¶
The real finding, end to end¶
| Step | Result |
|---|---|
Victim starts looking up guarddutyc2activityb.com |
✅ no internet needed — the VPC resolver does the lookup, GuardDuty sees it in its own DNS log copy |
| GuardDuty finding | ✅ Backdoor:EC2/C&CActivity.B!DNS, severity 8, ~4 min after launch |
| EventBridge → Lambda, attempt 1 | ❌ AccessDenied on ModifyInstanceAttribute — the ec2:Vpc condition isn't usable for that action on the instance |
Fix the policy: scope by aws:ResourceTag/Name = sec5-* |
|
| EventBridge async retry #2 | ✅ instance isolated: only sec5-isolation SG, tags record the finding and the old SG |
| Isolated instance afterwards | ⚠️ still sending DNS queries — the VPC resolver isn't filtered by security groups |
Suppression, samples and delegated admin¶
| Test | Result |
|---|---|
Sample finding ("sample": true) |
✅ reaches the Lambda, which skips it |
| Suppression rule (filter, action ARCHIVE) + High sample | ❌ auto-archived and never delivered to EventBridge |
| Control: rule deleted, new High sample | ✅ arrived at the Lambda in 23 s |
| Re-generate a sample type that already exists | ⚠️ no new finding — the old one is updated (Service.Count +1) and follows the publishing frequency |
| Delegated admin → member account 222222222222 | ✅ GuardDuty auto-enabled a detector there; admin sees the management account's findings |
| Management account (now a member) creates a filter / leaves | ❌ "member accounts cannot manage…" / rejected (org-managed) |
| Cleanup: disable the GuardDuty admin | ⚠️ Organizations still listed the delegated admin → deregister-delegated-administrator needed before disabling trusted access |
Key lessons¶
- GuardDuty reads its own copy of CloudTrail management events, VPC Flow Logs and DNS logs — you don't enable any of them, and turning yours off doesn't blind it. It detects; you build the response.
- Not every condition key works for every action.
ec2:Vpclooked right and was silently not applicable → deny. Check the Service Authorization Reference; resource tags are the safe scope. - EventBridge → Lambda is asynchronous with 2 retries. That saved the run here; in production add an on-failure destination or DLQ so a failed isolation isn't lost.
- Suppression = auto-archive + no downstream delivery. Use it only for truly benign noise.
- An isolation SG doesn't stop DNS to the VPC resolver. For DNS-based C&C / exfiltration use Route 53 Resolver DNS Firewall.
Exam notes¶
- Foundational sources (always on): CloudTrail management events, VPC Flow Logs, Route 53 Resolver DNS logs. Protection plans (optional): S3 data events, EKS audit logs, Runtime Monitoring, Malware Protection (EBS / S3), RDS login, Lambda network.
- GuardDuty is regional — enable it everywhere. It never blocks anything.
- Suspend keeps findings; delete the detector deletes them. Findings kept 90 days → export to S3 (KMS key required) for longer.
- New findings reach EventBridge in ~5 min; updates to existing findings follow the publishing frequency (15 min / 1 h / 6 h, default 6 h).
- Type format: ThreatPurpose:ResourceType/ThreatFamily.Mechanism!Artifact. Severity: Low 1–3.9, Medium 4–6.9, High 7–8.9, Critical 9–10.
InstanceCredentialExfiltration.OutsideAWS→ revoke the role's sessions (AWSRevokeOlderSessions), don't delete the role.- Event pattern:
source: aws.guardduty,detail-type: GuardDuty Finding, numeric match ondetail.severity. You can'tput-eventswith anaws.*source → test with sample findings. - Isolation: SG swap doesn't kill tracked connections; a deny NACL does but hits the whole subnet. Then snapshot EBS, keep it running for memory forensics, detach from ASG / deregister from ELB.
- Trusted IP list = no findings for traffic from those IPs. Threat list = findings for traffic to/from them. Managed by the admin account.
- Delegated admin: set from the management account, per region; best in a Security Tooling account. Admin sets auto-enable (NEW / ALL / NONE), suppression rules, lists, and sees all findings → one central EventBridge responder that assumes a role into the member. Members can't disable GuardDuty or leave.
Review questions¶
Question 1
A company disabled VPC Flow Logs to save money. Will GuardDuty still detect port scans against its instances? Why?
Show answer
Yes. GuardDuty consumes its own independent stream of flow-log data directly from the VPC infrastructure; it doesn't depend on the flow logs you configure (and you pay no flow-log charges for it). Disabling your flow logs only removes your copy for your own analysis — GuardDuty's detection is unaffected.
Question 2
An instance role's credentials are used from an IP outside AWS. Which finding, and what are the first two IR steps?
Show answer
UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS. First revoke the role's active
sessions (Revoke active sessions → AWSRevokeOlderSessions, a Deny on aws:TokenIssueTime older
than now) — the stolen temporary credentials die, new ones issued to the instance keep working. Then
investigate the instance (how were creds stolen — SSRF, IMDSv1?) and CloudTrail for what the
attacker did; enforce IMDSv2. Deleting the role would break the workload and isn't needed.
Question 3
You isolated an instance with an empty SG, yet an attacker's existing SSH session stays alive. Why, and what stops it?
Show answer
Security groups are stateful: connections already in the connection-tracking table keep flowing after the rules change. A deny NACL on the subnet is stateless and cuts it immediately (but affects everything in that subnet), or stop the instance after capturing memory. Placing affected workloads in a dedicated quarantine subnet makes the NACL option safe.
Question 4
A team suppresses a noisy finding type, and now their SIEM (fed by EventBridge) has a gap. Expected? What should they have used instead if they only wanted to stop the auto-response?
Show answer
Expected — suppressed findings are auto-archived and not sent to EventBridge, Security Hub, S3 export
or Detective (the lab saw exactly this). If the goal was only to stop the response, they should have
narrowed the EventBridge rule's event pattern (exclude that finding type, e.g. anything-but) or
filtered in the Lambda, leaving the finding flowing to the SIEM.
Question 5
60 accounts, 4 regions. What is the minimum setup so one security team sees and responds to every GuardDuty finding?
Show answer
From the management account, designate a GuardDuty delegated administrator (security tooling account) in each of the 4 regions, and in that admin set auto-enable for all members (ALL, so existing accounts are covered too). All members' findings then arrive in the admin's EventBridge per region → one responder per region (or forward to a single region / Security Hub with cross-region aggregation), acting in member accounts via an assumed role.
Surprises worth remembering
The deny that turned out to be a non-applicable condition key · async retries masking a broken first attempt · suppressed = invisible downstream · the delegated admin lingering in Organizations after GuardDuty let go of it.