From fcb979aae1497c3c8d7d63d005781297b43e8ab7 Mon Sep 17 00:00:00 2001 From: Sergio Garcia <38561120+sergargar@users.noreply.github.com> Date: Mon, 30 Oct 2023 17:51:49 +0100 Subject: [PATCH] feat(allowlist): allowlist non-default regions configuration (#2974) --- docs/tutorials/configuration_file.md | 19 +++++++ prowler/config/config.yaml | 5 ++ .../config_recorder_all_regions_enabled.py | 6 +++ .../drs/drs_job_exist/drs_job_exist.py | 6 +++ .../guardduty_is_enabled.py | 8 +++ .../securityhub_enabled.py | 13 ++++- ...onfig_recorder_all_regions_enabled_test.py | 52 +++++++++++++++++++ .../drs/drs_job_exist/drs_job_exist_test.py | 34 ++++++++++++ .../guardduty_is_enabled_test.py | 35 +++++++++++++ .../securityhub_enabled_test.py | 40 ++++++++++++++ 10 files changed, 216 insertions(+), 2 deletions(-) diff --git a/docs/tutorials/configuration_file.md b/docs/tutorials/configuration_file.md index 4c72963f..bc9f149b 100644 --- a/docs/tutorials/configuration_file.md +++ b/docs/tutorials/configuration_file.md @@ -29,6 +29,10 @@ The following list includes all the AWS checks with configurable variables that | `organizations_delegated_administrators` | `organizations_trusted_delegated_administrators` | List of Strings | | `ecr_repositories_scan_vulnerabilities_in_latest_image` | `ecr_repository_vulnerability_minimum_severity` | String | | `trustedadvisor_premium_support_plan_subscribed` | `verify_premium_support_plans` | Boolean | +| `config_recorder_all_regions_enabled` | `allowlist_non_default_regions` | Boolean | +| `drs_job_exist` | `allowlist_non_default_regions` | Boolean | +| `guardduty_is_enabled` | `allowlist_non_default_regions` | Boolean | +| `securityhub_enabled` | `allowlist_non_default_regions` | Boolean | ## Azure @@ -44,6 +48,17 @@ The following list includes all the AWS checks with configurable variables that ```yaml title="config.yaml" # AWS Configuration aws: + + # AWS Global Configuration + # aws.allowlist_non_default_regions --> Allowlist Failed Findings in non-default regions for GuardDuty, SecurityHub, DRS and Config + allowlist_non_default_regions: False + + # AWS IAM Configuration + # aws.iam_user_accesskey_unused --> CIS recommends 45 days + max_unused_access_keys_days: 45 + # aws.iam_user_console_access_unused --> CIS recommends 45 days + max_console_access_days: 45 + # AWS EC2 Configuration # aws.ec2_elastic_ip_shodan shodan_api_key: null @@ -105,6 +120,10 @@ aws: # MEDIUM ecr_repository_vulnerability_minimum_severity: "MEDIUM" + # AWS Trusted Advisor + # trustedadvisor_premium_support_plan_subscribed + verify_premium_support_plans: True + # Azure Configuration azure: diff --git a/prowler/config/config.yaml b/prowler/config/config.yaml index ee82363f..4a4fe73d 100644 --- a/prowler/config/config.yaml +++ b/prowler/config/config.yaml @@ -1,5 +1,10 @@ # AWS Configuration aws: + + # AWS Global Configuration + # aws.allowlist_non_default_regions --> Allowlist Failed Findings in non-default regions for GuardDuty, SecurityHub, DRS and Config + allowlist_non_default_regions: False + # AWS IAM Configuration # aws.iam_user_accesskey_unused --> CIS recommends 45 days max_unused_access_keys_days: 45 diff --git a/prowler/providers/aws/services/config/config_recorder_all_regions_enabled/config_recorder_all_regions_enabled.py b/prowler/providers/aws/services/config/config_recorder_all_regions_enabled/config_recorder_all_regions_enabled.py index adfcfcc5..5e4b86a5 100644 --- a/prowler/providers/aws/services/config/config_recorder_all_regions_enabled/config_recorder_all_regions_enabled.py +++ b/prowler/providers/aws/services/config/config_recorder_all_regions_enabled/config_recorder_all_regions_enabled.py @@ -35,6 +35,12 @@ class config_recorder_all_regions_enabled(Check): report.status_extended = ( f"AWS Config recorder {recorder.name} is disabled." ) + if report.status == "FAIL" and ( + config_client.audit_config.get("allowlist_non_default_regions", False) + and not recorder.region == config_client.region + ): + report.status = "WARNING" + findings.append(report) return findings diff --git a/prowler/providers/aws/services/drs/drs_job_exist/drs_job_exist.py b/prowler/providers/aws/services/drs/drs_job_exist/drs_job_exist.py index d7f4dd50..9a65dea7 100644 --- a/prowler/providers/aws/services/drs/drs_job_exist/drs_job_exist.py +++ b/prowler/providers/aws/services/drs/drs_job_exist/drs_job_exist.py @@ -19,6 +19,12 @@ class drs_job_exist(Check): report.status = "PASS" report.status_extended = "DRS is enabled for this region with jobs." + if report.status == "FAIL" and ( + drs_client.audit_config.get("allowlist_non_default_regions", False) + and not drs.region == drs_client.region + ): + report.status = "WARNING" + findings.append(report) return findings diff --git a/prowler/providers/aws/services/guardduty/guardduty_is_enabled/guardduty_is_enabled.py b/prowler/providers/aws/services/guardduty/guardduty_is_enabled/guardduty_is_enabled.py index 0075c65f..5a27f4be 100644 --- a/prowler/providers/aws/services/guardduty/guardduty_is_enabled/guardduty_is_enabled.py +++ b/prowler/providers/aws/services/guardduty/guardduty_is_enabled/guardduty_is_enabled.py @@ -27,6 +27,14 @@ class guardduty_is_enabled(Check): f"GuardDuty detector {detector.id} configured but suspended." ) + if report.status == "FAIL" and ( + guardduty_client.audit_config.get( + "allowlist_non_default_regions", False + ) + and not detector.region == guardduty_client.region + ): + report.status = "WARNING" + findings.append(report) return findings diff --git a/prowler/providers/aws/services/securityhub/securityhub_enabled/securityhub_enabled.py b/prowler/providers/aws/services/securityhub/securityhub_enabled/securityhub_enabled.py index c93b8753..62023ebb 100644 --- a/prowler/providers/aws/services/securityhub/securityhub_enabled/securityhub_enabled.py +++ b/prowler/providers/aws/services/securityhub/securityhub_enabled/securityhub_enabled.py @@ -10,6 +10,8 @@ class securityhub_enabled(Check): for securityhub in securityhub_client.securityhubs: report = Check_Report_AWS(self.metadata()) report.region = securityhub.region + report.resource_id = securityhub.id + report.resource_arn = securityhub.arn if securityhub.status == "ACTIVE": report.status = "PASS" if securityhub.standards: @@ -22,8 +24,15 @@ class securityhub_enabled(Check): else: report.status = "FAIL" report.status_extended = "Security Hub is not enabled." - report.resource_id = securityhub.id - report.resource_arn = securityhub.arn + + if report.status == "FAIL" and ( + securityhub_client.audit_config.get( + "allowlist_non_default_regions", False + ) + and not securityhub.region == securityhub_client.region + ): + report.status = "WARNING" + findings.append(report) return findings diff --git a/tests/providers/aws/services/config/config_recorder_all_regions_enabled/config_recorder_all_regions_enabled_test.py b/tests/providers/aws/services/config/config_recorder_all_regions_enabled/config_recorder_all_regions_enabled_test.py index 21ddd969..653f4244 100644 --- a/tests/providers/aws/services/config/config_recorder_all_regions_enabled/config_recorder_all_regions_enabled_test.py +++ b/tests/providers/aws/services/config/config_recorder_all_regions_enabled/config_recorder_all_regions_enabled_test.py @@ -39,6 +39,7 @@ class Test_config_recorder_all_regions_enabled: completed_checks=0, audit_progress=0, ), + audit_config={}, ) return audit_info @@ -159,3 +160,54 @@ class Test_config_recorder_all_regions_enabled: assert recorder.resource_id == "default" assert recorder.resource_arn == AWS_ACCOUNT_ARN assert recorder.region == AWS_REGION + + @mock_config + def test_config_one_recorder_disabled_allowlisted(self): + # Create Config Mocked Resources + config_client = client("config", region_name=AWS_REGION) + # Create Config Recorder + config_client.put_configuration_recorder( + ConfigurationRecorder={"name": AWS_ACCOUNT_NUMBER, "roleARN": "somearn"} + ) + from prowler.providers.aws.services.config.config_service import Config + + current_audit_info = self.set_mocked_audit_info() + current_audit_info.profile_region = "eu-south-2" + current_audit_info.audited_regions = ["eu-south-2", AWS_REGION] + current_audit_info.audit_config = {"allowlist_non_default_regions": True} + + with mock.patch( + "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", + new=current_audit_info, + ), mock.patch( + "prowler.providers.aws.services.config.config_recorder_all_regions_enabled.config_recorder_all_regions_enabled.config_client", + new=Config(current_audit_info), + ): + # Test Check + from prowler.providers.aws.services.config.config_recorder_all_regions_enabled.config_recorder_all_regions_enabled import ( + config_recorder_all_regions_enabled, + ) + + check = config_recorder_all_regions_enabled() + result = check.execute() + assert len(result) == 2 + # Search for the recorder just created + for recorder in result: + if recorder.region == AWS_REGION: + assert recorder.status == "WARNING" + assert ( + recorder.status_extended + == f"AWS Config recorder {AWS_ACCOUNT_NUMBER} is disabled." + ) + assert recorder.resource_id == AWS_ACCOUNT_NUMBER + assert recorder.resource_arn == AWS_ACCOUNT_ARN + assert recorder.region == AWS_REGION + else: + assert recorder.status == "FAIL" + assert ( + recorder.status_extended + == f"AWS Config recorder {AWS_ACCOUNT_NUMBER} is disabled." + ) + assert recorder.resource_id == AWS_ACCOUNT_NUMBER + assert recorder.resource_arn == AWS_ACCOUNT_ARN + assert recorder.region == "eu-south-2" diff --git a/tests/providers/aws/services/drs/drs_job_exist/drs_job_exist_test.py b/tests/providers/aws/services/drs/drs_job_exist/drs_job_exist_test.py index caf9f714..4fad6112 100644 --- a/tests/providers/aws/services/drs/drs_job_exist/drs_job_exist_test.py +++ b/tests/providers/aws/services/drs/drs_job_exist/drs_job_exist_test.py @@ -119,3 +119,37 @@ class Test_drs_job_exist: assert result[0].resource_arn == f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:root" assert result[0].region == AWS_REGION assert result[0].resource_tags == [] + + def test_drs_disabled_allowlisted(self): + drs_client = mock.MagicMock + drs_client.audit_config = {"allowlist_non_default_regions": True} + drs_client.audited_account = AWS_ACCOUNT_NUMBER + drs_client.audited_account_arn = f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:root" + drs_client.region = "eu-west-2" + drs_client.drs_services = [ + DRSservice( + id="DRS", + status="DISABLED", + region=AWS_REGION, + jobs=[], + ) + ] + with mock.patch( + "prowler.providers.aws.services.drs.drs_service.DRS", + new=drs_client, + ): + # Test Check + from prowler.providers.aws.services.drs.drs_job_exist.drs_job_exist import ( + drs_job_exist, + ) + + check = drs_job_exist() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "WARNING" + assert result[0].status_extended == "DRS is not enabled for this region." + assert result[0].resource_id == AWS_ACCOUNT_NUMBER + assert result[0].resource_arn == f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:root" + assert result[0].region == AWS_REGION + assert result[0].resource_tags == [] diff --git a/tests/providers/aws/services/guardduty/guardduty_is_enabled/guardduty_is_enabled_test.py b/tests/providers/aws/services/guardduty/guardduty_is_enabled/guardduty_is_enabled_test.py index 2872d923..d5f5775f 100644 --- a/tests/providers/aws/services/guardduty/guardduty_is_enabled/guardduty_is_enabled_test.py +++ b/tests/providers/aws/services/guardduty/guardduty_is_enabled/guardduty_is_enabled_test.py @@ -15,6 +15,7 @@ detector_arn = f"arn:aws:guardduty:{AWS_REGION}:{AWS_ACCOUNT_ID}:detector/{detec class Test_guardduty_is_enabled: def test_no_detectors(self): guardduty_client = mock.MagicMock + guardduty_client.region = AWS_REGION guardduty_client.detectors = [] guardduty_client.detectors.append( Detector( @@ -71,6 +72,7 @@ class Test_guardduty_is_enabled: def test_guardduty_configured_but_suspended(self): guardduty_client = mock.MagicMock + guardduty_client.region = AWS_REGION guardduty_client.detectors = [] guardduty_client.detectors.append( Detector( @@ -100,6 +102,7 @@ class Test_guardduty_is_enabled: def test_guardduty_not_configured(self): guardduty_client = mock.MagicMock guardduty_client.detectors = [] + guardduty_client.region = AWS_REGION guardduty_client.detectors.append( Detector( id=detector_id, @@ -123,3 +126,35 @@ class Test_guardduty_is_enabled: assert result[0].resource_id == detector_id assert result[0].resource_arn == detector_arn assert result[0].region == AWS_REGION + + def test_guardduty_not_configured_allowlisted(self): + guardduty_client = mock.MagicMock + guardduty_client.audit_config = {"allowlist_non_default_regions": True} + guardduty_client.region = "eu-south-2" + guardduty_client.detectors = [] + guardduty_client.detectors.append( + Detector( + id=detector_id, + arn=detector_arn, + region=AWS_REGION, + ) + ) + with mock.patch( + "prowler.providers.aws.services.guardduty.guardduty_service.GuardDuty", + guardduty_client, + ): + from prowler.providers.aws.services.guardduty.guardduty_is_enabled.guardduty_is_enabled import ( + guardduty_is_enabled, + ) + + check = guardduty_is_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "WARNING" + assert ( + result[0].status_extended + == f"GuardDuty detector {detector_id} not configured." + ) + assert result[0].resource_id == detector_id + assert result[0].resource_arn == detector_arn + assert result[0].region == AWS_REGION diff --git a/tests/providers/aws/services/securityhub/securityhub_enabled/securityhub_enabled_test.py b/tests/providers/aws/services/securityhub/securityhub_enabled/securityhub_enabled_test.py index 3435b952..977ab1a4 100644 --- a/tests/providers/aws/services/securityhub/securityhub_enabled/securityhub_enabled_test.py +++ b/tests/providers/aws/services/securityhub/securityhub_enabled/securityhub_enabled_test.py @@ -12,6 +12,7 @@ AWS_ACCOUNT_ARN = f"arn:aws:iam::{AWS_ACCOUNT_ID}:root" class Test_securityhub_enabled: def test_securityhub_hub_inactive(self): securityhub_client = mock.MagicMock + securityhub_client.region = AWS_REGION securityhub_client.securityhubs = [ SecurityHubHub( arn=AWS_ACCOUNT_ARN, @@ -114,6 +115,7 @@ class Test_securityhub_enabled: def test_securityhub_hub_active_without_integrations_or_standards(self): securityhub_client = mock.MagicMock + securityhub_client.region = AWS_REGION securityhub_client.securityhubs = [ SecurityHubHub( arn="arn:aws:securityhub:us-east-1:0123456789012:hub/default", @@ -147,3 +149,41 @@ class Test_securityhub_enabled: == "arn:aws:securityhub:us-east-1:0123456789012:hub/default" ) assert result[0].region == AWS_REGION + + def test_securityhub_hub_active_without_integrations_or_standards_allowlisted(self): + securityhub_client = mock.MagicMock + securityhub_client.audit_config = {"allowlist_non_default_regions": True} + securityhub_client.region = AWS_REGION + securityhub_client.securityhubs = [ + SecurityHubHub( + arn="arn:aws:securityhub:us-east-1:0123456789012:hub/default", + id="default", + status="ACTIVE", + standards="", + integrations="", + region="eu-south-2", + ) + ] + with mock.patch( + "prowler.providers.aws.services.securityhub.securityhub_service.SecurityHub", + new=securityhub_client, + ): + # Test Check + from prowler.providers.aws.services.securityhub.securityhub_enabled.securityhub_enabled import ( + securityhub_enabled, + ) + + check = securityhub_enabled() + result = check.execute() + + assert result[0].status == "WARNING" + assert ( + result[0].status_extended + == "Security Hub is enabled but without any standard or integration." + ) + assert result[0].resource_id == "default" + assert ( + result[0].resource_arn + == "arn:aws:securityhub:us-east-1:0123456789012:hub/default" + ) + assert result[0].region == "eu-south-2"