From 641333ba6d6df06cad08a93226d13e6ea9ebb3b3 Mon Sep 17 00:00:00 2001 From: Gabriel Soltz <8935378+gabrielsoltz@users.noreply.github.com> Date: Sat, 9 Dec 2023 15:16:39 +0000 Subject: [PATCH] lambda-execute-by-resource-id (#75) * lambda-execute-by-resource-id * fix-list * fix-list * fix-list * lambda * add-access-and-status-insights * increase-lambda-memory --- README.md | 22 +-- lib/lambda.py | 14 +- terraform/lambda.tf | 1 + terraform/sh-insights.tf | 338 +++++++++++++++++++++++++++++++++++++-- 4 files changed, 348 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 677285d..fa937a1 100644 --- a/README.md +++ b/README.md @@ -341,11 +341,7 @@ docker run -ti metahub ./metahub -h **MetaHub** is Lambda/Serverless ready! You can run MetaHub directly on an AWS Lambda function without any additional infrastructure required. -Running MetaHub in a Lambda function allows you to automate its execution based on your defined triggers. - -Terraform code is provided for deploying the Lambda function and all its dependencies. - -## Lambda use-cases +Running MetaHub in a Lambda function allows you to automate its execution based on your defined triggers. For example, you can: - Trigger the MetaHub Lambda function each time there is a new security finding to enrich that finding back in AWS Security Hub. - Trigger the MetaHub Lambda function each time there is a new security finding for suppression based on Context. @@ -364,7 +360,9 @@ terraform init terraform apply ``` -The code will create a zip file for the lambda code and a zip file for the Python dependencies. It will also create a Lambda function and all the required resources. +The code will create a zip file for the Lambda code and a zip file for the Python dependencies that we will use as Lambda layer. It will also create the Lambda function and all the required resources. + +The Terraform code will also create a Security Hub custom action and an EventBridge rule to trigger the Lambda function when the custom action is executed. See below. ## Customize Lambda behaviour @@ -376,19 +374,20 @@ Terraform will create the minimum required permissions for the Lambda function t # Run with Security Hub Custom Action -**MetaHub** can be run as a Security Hub Custom Action. This allows you to run MetaHub directly from the Security Hub console for a selected finding or for a selected set of findings. +**MetaHub** can be run as a [Security Hub Custom Action](https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-cwe-custom-actions.html). This allows you to run MetaHub directly from the Security Hub console for a selected finding or for a selected set of findings.

custom_action

-The custom action will then trigger a Lambda function that will run MetaHub for the selected findings. By default, the Lambda function will run MetaHub with the option `--enrich-findings`, which means that it will update your finding back with MetaHub outputs. If you want to change this, see [Customize Lambda behavior](#customize-lambda-behaviour) +The custom action will then trigger a Lambda function that will run MetaHub for the selected findings. -You need first to create the Lambda function and then create the custom action in Security Hub. +When you trigger the Lambda using the Security Hub Custom Action, the lambda will read the selected findings for it's context, and it will execute once for each finding. By default, no action will be taken on the findings, but you can change this behavior. See [Customize Lambda behavior](#customize-lambda-behaviour). -For creating the lambda function, follow the instructions in the [Run with Lambda](#run-with-lambda) section. +The Security Hub custom action is deployed as part of the Terraform code. See [Deploying Lambda](#deploying-lambda) for more information. -For creating the AWS Security Hub custom action: +
+ If you want to deploy it manually, you can follow the steps below: 1. In Security Hub, choose Settings and then choose Custom Actions. 2. Choose Create custom action. @@ -407,6 +406,7 @@ For creating the AWS Security Hub custom action: 15. Choose Next. 16. Under Select targets, choose the Lambda function 17. Select the Lambda function you created for MetaHub. +
# AWS Authentication diff --git a/lib/lambda.py b/lib/lambda.py index 4737d33..a0245a4 100644 --- a/lib/lambda.py +++ b/lib/lambda.py @@ -6,10 +6,10 @@ def lambda_handler(event, context): logger = get_logger("INFO") # Add your custom options here (e.g. Only Critical: ["--sh-filters", "SeverityLabel=CRITICAL"]) - # Only used if running lambda manually, not from Security Hub Custom Actions + # Only used if triggering lambda manually, not from Security Hub Custom Actions CUSTOM_OPTIONS = [] - # - Actions the lambda will execute, if you don't need actions, keep this list empty + # Actions the lambda will execute, if you don't need actions, keep this list empty # Example, for enriching findings: # ACTIONS = [ # "--enrich-findings", @@ -17,7 +17,7 @@ def lambda_handler(event, context): # ] ACTIONS = [] - # This are the minimum options required to run the Lambda, don't change this + # These are the minimum options required to run the Lambda, don't change this LAMBDA_OPTIONS = [ "--output-modes", "lambda", @@ -39,9 +39,15 @@ def lambda_handler(event, context): logger.info("Security Hub Custom Action: %s", action_name) for finding in event_detail.get("findings"): finding_id = finding.get("Id") + resource_id = finding.get("Resources")[0].get("Id") logger.info("Security Hub Finding: %s", finding_id) CUSTOM_OPTIONS = [] - LAMBDA_OPTIONS.extend(["--sh-filters", f"Id={finding_id}"]) + # Search by ResoureId + LAMBDA_OPTIONS.extend( + ["--sh-filters", f"ResourceId={resource_id}", "RecordState=ACTIVE"] + ) + # Search by FindingId + # LAMBDA_OPTIONS.extend(["--sh-filters", f"Id={finding_id}"]) OPTIONS = LAMBDA_OPTIONS + ACTIONS + CUSTOM_OPTIONS diff --git a/terraform/lambda.tf b/terraform/lambda.tf index 8bcce7c..e10af6e 100644 --- a/terraform/lambda.tf +++ b/terraform/lambda.tf @@ -38,6 +38,7 @@ resource "aws_lambda_function" "lambda_zip" { timeout = 600 layers = [aws_lambda_layer_version.lambda_layer.id] source_code_hash = data.local_file.code_hash.content + memory_size = 256 tags = { Service = local.prefix diff --git a/terraform/sh-insights.tf b/terraform/sh-insights.tf index 2703218..a927e45 100644 --- a/terraform/sh-insights.tf +++ b/terraform/sh-insights.tf @@ -1,6 +1,8 @@ # Insights -resource "aws_securityhub_insight" "exposure_restricted" { +# Exposure Insights + +resource "aws_securityhub_insight" "exposure_effectively_public" { filters { record_state { comparison = "EQUALS" @@ -9,17 +11,17 @@ resource "aws_securityhub_insight" "exposure_restricted" { user_defined_values { comparison = "EQUALS" key = "exposure" - value = "restricted" + value = "effectively-public" } } group_by_attribute = "ResourceId" - name = "MetaHub Exposure: Restricted" + name = "MetaHub Exposure: Effectively Public" } -resource "aws_securityhub_insight" "exposure_launch_public" { +resource "aws_securityhub_insight" "exposure_restricted_public" { filters { record_state { comparison = "EQUALS" @@ -28,13 +30,13 @@ resource "aws_securityhub_insight" "exposure_launch_public" { user_defined_values { comparison = "EQUALS" key = "exposure" - value = "launch-public" + value = "restricted-public" } } group_by_attribute = "ResourceId" - name = "MetaHub Exposure: Launch Public" + name = "MetaHub Exposure: Restricted Public" } @@ -57,7 +59,7 @@ resource "aws_securityhub_insight" "exposure_unrestricted_private" { } -resource "aws_securityhub_insight" "exposure_restricted_public" { +resource "aws_securityhub_insight" "exposure_launch_public" { filters { record_state { comparison = "EQUALS" @@ -66,17 +68,17 @@ resource "aws_securityhub_insight" "exposure_restricted_public" { user_defined_values { comparison = "EQUALS" key = "exposure" - value = "restricted-public" + value = "launch-public" } } group_by_attribute = "ResourceId" - name = "MetaHub Exposure: Restricted Public" + name = "MetaHub Exposure: Launch Public" } -resource "aws_securityhub_insight" "exposure_effectively_public" { +resource "aws_securityhub_insight" "exposure_restricted" { filters { record_state { comparison = "EQUALS" @@ -85,12 +87,324 @@ resource "aws_securityhub_insight" "exposure_effectively_public" { user_defined_values { comparison = "EQUALS" key = "exposure" - value = "effectively-public" + value = "restricted" } } group_by_attribute = "ResourceId" - name = "MetaHub Exposure: Effectively Public" + name = "MetaHub Exposure: Restricted" + +} + + + +# Access Insights + +resource "aws_securityhub_insight" "access_unrestricted" { + filters { + record_state { + comparison = "EQUALS" + value = "ACTIVE" + } + user_defined_values { + comparison = "EQUALS" + key = "access" + value = "unrestricted" + } + } + + group_by_attribute = "ResourceId" + + name = "MetaHub Access: Unrestricted" + +} + +resource "aws_securityhub_insight" "access_untrusted-principal" { + filters { + record_state { + comparison = "EQUALS" + value = "ACTIVE" + } + user_defined_values { + comparison = "EQUALS" + key = "access" + value = "untrusted-principal" + } + } + + group_by_attribute = "ResourceId" + + name = "MetaHub Access: Untrusted Principal" + +} + +resource "aws_securityhub_insight" "access_unrestricted-principal" { + filters { + record_state { + comparison = "EQUALS" + value = "ACTIVE" + } + user_defined_values { + comparison = "EQUALS" + key = "access" + value = "unrestricted-principal" + } + } + + group_by_attribute = "ResourceId" + + name = "MetaHub Access: Unrestricted Principal" + +} + +resource "aws_securityhub_insight" "access_cross-account-principal" { + filters { + record_state { + comparison = "EQUALS" + value = "ACTIVE" + } + user_defined_values { + comparison = "EQUALS" + key = "access" + value = "cross-account-principal" + } + } + + group_by_attribute = "ResourceId" + + name = "MetaHub Access: Cross-Account principal" + +} + +resource "aws_securityhub_insight" "access_unrestricted-actions" { + filters { + record_state { + comparison = "EQUALS" + value = "ACTIVE" + } + user_defined_values { + comparison = "EQUALS" + key = "access" + value = "unrestricted-actions" + } + } + + group_by_attribute = "ResourceId" + + name = "MetaHub Access: Unrestricted Actions" + +} + +resource "aws_securityhub_insight" "access_dangerous-actions" { + filters { + record_state { + comparison = "EQUALS" + value = "ACTIVE" + } + user_defined_values { + comparison = "EQUALS" + key = "access" + value = "dangerous-actions" + } + } + + group_by_attribute = "ResourceId" + + name = "MetaHub Access: Dangerous Actions" + +} + +resource "aws_securityhub_insight" "access_unrestricted-service" { + filters { + record_state { + comparison = "EQUALS" + value = "ACTIVE" + } + user_defined_values { + comparison = "EQUALS" + key = "access" + value = "unrestricted-service" + } + } + + group_by_attribute = "ResourceId" + + name = "MetaHub Access: Unrestricted Service" + +} + +resource "aws_securityhub_insight" "access_restricted" { + filters { + record_state { + comparison = "EQUALS" + value = "ACTIVE" + } + user_defined_values { + comparison = "EQUALS" + key = "access" + value = "restricted" + } + } + + group_by_attribute = "ResourceId" + + name = "MetaHub Access: Restricted" + +} + +# Encryption Insights + +resource "aws_securityhub_insight" "encryption_unencrypted" { + filters { + record_state { + comparison = "EQUALS" + value = "ACTIVE" + } + user_defined_values { + comparison = "EQUALS" + key = "encryption" + value = "unencrypted" + } + } + + group_by_attribute = "ResourceId" + + name = "MetaHub Encryption: Unencrypted" + +} + +resource "aws_securityhub_insight" "encryption_encrypted" { + filters { + record_state { + comparison = "EQUALS" + value = "ACTIVE" + } + user_defined_values { + comparison = "EQUALS" + key = "encryption" + value = "encrypted" + } + } + + group_by_attribute = "ResourceId" + + name = "MetaHub Encryption: Encrypted" + +} + +# Status Insights + +resource "aws_securityhub_insight" "status_attached" { + filters { + record_state { + comparison = "EQUALS" + value = "ACTIVE" + } + user_defined_values { + comparison = "EQUALS" + key = "status" + value = "attached" + } + } + + group_by_attribute = "ResourceId" + + name = "MetaHub Status: Attached" + +} + +resource "aws_securityhub_insight" "status_running" { + filters { + record_state { + comparison = "EQUALS" + value = "ACTIVE" + } + user_defined_values { + comparison = "EQUALS" + key = "status" + value = "running" + } + } + + group_by_attribute = "ResourceId" + + name = "MetaHub Status: Running" + +} + +resource "aws_securityhub_insight" "status_enabled" { + filters { + record_state { + comparison = "EQUALS" + value = "ACTIVE" + } + user_defined_values { + comparison = "EQUALS" + key = "status" + value = "enabled" + } + } + + group_by_attribute = "ResourceId" + + name = "MetaHub Status: Enabled" + +} + +resource "aws_securityhub_insight" "status_not_attached" { + filters { + record_state { + comparison = "EQUALS" + value = "ACTIVE" + } + user_defined_values { + comparison = "EQUALS" + key = "status" + value = "not-attached" + } + } + + group_by_attribute = "ResourceId" + + name = "MetaHub Status: Not Attached" + +} + +resource "aws_securityhub_insight" "status_not_running" { + filters { + record_state { + comparison = "EQUALS" + value = "ACTIVE" + } + user_defined_values { + comparison = "EQUALS" + key = "status" + value = "not-running" + } + } + + group_by_attribute = "ResourceId" + + name = "MetaHub Status: Not Running" + +} + +resource "aws_securityhub_insight" "status_not_enabled" { + filters { + record_state { + comparison = "EQUALS" + value = "ACTIVE" + } + user_defined_values { + comparison = "EQUALS" + key = "status" + value = "not-enabled" + } + } + + group_by_attribute = "ResourceId" + + name = "MetaHub Status: Not Enabled" }