Business Challenge
#43 built the account that receives these findings and #45 covered turning detection on across an organisation. Both leave you with the same problem: a queue, and a severity number next to each item.
The number is honest about what it is: “Each GuardDuty finding has an assigned severity level and value that reflects the potential risk the finding could have to your environment, as determined by our security engineers. The value of the severity can fall anywhere within the 1.0 to 10.0 range.”
A risk estimate for that finding, by itself. Not a queue position, and not a statement about what the finding might become.
Read the definition of critical severity carefully: “A critical severity level indicates that an attack sequence may be in progress or had recently happened. One or more AWS resources… are potentially being compromised or may have already been compromised.”
An attack sequence is a correlated finding. And suppression rules take findings out of that correlation: “When you create suppression rules that archive findings, Extended Threat Detection can't use these archived findings when correlating events for attack sequences. Broad suppression rules might impact the ability of GuardDuty to detect behaviors aligned with detecting multi-stage attacks. Findings that are archived because of suppression rules are not considered as signals for attack sequences.”
AWS supplies the worked example, and it is the obvious rule somebody writes on a noisy Tuesday: “if you create a suppression rule that archives all EKS cluster-related findings instead of targeting specific known activities, GuardDuty won't be able to use those findings to detect an attack sequence where a threat actor exploits a container, obtains privileged tokens, and accesses sensitive resources.”
So the triage instinct inverts. The findings that look least worth actioning individually are candidate signals for the band GuardDuty asks you to prioritise above everything else.
FixScope rules to behaviours, not to finding types or resource classes. AWS's own guidance: “Keep the suppression rules focused on specific behaviors for which you don't want GuardDuty to generate a finding.”
“Suppressed findings are not sent to AWS Security Hub CSPM, Amazon Simple Storage Service, Amazon Detective, or Amazon EventBridge, reducing finding noise level if you consume GuardDuty findings via Security Hub CSPM, a third-party SIEM, or other alerting and ticketing applications.”
That is the intended effect for a SIEM, and it is a side effect everywhere else. Your S3 export is your long-term evidence store. Detective is where somebody goes to build a timeline during an incident. A suppression rule written to quiet a ticket queue removes the finding from both.
And one more, which is easy to miss because it is a different product: “If you've enabled Malware Protection for EC2, the suppressed GuardDuty findings won't initiate a malware scan.” A suppression rule can therefore turn off scanning for the exact activity that would have triggered it.
FixBefore writing a rule, enumerate who consumes findings. The finding survives in GuardDuty for 90 days either way, so suppression buys inbox quiet at the cost of every other consumer.
In the API they are the same object with one field different.
CreateFilter's action parameter has
“Valid Values: NOOP | ARCHIVE” and
“Default: NOOP”.
So a filter created without action is a saved view — it changes what
you see and nothing else. Set it to ARCHIVE and the same criteria become a
suppression rule with all the consequences above. One field, in a parameter that is
“Required: No”, separates a console convenience from a detection change.
Worth knowing in the other direction too: if you inherited Terraform with
action = "ARCHIVE" on something described as a filter, it is suppressing.
Audit every GuardDuty filter for action. The ones set to ARCHIVE are the detection configuration; the rest are bookmarks.
Architecture
Four bands over one continuous range, and a filter mechanism that addresses them as integers.
The four bands, and the qualifier under them
| Band | Value range | What AWS says it means | Recommended response |
|---|---|---|---|
| Critical | 9.0 – 10.0 | “an attack sequence may be in progress or had recently happened” | Prioritise all of them — “can be a part of a ransomware attack and can escalate at any time” |
| High | 7.0 – 8.9 | “the resource in question… is compromised and is actively being used for unauthorized purposes” | Immediate remediation |
| Medium | 4.0 – 6.9 | “suspicious activity that deviates from normally observed behavior” | Investigate at earliest convenience; if unconfirmed, “consider the resource compromised” |
| Low | 1.0 – 3.9 | “attempted suspicious activity that did not compromise your environment” | “no immediate recommended action”, but worth noting |
And the sentence that answers why the same alert arrives with two different numbers on two different days: “A finding of a particular type may have a different severity depending on the context specific to the finding.”
Severity is therefore a property of the occurrence, not of the type. A per-type default list exists, but the number on the finding in front of you has already been adjusted for context. Which means a runbook keyed on finding type is keyed on the wrong thing, and a dashboard counting "how many High" is counting a population whose membership shifts.
The filter addresses severity as an integer
The bands are decimal, and the filter criteria are not:
“To configure severity based filters, use the following for the FindingCriteria condition:
Low: ["1", "2", "3"]…
Medium: ["4", "5", "6"]…
High: ["7", "8"]…
Critical: ["9", "10"].”
The integer buckets line up exactly with the decimal bands — 7 and 8 cover 7.0 through 8.9 —
so there is no gap. What there is, is a mismatch between the value you read in the console and the value
you write in a rule. Somebody copying 8.5 out of a finding into a filter is
writing a criterion against a different representation than the one the page documents.
“GuardDuty continues to generate findings even when they match your suppression rules, however, those findings are automatically marked as archived. The archived finding is stored in GuardDuty for 90 days and can be viewed at any time during that period.” So a suppression rule is a routing decision rather than a detection one — the detector keeps working and the record keeps existing. What stops is delivery, and participation in correlation. You can read what you suppressed via ListFindings with service.archived equal to true, which is the single most useful query for auditing your own rules.
Why This Architecture Holds Up
AWS's guidance is unusually restrictive, and the reason is now visible
Marked Important in the documentation: “GuardDuty recommends that you build suppression rules reactively and only for findings for which you have repeatedly identified false positives in your environment.”
Three constraints in one sentence — after the fact, only for false positives, and only for repeated ones. That rules out the whole category of pre-emptive noise reduction, which is how most suppression rules actually get written: during onboarding, from a list of finding types somebody expects to be noisy.
Read alongside the attack-sequence consequence, the restriction stops looking conservative. A rule built pre-emptively over a finding type is exactly the broad rule that removes signals, and it is built before anyone has seen a single false positive to justify it.
The documented examples share a shape worth copying
Every example AWS gives pairs a finding type with a second criterion that identifies the specific legitimate cause:
-
UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWSplus the API caller IPv4 address of your on-premises gateway — for the case where “VPC networking is configured to route internet traffic such that it egresses from an on-premises gateway rather than from a VPC Internet Gateway”. -
UnauthorizedAccess:EC2/SSHBruteForceplus an instance image ID or tag value identifying your bastion hosts, because “If the target of the brute force attempt is a bastion host, this may represent expected behavior for your AWS environment.” -
Recon:EC2/Portscanplus the instances “that host these vulnerability assessment tools”.
Not one of them is the finding type alone — and that is a choice in the examples rather than a restriction in the product. AWS is explicit that both shapes are available: “You can configure suppression rules to suppress entire finding types, or define more granular filter criteria to suppress only specific instances of a particular finding type.”
So the broad rule is permitted and the narrow one is what gets demonstrated. The second criterion is what turns "stop telling me about brute force" into "stop telling me about brute force against the host whose job is to absorb it" — and it is what leaves the same finding type live everywhere else, where it can still act as a signal.
“Kubernetes clusters run their own DNS servers as pods, such as coredns. Therefore, for each DNS lookup from a pod, GuardDuty captures two DNS events — one from the pod and the other from the server pod.” AWS lists eleven DNS finding types this can duplicate, and the recommended rule pairs the finding type with the DNS server's own executablePath or executableSha256. That is suppression of a mechanical artefact rather than of a risk judgement, which is the distinction worth holding: you are removing the second copy of an event, not deciding the event does not matter.
Two operational limits on the mechanism itself
“The maximum number of saved filters per AWS account per Region is 100.” Since specific rules are the recommended kind, and specific rules are numerous, the ceiling and the guidance pull against each other — one rule per legitimate cause per Region adds up faster than it sounds.
And filters are ordered:
“rank… Specifies the position of the filter in the list of
current filters. Also specifies the order in which this filter is applied to the findings”,
with a range of 1 to 100. So the mechanism has precedence, which means two overlapping rules are not
commutative and the order is a thing you set rather than a thing you discover.
And in an organisation, this is one person's decision
“In a multi-account environment only the GuardDuty administrator can create suppression rules.” Correct design — suppression is a detection change and should not be delegated to the account generating the noise. The consequence is that the request comes from the team with the context and the decision sits with the team without it, so the administrator needs the second criterion from the requester rather than just a finding type.
Key Architecture Decisions
| Decision | Choice | Reasoning |
|---|---|---|
| Rule scope | Finding type plus a criterion identifying the legitimate cause | Every documented example does this; type-only rules are the broad ones that remove attack-sequence signals. |
| When to write a rule | Reactively, after repeated false positives | AWS's stated recommendation, and pre-emptive rules are necessarily the broad kind. |
| Low-severity noise | Route elsewhere rather than suppress | Suppressed findings are not considered as signals for attack sequences, and critical severity is defined as an attack sequence. |
| Before any rule | Enumerate the consumers | Suppression removes the finding from Security Hub CSPM, S3, Detective and EventBridge at once. |
| Malware Protection for EC2 enabled | Treat suppression as scan suppression too | Suppressed findings won't initiate a malware scan. |
| Existing filters | Audit the action field |
NOOP is a saved view; ARCHIVE is detection configuration. The default is NOOP. |
| Severity in filter criteria | Integers, per the documented mapping | Bands are decimal (7.0–8.9) but criteria are written as ["7", "8"]. |
| Runbooks | Key on severity and context, not on finding type | The same type may arrive with a different severity depending on context. |
| Overlapping rules | Set rank deliberately |
It determines the order in which filters are applied. |
| Kubernetes DNS duplicates | Suppress on the DNS pod's executable path or SHA-256 | Each pod lookup produces two events; this removes the mechanical duplicate, not the judgement. |
The audit worth running
ListFindings with service.archived equal to
true, over the last 90 days. That is the record of what your rules decided
you would not see, and reading it is how you find out whether a rule written eighteen months ago is now
archiving something that matters — which reviewing the rules themselves will not tell you, because
a rule's text does not change when your environment does.
Then read every filter's action and its criteria count. A rule whose criteria
are a finding type and nothing else is the shape AWS warns about, regardless of what it was written for.
Closing Thought
The severity number is doing a narrower job than its presentation suggests. It is an estimate of the risk that finding carries, which is why a port scan is a 2 and why the recommendation for a 2 is to take note and do nothing. That is reasonable advice about the finding and bad advice about the queue, because the detector is also reading those 2s as material for something else.
So the useful reframe is that triage has two outputs, not one. Whether a human should look at this now is a severity question. Whether GuardDuty should keep seeing findings like this is a different question entirely, and the suppression rule answers the second while appearing to answer the first.
Which lands in the same place this block keeps landing. #72 was a resource accumulating against a ceiling. #73 was a schedule quietly not running. This one is a detection capability quietly reduced by a change made for inbox hygiene — documented, intended, and invisible from the dashboard that motivated it.
Security & Identity — Security Hub control findings: why a control can be passing on a resource that is non-compliant, what consolidated control findings changed about counting, and why the security score is not a percentage of your risk.
Official AWS Reference
- Severity levels of GuardDuty findings — the four bands, their value ranges and recommended responses, and the context qualifier
- Suppression rules in GuardDuty — what suppression removes, the Extended Threat Detection consequence, and the documented use cases
- CreateFilter — the NOOP and ARCHIVE actions, the 100-filter ceiling, rank ordering, and the integer severity criteria
- GuardDuty Extended Threat Detection — further reading on attack sequences; no claims in this post are drawn from it
Comments