diff --git a/README.md b/README.md index ac2b9ee..63956f3 100644 --- a/README.md +++ b/README.md @@ -1324,12 +1324,13 @@ For example, you can generate an HTML output with Tags and add "Owner" and "Envi # Filters -You can filter the security findings and resources that you get from your source in different ways and combine all of them to get exactly what you are looking for, then re-use those filters to create alerts. +You can filter the security findings and resources that you get from your source in different ways and combine all of them to get exactly what you are looking for, then re-use those filters to create automations, alerts, reports, and more. - [Security Hub Filtering](#security-hub-filtering) - [Security Hub Filtering using YAML templates](#security-hub-filtering-using-yaml-templates) - [Config Filters](#config-filters) - [Tags Filters](#tags-filters) +- [Impact Filters](#impact-filters) ## Security Hub Filtering @@ -1462,6 +1463,24 @@ Examples: ./metahub --sh-filters RecordState=ACTIVE WorkflowStatus=NEW ResourceType=AwsEc2SecurityGroup --mh-filters-tags Environment=Production ``` +## Impact Filters + +**MetaHub** supports **Impact filters**, you can filter by the [impact keys](#impact) calculated by MetaHub. You can use as many filters as you want and separate them using spaces. If you specify more than one filter, you will get all resources that match **all** filters. + +Examples: + +- Filter all Security Findings affecting resources with exposure calculated as effectively-public: + +```sh +./metahub --mh-filters-impact exposure=effectively-public +``` + +- Filter all Security Findings affecting resources with status calculated as not-attached: + +```sh +./metahub --mh-filters-impact status=not-attached +``` + # Security Hub Actions ## Updating Workflow Status diff --git a/lib/findings.py b/lib/findings.py index 5481b9d..79dbc15 100644 --- a/lib/findings.py +++ b/lib/findings.py @@ -23,6 +23,7 @@ def generate_findings( mh_role, mh_filters_config, mh_filters_tags, + mh_filters_impact, inputs, asff_findings, banners, @@ -124,13 +125,23 @@ def process_finding(finding): # Generate Impact imp = Impact(logger) - for resource_arn in mh_findings: + for resource_arn in list(mh_findings): impact_checks = imp.generate_impact_checks( resource_arn, mh_findings[resource_arn] ) mh_findings[resource_arn]["impact"] = mh_findings_short[resource_arn][ "impact" ] = impact_checks + # Check if the resources matches the impact filters + if mh_filters_impact: + for impact_filter, impact_value in mh_filters_impact.items(): + resource_value = list(impact_checks.get(impact_filter).keys())[0] + # If it doesn't match, we remove the resource from the findings + if resource_value != impact_value: + del mh_findings[resource_arn] + del mh_findings_short[resource_arn] + mh_inventory.remove(resource_arn) + break # Generate Statistics mh_statistics = generate_statistics(mh_findings) diff --git a/lib/helpers.py b/lib/helpers.py index 25c74bf..83f43a4 100644 --- a/lib/helpers.py +++ b/lib/helpers.py @@ -150,8 +150,8 @@ def get_parser(): ) # Group: Context Options - group_meta_checks = parser.add_argument_group("Context Options") - group_meta_checks.add_argument( + group_context = parser.add_argument_group("Context Options") + group_context.add_argument( "--mh-filters-config", default=None, help="Use this option to filter the resources based on context results using key=True/False pairs, for example public=True. Only True or False are supported as values. You can combine one or more filters using spaces", @@ -159,7 +159,7 @@ def get_parser(): nargs="*", action=KeyValue, ) - group_meta_checks.add_argument( + group_context.add_argument( "--mh-filters-tags", default=None, help="Use this option to filter the resources based on Tags results using key=value pairs, for example environment=production. If a value contains spaces, you should define it with double quotes. You can combine one or more filters using spaces", @@ -167,13 +167,21 @@ def get_parser(): nargs="*", action=KeyValue, ) - group_meta_checks.add_argument( + group_context.add_argument( + "--mh-filters-impact", + default=None, + help="Use this option to filter the resources based on Impact results using key=value pairs, for example exposure=effecively-public. If a value contains spaces, you should define it with double quotes. You can combine one or more filters using spaces", + required=False, + nargs="*", + action=KeyValue, + ) + group_context.add_argument( "--mh-assume-role", default=None, help="Specify the AWS IAM role role to be assumed where the affected resources are running", required=False, ) - group_meta_checks.add_argument( + group_context.add_argument( "--context", default=[ "config", @@ -462,6 +470,23 @@ def validate_arguments(args, logger): # Validate Tags filters mh_filters_tags = args.mh_filters_tags or {} + # Validate Impact Filters + mh_filters_impact = args.mh_filters_impact or {} + for mh_filters_impact_key, mh_filters_impact_value in mh_filters_impact.items(): + if mh_filters_impact_key not in ( + "access", + "exposure", + "encryption", + "environment", + "application", + "owner", + "status", + ): + logger.error( + "Incorrect Impact filter key. Use one of: access, exposure, encryption, environment, application, owner, status" + ) + exit(1) + # Parameter Validation: --sh-account and --sh-assume-role if bool(args.sh_account) != bool(args.sh_assume_role): logger.error( @@ -533,6 +558,7 @@ def validate_arguments(args, logger): sh_filters, mh_filters_config, mh_filters_tags, + mh_filters_impact, sh_account, sh_account_alias_str, sh_region, diff --git a/lib/main.py b/lib/main.py index bf675dd..ca83408 100755 --- a/lib/main.py +++ b/lib/main.py @@ -29,6 +29,7 @@ def main(args): sh_filters, mh_filters_config, mh_filters_tags, + mh_filters_impact, sh_account, sh_account_alias_str, sh_region, @@ -52,6 +53,7 @@ def print_options(): print_table("Context Options: ", str(args.context), banners=banners) print_table("Config Filters: ", str(mh_filters_config), banners=banners) print_table("Tags Filters: ", str(mh_filters_tags), banners=banners) + print_table("Impact Filters: ", str(mh_filters_impact), banners=banners) print_table("Update Findings: ", str(args.update_findings), banners=banners) print_table("Enrich Findings: ", str(args.enrich_findings), banners=banners) print_table( @@ -83,6 +85,7 @@ def print_options(): mh_role=args.mh_assume_role, mh_filters_config=mh_filters_config, mh_filters_tags=mh_filters_tags, + mh_filters_impact=mh_filters_impact, inputs=args.inputs, asff_findings=asff_findings, banners=banners,