awsfindingsmanagerlib

Quickstart

Installation

Install with your favorite Python package manager like:

pip install awsfindingsmanagerlib

Define Your Rules

You can define rules in multiple ways, the most common are:

  1. Using a YAML File

Create a YAML file, such as rules.yaml, defining the findings you want to suppress. For example:

Rules:
  - note: Suppress DynamoDB Autoscaling findings
    action: SUPPRESSED
    match_on:
      security_control_id: DynamoDB.1
  - note: Suppress findings for development resources
    action: SUPPRESSED
    match_on:
      tags:
        - key: env
          value: dev

Host the file on an HTTP server (e.g., using python3 -m http.server) or use it directly in your project.

from awsfindingsmanagerlib import FindingsManager, Http

http_backend = Http('http://localhost:8000/rules.yaml')

findings_manager = FindingsManager('eu-west-1')
findings_manager.register_rules(http_backend.get_rules())
findings_manager.suppress_matching_findings()

And zip 🤐 all noise is silenced.

  1. Programmatically with `register_rule`

If you prefer a more dynamic approach, you can define rules programmatically using the register_rule method:

from awsfindingsmanagerlib import FindingsManager

findings_manager = FindingsManager('eu-west-1')
findings_manager.register_rule(
  note="Suppress DynamoDB Autoscaling findings",
  action="SUPPRESSED",
  match_on={"security_control_id": "DynamoDB.1"}
)
findings_manager.suppress_matching_findings()

And zip 🤐 all noise is silenced.

Rule Syntax

Rules in your YAML file follow this general syntax:

Rules:
  - note: 'str' # A descriptive note for the rule
    action: 'SUPPRESSED'
    match_on:
      security_control_id: 'str'
      rule_or_control_id: 'str'
      product_name: 'str'
      title: 'str'
      tags:
        - key: 'str'
          value: 'str'
      resource_id_regexps:
        - 'regex'
      regions:
        - 'str'

When Suppressing Native Security Hub Findings:

Specify either security_control_id or rule_or_control_id — but not both!.

If ``rule_or_control_id`` is used, ensure that “consolidated control findings” is disabled in AWS Security Hub.

When Suppressing Findings from AWS Security Hub Service Integrations:

Specify both product_name and title. The product_name field must match the name of the product that created the finding (e.g., Inspector). The title field must match the title of the finding. Read the AWS service integrations page for all the supported integrations.

Additional Filters:

Either regions, tags, or resource_id_regexps (or all) can be provided to ensure precise matching.

When no regions are set, the rule will match findings from all regions.

Note Configuration

The library supports two modes for handling finding notes: text mode (default) and JSON mode.

Text Mode (Default)

By default, suppression notes are stored as plain text.

from awsfindingsmanagerlib import FindingsManager

findings_manager = FindingsManager('eu-west-1')
findings_manager.register_rule(
  note="Suppress SSM.7 findings",
  action="SUPPRESSED",
  match_on={"security_control_id": "SSM.7"}
)
findings_manager.suppress_matching_findings()

Finding notes will be stored as: "Suppress SSM.7 findings"

JSON Mode

JSON mode enables a more structured way of storing notes and allows for note preservation by merging existing JSON formatted metadata. This is particularly useful when integrating with ticketing systems or when multiple teams manage suppressions.

To enable this feature, configure the FindingsManager with a NoteTextConfig object:

from awsfindingsmanagerlib import FindingsManager, NoteTextConfig

# Enable JSON mode with default key "Note"
findings_manager = FindingsManager(
  region='eu-west-1',
  note_text=NoteTextConfig(format="json")
)

When JSON mode is enabled:

  1. No existing note or empty note: Creates a new JSON note with the suppression reason

    {"Note": "Suppress SSM.7 findings"}
    
  2. Existing plain text note: Replaces the plain text with a JSON note containing the suppression reason

    {"Note": "Suppress SSM.7 findings"}
    
  3. Existing JSON note: Merges the suppression reason with existing metadata

    # Before: {"jiraIssue": "PROJ-123"}
    # After:  {"jiraIssue": "PROJ-123", "Note": "Suppress SSM.7 findings"}
    

Custom JSON Key

You can customize the JSON key used for suppression notes:

from awsfindingsmanagerlib import FindingsManager, NoteTextConfig

findings_manager = FindingsManager(
  region='eu-west-1',
  note_text=NoteTextConfig(format="json", key="suppressionReason")
)

This will store suppression notes using your custom key:

{"jiraIssue": "PROJ-123", "suppressionReason": "Suppress SSM.7 findings"}

Valid Credentials

To ensure successful operation, your AWS credentials must include the following permissions:

  • ec2:DescribeRegions

  • securityhub:GetFindings

  • securityhub:BatchUpdateFindings

Why use awsfindingsmanagerlib?

You may wonder what justifies using a dedicated lib to suppress findings. You could have just as easily, maybe even more easily clicked suppress in the console, right? Yes, BUT, actually, multiple buts. Let’s sum up the advantages of using awsfindingsmanagerlib from the skeptic’s perspective.

“I can just do this in the AWS console”

Well, that will be a tedious amount of clicking for a lot false positives, while you could have just written:

Rules:
  - note: My dev instance
    action: SUPPRESSED
    match_on:
      resource_ids:
        - arn:aws:ec2:eu-central-1:1234567890:instance/i-1234567890

Maybe, better yet:

Rules:
  - note: dev resources by tag
    action: SUPPRESSED
    match_on:
      tags:
        - key: env
          value: dev
  - note: dev resources by name
    action: SUPPRESSED
    match_on:
      resource_ids:
        - '*-dev$' # yes, we support regex

Add this point you might almost get scared of being too suppressive. Don’t panic:

Rules:
  - note: We'll make this one exception, especially for you two then
    action: SUPPRESSED
    match_on:
      security_control_id: 'IAM.3'
      resource_ids:
        - '^arn:aws:iam::1234567890:user/lazyperson1$'
        - '^arn:aws:iam::1234567890:user/lazyperson2$'

As you can see, suppressions can now be expressed in a more general, meaningful, dare-we-say-Pythonic way. Moreover, you can apply your suppressions over all your AWS accounts with this tool with little effort. Control ids are the same in every AWS account and you can express you resources with tags and regex. This way, your suppressions become portable through your whole environment.

The generality makes it possible to apply the suppressions even in your audit account, despite differing AWS account ids. This way you can get a truly good overview without clutter from false positives.

“I don’t have that many findings to suppress”

Even if you don’t have many false positives in your environment, findings are only saved for 90 days. After that time your suppressions are gone with them. Most checks immediately generate a new finding then. Re-suppressing these findings each time manually is error-prone and can eventually amount to a lot of work.

To reduce errors further, we recommend storing your suppressions file in a VCS and suppressing in full automation. (See below for our reference implementation.)

Third-Party Tools

While tools like Splunk, Datadog, and OpenSearch excel at aggregation and analysis, managing findings at the source in AWS Security Hub offers significant advantages. Suppressing irrelevant findings within AWS Security Hub ensures:

  • Only relevant data is forwarded to third-party tools, reducing noise and enhancing visibility.

  • Lower costs due to reduced storage requirements and improved query performance.

AWS Security Hub Automations

AWS Security Hub Automations is AWS’s native solution for managing findings. However, it has several limitations that can hinder its effectiveness in large or complex environments:

Rule Count

Automations are limited to 100 rules, which can quickly become insufficient in large environments. Each unique suppression scenario often requires its own rule, leading to a rapid depletion of the rule quota.

Flexibility

Automations lack support for regex or multi-property rules, making them less flexible for complex suppression needs. For example, suppressing a specific check across multiple resources in Automations requires creating multiple rules.

With regex, you can achieve the same result with a single, concise rule. For instance, to suppress findings for Lambda functions in specific dev/test accounts, you could use:

arn:aws:lambda:eu-central-1:(1234567890|2345678901):function:(client-a|client-b|client-c)

In Automations, this scenario would require separate rules for each permutation, increasing rule count and reducing manageability.

Retroactive Suppression

Unlike Automations, this library supports retroactive suppression, allowing you to address findings from the past. This eliminates the need to wait for the 90-day retention period to expire before irrelevant findings stop cluttering your dashboard.

Readability

While regex has some inherent readability challenges, it offers more flexibility than Automations’ filter: prefix/suffix. This flexibility reduces the number of rules required, simplifying suppression management. Additionally, suppressions should be regularly reviewed, often by someone other than the original author. A well-structured regex rule can still be easier to manage than dozens of fragmented rules in Automations.

“Alright, I want this, why is there still more text on this page?”

Well, this is ‘just’ a lib. While it provides all the magic you want, why do the standard infra work yourself? We have a standard implementation of suppressing with this lib available in Terraform here. On top of that, it provides some integrations for automatic alerting and ticketing.

Contents

Indices and Tables