Welcome to awsfindingsmanagerlib
Rule-based Python library for managing and suppressing findings in AWS Security Hub and its integrated services
This library tries to stay as close to the boto3/API specifications as possible. See their documentation for more information on low-level specifics.
Some quirks about the API worth mentioning for the usability of this library:
- This library uses the original
get_findingsboto3/API call, because it is the most versatile one. As such, string filters can only be"EQUALS"|"PREFIX"|"NOT_EQUALS"|"PREFIX_NOT_EQUALS"and map filters can only be"EQUALS"|"NOT_EQUALS". See the string filter API specs and the map filter API specs for more information. - The boto3/API arguments don't always exactly match with finding fields.
For example, the finding field
{"Severity":{"Label":"string"}}becomes simplySeverityLabelas a filter field. Compare the API specs with the finding specs for more details. - The
Cidrattribute of the IpFilter works like a StringFilter withValueset to the value forCidrandComparisonset toEQUALS.
Things worth noting about the library itself.
- To make big rule files a little smaller and more readable rules can be create via a rule manager. The rule manager can have a default config for all rules created by it.
- Individual rules can still override the defaults set by the manager.
- All string filter fields can also filter values on regexes when set under
ExtraFeatures>RegexStringFilters. This is not supported by the API, so it always happens in the logic of this library. See the code examples below on how to use it. - Setting
jsonUpdatemode underExtraFeatures>NoteTextConfigenables a more structured way of storing notes. It allows for note preservation from other processes by merging existing JSON formatted note metadata. This requires setting a key under which to store the data in the JSON object. This is particularly useful when integrating with ticketing systems or when multiple teams manage findings. When a note is empty, this mode will create a new JSON note like:{"Note":"Suppress SSM.7 findings"}. Existing notes in plain text (non-JSON-formatted) will be overwritten, the previous note will be captured in the logs. When there is an existing JSON-formatted note, this mode will update only the key it manages in that note like:{"jiraIssue":"PROJ-123","Note":"Suppress SSM.7 findings"}. See the code examples below on how to activate it. - Often the note is the only specific input to what you want to update with a rule.
To trim some boilerplate config per rule, the feature
QuickNotecan be used. See the code examples below on how to use it.
Example usage
Rules:
- Filters:
Region:
- Value: eu-west-1
Comparison: EQUALS
WorkflowStatus:
- Value: NEW
Comparison: EQUALS
UpdatesToFilteredFindings:
Workflow:
Status: SUPPRESSED
Note:
Text: Test
UpdatedBy: awsfindingsmanagerlib
ExtraFeatures:
RegexStringFilters:
ResourceId:
- .*-dev$
- .*-test$
Description:
- .*non-critical.*
NoteTextConfig:
Mode: jsonUpdate
Key: suppressionReason
from pathlib import Path
import boto3
import yaml
from awsfindingsmanagerlib import Rule
with Path("rules.yaml").open() as file:
rules = yaml.safe_load(file)["Rules"]
client = boto3.client("securityhub")
rule = Rule(**rules[0], client=client)
rule.get_and_update()
Condensing big rule sets
ManagerConfig:
DefaultRuleInput:
Filters:
WorkflowStatus:
- Value: NEW
Comparison: EQUALS
- Value: NOTIFIED
Comparison: EQUALS
UpdatesToFilteredFindings:
Workflow:
Status: SUPPRESSED
Note:
UpdatedBy: awsfindingsmanagerlib
ExtraFeatures:
NoteTextConfig:
Mode: jsonUpdate
Key: suppressionReason
Rules:
- Filters:
ResourceId:
- Value: arn:aws:s3:::test-awsfindingsmanagerlib
Comparison: EQUALS
UpdatesToFilteredFindings:
Note:
Text: Test
- Filters:
ResourceId:
- Value: arn:aws:s3:::test-awsfindingsmanagerlib-2
Comparison: EQUALS
ExtraFeatures:
NoteTextConfig:
Mode: plaintext
QuickNote: Test-2
from pathlib import Path
import boto3
import yaml
from awsfindingsmanagerlib import Manager
with Path("rules.yaml").open() as file:
rules = yaml.safe_load(file)
client = boto3.client("securityhub")
manager = Manager.from_rules_document(rules, client)
manager.get_and_update_all()
Running in AWS Lambda
Installing the lambda extra (awsfindingsmanagerlib[lambda], pulling in aws-lambda-powertools and
pyyaml) provides awsfindingsmanagerlib.aws_lambda, four ready-made Lambda handlers built on top of
Manager/Rule:
awsfindingsmanagerlib.aws_lambda.scheduled.lambda_handler: applies all configured rules to every currently matching finding. Intended to run on a schedule (e.g. an EventBridge rule). RaisesRuntimeErrorif any matched finding could not be processed, so the invocation is reported as failed.awsfindingsmanagerlib.aws_lambda.events.lambda_handler: intended as the target of an EventBridge rule matching"Security Hub Findings - Imported"events. Suppresses the finding(s) carried by the event and returns{"finding_state": "suppressed"}or{"finding_state": "skipped"}instead of raising, so that a Step Function (or any other orchestration) placed after it can branch on whether the finding still needs further handling, such as a ticket.awsfindingsmanagerlib.aws_lambda.trigger.lambda_handler: intended as the target of an S3ObjectCreatednotification on the rules file. Loads the rules and places one SQS message per rule (carrying the sharedManagerConfigalongside it) on the queue URL given by theSQS_QUEUE_URLenvironment variable, forawsfindingsmanagerlib.aws_lambda.workerto apply.awsfindingsmanagerlib.aws_lambda.worker.lambda_handler: intended as the target of an SQS event source mapping consuming the queue thatawsfindingsmanagerlib.aws_lambda.triggerwrites to. Rebuilds a manager from the single rule carried by each record and applies it against every currently matching finding. Logs and continues on a per-record failure, relying on the queue's own redrive policy for retries rather than on the Lambda invocation failing.
Rules source
All four handlers load rules through the same logic: if both the S3_BUCKET_NAME and
S3_OBJECT_NAME environment variables are set (awsfindingsmanagerlib.aws_lambda.trigger and .scheduled
and .events all read rules this way), the rules document is loaded from that S3 object;
otherwise it is loaded from the local file named by RULES_PATH (defaulting to rules.yaml,
relative to the Lambda's working directory), which must be bundled into the deployment package.
awsfindingsmanagerlib.aws_lambda.worker never loads rules itself: it receives its single rule directly in
the SQS message body.
IAM permissions
At minimum, the execution role needs securityhub:GetFindings and
securityhub:BatchUpdateFindings on the Security Hub resource. Depending on which handlers are
deployed, also add s3:GetObject on the rules object (events, trigger, scheduled) and
sqs:SendMessage/sqs:ReceiveMessage/sqs:DeleteMessage/sqs:GetQueueAttributes on the queue
(trigger and worker respectively).
Region behaviour
Each handler queries Security Hub in the boto3 client's own region only; unlike some other findings-management libraries, it does not enumerate finding aggregators or other regions. Deploy the Lambda(s) in the Region where Security Hub findings are aggregated (typically the organization's Security Hub home Region) so this default is correct.
Deployment package
Download lambda_package.zip from the awsfindingsmanagerlib GitHub release; it is built by the release
workflow with uv export --all-extras --no-dev and contains awsfindingsmanagerlib and its dependencies with
a flat, importable layout. Add your rules.yaml (if not loading from S3) at the root of the zip
alongside the awsfindingsmanagerlib package before uploading it.
Upgrading from 1.x
2.0 is a complete rewrite and is not compatible with 1.x: rules are no longer written under match_on, but map
directly onto the get_findings/batch_update_findings boto3 API, and the Python API changed accordingly.
See UPGRADING.md
for a field-by-field mapping, a script converting a 1.x rules.yaml, and the behavioural differences.
Behaviours that 1.x applied implicitly (the default WorkflowStatus filter, the note author and the note format)
are set once for all rules via ManagerConfig.DefaultRuleInput, for instance:
ManagerConfig:
DefaultRuleInput:
Filters:
WorkflowStatus:
- Value: NEW
Comparison: EQUALS
- Value: NOTIFIED
Comparison: EQUALS
UpdatesToFilteredFindings:
Workflow:
Status: SUPPRESSED
Note:
UpdatedBy: awsfindingsmanagerlib
ExtraFeatures:
NoteTextConfig:
Mode: jsonUpdate
Key: Note