diff --git a/prowler/__main__.py b/prowler/__main__.py index e7d2569a..1cd5e6cd 100644 --- a/prowler/__main__.py +++ b/prowler/__main__.py @@ -247,7 +247,7 @@ def prowler(): for region in security_hub_regions: # Save the regions where AWS Security Hub is enabled if verify_security_hub_integration_enabled_per_region( - region, audit_info.audit_session + region, audit_info.audit_session, audit_info.audited_account ): aws_security_enabled_regions.append(region) diff --git a/prowler/providers/aws/lib/security_hub/security_hub.py b/prowler/providers/aws/lib/security_hub/security_hub.py index 4b155312..08fb44d7 100644 --- a/prowler/providers/aws/lib/security_hub/security_hub.py +++ b/prowler/providers/aws/lib/security_hub/security_hub.py @@ -14,9 +14,11 @@ def prepare_security_hub_findings( findings: [], audit_info: AWS_Audit_Info, output_options, enabled_regions: [] ) -> dict: security_hub_findings_per_region = {} - # Create a key per region - for region in audit_info.audited_regions: + + # Create a key per audited region + for region in enabled_regions: security_hub_findings_per_region[region] = [] + for finding in findings: # We don't send the INFO findings to AWS Security Hub if finding.status == "INFO": @@ -49,6 +51,7 @@ def prepare_security_hub_findings( def verify_security_hub_integration_enabled_per_region( region: str, session: session.Session, + aws_account_number: str, ) -> bool: f"""verify_security_hub_integration_enabled returns True if the {SECURITY_HUB_INTEGRATION_NAME} is enabled for the given region. Otherwise returns false.""" prowler_integration_enabled = False @@ -62,7 +65,8 @@ def verify_security_hub_integration_enabled_per_region( security_hub_client.describe_hub() # Check if Prowler integration is enabled in Security Hub - if "prowler/prowler" not in str( + security_hub_prowler_integration_arn = f"arn:aws:securityhub:{region}:{aws_account_number}:product-subscription/{SECURITY_HUB_INTEGRATION_NAME}" + if security_hub_prowler_integration_arn not in str( security_hub_client.list_enabled_products_for_import() ): logger.error( diff --git a/tests/providers/aws/audit_info_utils.py b/tests/providers/aws/audit_info_utils.py index d2598a8c..6d98887d 100644 --- a/tests/providers/aws/audit_info_utils.py +++ b/tests/providers/aws/audit_info_utils.py @@ -5,6 +5,7 @@ from prowler.providers.common.models import Audit_Metadata AWS_REGION_US_EAST_1 = "us-east-1" AWS_REGION_EU_WEST_1 = "eu-west-1" +AWS_REGION_EU_WEST_2 = "eu-west-2" AWS_PARTITION = "aws" AWS_ACCOUNT_NUMBER = "123456789012" AWS_ACCOUNT_ARN = f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:root" diff --git a/tests/providers/aws/lib/security_hub/security_hub_test.py b/tests/providers/aws/lib/security_hub/security_hub_test.py index 6c81d2e4..4f3ca397 100644 --- a/tests/providers/aws/lib/security_hub/security_hub_test.py +++ b/tests/providers/aws/lib/security_hub/security_hub_test.py @@ -6,7 +6,6 @@ from mock import MagicMock, patch from prowler.config.config import prowler_version, timestamp_utc from prowler.lib.check.models import Check_Report, load_check_metadata -from prowler.providers.aws.lib.audit_info.models import AWS_Audit_Info # from prowler.providers.aws.lib.audit_info.models import AWS_Audit_Info from prowler.providers.aws.lib.security_hub.security_hub import ( @@ -14,11 +13,12 @@ from prowler.providers.aws.lib.security_hub.security_hub import ( prepare_security_hub_findings, verify_security_hub_integration_enabled_per_region, ) -from prowler.providers.common.models import Audit_Metadata - -AWS_ACCOUNT_ID = "123456789012" -AWS_REGION_1 = "eu-west-1" -AWS_REGION_2 = "eu-west-2" +from tests.providers.aws.audit_info_utils import ( + AWS_ACCOUNT_NUMBER, + AWS_REGION_EU_WEST_1, + AWS_REGION_EU_WEST_2, + set_mocked_aws_audit_info, +) # Mocking Security Hub Get Findings make_api_call = botocore.client.BaseClient._make_api_call @@ -32,7 +32,7 @@ def mock_make_api_call(self, operation_name, kwarg): } if operation_name == "DescribeHub": return { - "HubArn": f"arn:aws:securityhub:{AWS_REGION_1}:{AWS_ACCOUNT_ID}:hub/default", + "HubArn": f"arn:aws:securityhub:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:hub/default", "SubscribedAt": "2023-02-07T09:45:43.742Z", "AutoEnableControls": True, "ControlFindingGenerator": "STANDARD_CONTROL", @@ -41,7 +41,7 @@ def mock_make_api_call(self, operation_name, kwarg): if operation_name == "ListEnabledProductsForImport": return { "ProductSubscriptions": [ - f"arn:aws:securityhub:{AWS_REGION_1}:{AWS_ACCOUNT_ID}:product-subscription/prowler/prowler", + f"arn:aws:securityhub:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:product-subscription/prowler/prowler", ] } @@ -49,32 +49,6 @@ def mock_make_api_call(self, operation_name, kwarg): class Test_SecurityHub: - def set_mocked_audit_info(self): - return AWS_Audit_Info( - session_config=None, - original_session=None, - audit_session=None, - audited_account=AWS_ACCOUNT_ID, - audited_account_arn=f"arn:aws:iam::{AWS_ACCOUNT_ID}:root", - audited_identity_arn="test-arn", - audited_user_id="test", - audited_partition="aws", - profile="default", - profile_region="eu-west-1", - credentials=None, - assumed_role_info=None, - audited_regions=["eu-west-2", "eu-west-1"], - organizations_metadata=None, - audit_resources=None, - mfa_enabled=False, - audit_metadata=Audit_Metadata( - services_scanned=0, - expected_checks=[], - completed_checks=0, - audit_progress=0, - ), - ) - def generate_finding(self, status, region): finding = Check_Report( load_check_metadata( @@ -104,14 +78,18 @@ class Test_SecurityHub: @patch("botocore.client.BaseClient._make_api_call", new=mock_make_api_call) def test_verify_security_hub_integration_enabled_per_region(self): - session = self.set_mocked_session(AWS_REGION_1) - assert verify_security_hub_integration_enabled_per_region(AWS_REGION_1, session) + session = self.set_mocked_session(AWS_REGION_EU_WEST_1) + assert verify_security_hub_integration_enabled_per_region( + AWS_REGION_EU_WEST_1, session, AWS_ACCOUNT_NUMBER + ) def test_prepare_security_hub_findings_enabled_region_not_quiet(self): - enabled_regions = [AWS_REGION_1] + enabled_regions = [AWS_REGION_EU_WEST_1] output_options = self.set_mocked_output_options(is_quiet=False) - findings = [self.generate_finding("PASS", AWS_REGION_1)] - audit_info = self.set_mocked_audit_info() + findings = [self.generate_finding("PASS", AWS_REGION_EU_WEST_1)] + audit_info = set_mocked_aws_audit_info( + audited_regions=[AWS_REGION_EU_WEST_1, AWS_REGION_EU_WEST_2] + ) assert prepare_security_hub_findings( findings, @@ -119,11 +97,11 @@ class Test_SecurityHub: output_options, enabled_regions, ) == { - AWS_REGION_1: [ + AWS_REGION_EU_WEST_1: [ { "SchemaVersion": "2018-10-08", - "Id": f"prowler-iam_user_accesskey_unused-{AWS_ACCOUNT_ID}-{AWS_REGION_1}-ee26b0dd4", - "ProductArn": f"arn:aws:securityhub:{AWS_REGION_1}::product/prowler/prowler", + "Id": f"prowler-iam_user_accesskey_unused-{AWS_ACCOUNT_NUMBER}-{AWS_REGION_EU_WEST_1}-ee26b0dd4", + "ProductArn": f"arn:aws:securityhub:{AWS_REGION_EU_WEST_1}::product/prowler/prowler", "RecordState": "ACTIVE", "ProductFields": { "ProviderName": "Prowler", @@ -131,7 +109,7 @@ class Test_SecurityHub: "ProwlerResourceName": "test", }, "GeneratorId": "prowler-iam_user_accesskey_unused", - "AwsAccountId": f"{AWS_ACCOUNT_ID}", + "AwsAccountId": f"{AWS_ACCOUNT_NUMBER}", "Types": ["Software and Configuration Checks"], "FirstObservedAt": timestamp_utc.strftime("%Y-%m-%dT%H:%M:%SZ"), "UpdatedAt": timestamp_utc.strftime("%Y-%m-%dT%H:%M:%SZ"), @@ -144,7 +122,7 @@ class Test_SecurityHub: "Type": "AwsIamAccessAnalyzer", "Id": "test", "Partition": "aws", - "Region": f"{AWS_REGION_1}", + "Region": f"{AWS_REGION_EU_WEST_1}", } ], "Compliance": { @@ -160,55 +138,117 @@ class Test_SecurityHub: }, } ], - AWS_REGION_2: [], } def test_prepare_security_hub_findings_quiet_INFO_finding(self): - enabled_regions = [AWS_REGION_1] + enabled_regions = [AWS_REGION_EU_WEST_1] output_options = self.set_mocked_output_options(is_quiet=False) - findings = [self.generate_finding("INFO", AWS_REGION_1)] - audit_info = self.set_mocked_audit_info() + findings = [self.generate_finding("INFO", AWS_REGION_EU_WEST_1)] + audit_info = set_mocked_aws_audit_info( + audited_regions=[AWS_REGION_EU_WEST_1, AWS_REGION_EU_WEST_2] + ) assert prepare_security_hub_findings( findings, audit_info, output_options, enabled_regions, - ) == {AWS_REGION_1: [], AWS_REGION_2: []} + ) == {AWS_REGION_EU_WEST_1: []} def test_prepare_security_hub_findings_disabled_region(self): - enabled_regions = [AWS_REGION_1] + enabled_regions = [AWS_REGION_EU_WEST_1] output_options = self.set_mocked_output_options(is_quiet=False) - findings = [self.generate_finding("PASS", AWS_REGION_2)] - audit_info = self.set_mocked_audit_info() + findings = [self.generate_finding("PASS", AWS_REGION_EU_WEST_2)] + audit_info = set_mocked_aws_audit_info( + audited_regions=[AWS_REGION_EU_WEST_1, AWS_REGION_EU_WEST_2] + ) assert prepare_security_hub_findings( findings, audit_info, output_options, enabled_regions, - ) == {AWS_REGION_1: [], AWS_REGION_2: []} + ) == {AWS_REGION_EU_WEST_1: []} def test_prepare_security_hub_findings_quiet(self): - enabled_regions = [AWS_REGION_1] + enabled_regions = [AWS_REGION_EU_WEST_1] output_options = self.set_mocked_output_options(is_quiet=True) - findings = [self.generate_finding("PASS", AWS_REGION_1)] - audit_info = self.set_mocked_audit_info() + findings = [self.generate_finding("PASS", AWS_REGION_EU_WEST_1)] + audit_info = set_mocked_aws_audit_info( + audited_regions=[AWS_REGION_EU_WEST_1, AWS_REGION_EU_WEST_2] + ) assert prepare_security_hub_findings( findings, audit_info, output_options, enabled_regions, - ) == {AWS_REGION_1: [], AWS_REGION_2: []} + ) == {AWS_REGION_EU_WEST_1: []} + + def test_prepare_security_hub_findings_no_audited_regions(self): + enabled_regions = [AWS_REGION_EU_WEST_1] + output_options = self.set_mocked_output_options(is_quiet=False) + findings = [self.generate_finding("PASS", AWS_REGION_EU_WEST_1)] + audit_info = set_mocked_aws_audit_info() + + assert prepare_security_hub_findings( + findings, + audit_info, + output_options, + enabled_regions, + ) == { + AWS_REGION_EU_WEST_1: [ + { + "SchemaVersion": "2018-10-08", + "Id": f"prowler-iam_user_accesskey_unused-{AWS_ACCOUNT_NUMBER}-{AWS_REGION_EU_WEST_1}-ee26b0dd4", + "ProductArn": f"arn:aws:securityhub:{AWS_REGION_EU_WEST_1}::product/prowler/prowler", + "RecordState": "ACTIVE", + "ProductFields": { + "ProviderName": "Prowler", + "ProviderVersion": prowler_version, + "ProwlerResourceName": "test", + }, + "GeneratorId": "prowler-iam_user_accesskey_unused", + "AwsAccountId": f"{AWS_ACCOUNT_NUMBER}", + "Types": ["Software and Configuration Checks"], + "FirstObservedAt": timestamp_utc.strftime("%Y-%m-%dT%H:%M:%SZ"), + "UpdatedAt": timestamp_utc.strftime("%Y-%m-%dT%H:%M:%SZ"), + "CreatedAt": timestamp_utc.strftime("%Y-%m-%dT%H:%M:%SZ"), + "Severity": {"Label": "LOW"}, + "Title": "Ensure Access Keys unused are disabled", + "Description": "test", + "Resources": [ + { + "Type": "AwsIamAccessAnalyzer", + "Id": "test", + "Partition": "aws", + "Region": f"{AWS_REGION_EU_WEST_1}", + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [], + "AssociatedStandards": [], + }, + "Remediation": { + "Recommendation": { + "Text": "Run sudo yum update and cross your fingers and toes.", + "Url": "https://myfp.com/recommendations/dangerous_things_and_how_to_fix_them.html", + } + }, + } + ], + } @patch("botocore.client.BaseClient._make_api_call", new=mock_make_api_call) def test_batch_send_to_security_hub_one_finding(self): - enabled_regions = [AWS_REGION_1] + enabled_regions = [AWS_REGION_EU_WEST_1] output_options = self.set_mocked_output_options(is_quiet=False) - findings = [self.generate_finding("PASS", AWS_REGION_1)] - audit_info = self.set_mocked_audit_info() - session = self.set_mocked_session(AWS_REGION_1) + findings = [self.generate_finding("PASS", AWS_REGION_EU_WEST_1)] + audit_info = set_mocked_aws_audit_info( + audited_regions=[AWS_REGION_EU_WEST_1, AWS_REGION_EU_WEST_2] + ) + session = self.set_mocked_session(AWS_REGION_EU_WEST_1) security_hub_findings = prepare_security_hub_findings( findings,