From 9e8023d716723921ed2a95758de25d124d7c0794 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Wed, 9 Aug 2023 09:52:45 +0200 Subject: [PATCH] fix(config): Pass a configuration file using `--config-file config.yaml` (#2679) --- docs/tutorials/configuration_file.md | 110 +++++---- prowler/config/config.py | 86 ++++--- prowler/config/config.yaml | 108 +++++---- prowler/lib/cli/parser.py | 11 + .../aws/lib/audit_info/audit_info.py | 1 + .../providers/aws/lib/audit_info/models.py | 1 + prowler/providers/aws/lib/service/service.py | 1 + ...ppstream_fleet_maximum_session_duration.py | 10 +- ...stream_fleet_session_disconnect_timeout.py | 10 +- ...m_fleet_session_idle_disconnect_timeout.py | 12 +- ...ambda_function_using_supported_runtimes.py | 5 +- ..._retention_policy_specific_days_enabled.py | 7 +- .../ec2_elastic_ip_shodan.py | 3 +- .../ec2_instance_older_than_specific_days.py | 7 +- ...itygroup_with_many_ingress_egress_rules.py | 7 +- .../organizations_delegated_administrators.py | 8 +- .../organizations_scp_check_deny_regions.py | 5 +- ...c_endpoint_connections_trust_boundaries.py | 3 +- ...ces_allowed_principals_trust_boundaries.py | 3 +- .../azure/lib/audit_info/audit_info.py | 1 + .../providers/azure/lib/audit_info/models.py | 6 +- prowler/providers/common/audit_info.py | 6 + prowler/providers/common/outputs.py | 4 +- .../gcp/lib/audit_info/audit_info.py | 1 + .../providers/gcp/lib/audit_info/models.py | 3 + tests/config/config_test.py | 156 +++++++++++- tests/config/fixtures/config.yaml | 61 +++++ tests/config/fixtures/config_old.yaml | 53 ++++ tests/lib/cli/parser_test.py | 14 ++ tests/lib/outputs/slack_test.py | 3 + ...eam_fleet_maximum_session_duration_test.py | 6 + ...m_fleet_session_disconnect_timeout_test.py | 5 + ...et_session_idle_disconnect_timeout_test.py | 6 + ..._function_using_supported_runtimes_test.py | 80 +++++-- ...ntion_policy_specific_days_enabled_test.py | 4 + .../ec2_elastic_ip_shodan_test.py | 226 +++++++++++------- ..._instance_older_than_specific_days_test.py | 3 + ...oup_with_many_ingress_egress_rules_test.py | 3 + ...nizations_delegated_administrators_test.py | 47 ++-- ...ganizations_scp_check_deny_regions_test.py | 77 +++--- ...point_connections_trust_boundaries_test.py | 110 +++++---- ...llowed_principals_trust_boundaries_test.py | 4 + tests/providers/common/audit_info_test.py | 5 + tests/providers/common/common_outputs_test.py | 10 +- 44 files changed, 910 insertions(+), 382 deletions(-) create mode 100644 tests/config/fixtures/config.yaml create mode 100644 tests/config/fixtures/config_old.yaml diff --git a/docs/tutorials/configuration_file.md b/docs/tutorials/configuration_file.md index c3e6eada..bbad963a 100644 --- a/docs/tutorials/configuration_file.md +++ b/docs/tutorials/configuration_file.md @@ -1,11 +1,14 @@ # Configuration File -Several Prowler's checks have user configurable variables that can be modified in a common **configuration file**. -This file can be found in the following path: +Several Prowler's checks have user configurable variables that can be modified in a common **configuration file**. This file can be found in the following [path](https://github.com/prowler-cloud/prowler/blob/master/prowler/config/config.yaml): ``` prowler/config/config.yaml ``` -## Configurable Checks +Also you can input a custom configuration file using the `--config-file` argument. + +## AWS + +### Configurable Checks The following list includes all the checks with configurable variables that can be changed in the mentioned configuration yaml file: 1. aws.ec2_elastic_ip_shodan @@ -29,48 +32,73 @@ The following list includes all the checks with configurable variables that can - aws.awslambda_function_using_supported_runtimes - obsolete_lambda_runtimes (List of Strings) -## Config Yaml File +## Azure - # AWS EC2 Configuration - # aws.ec2_elastic_ip_shodan - shodan_api_key: null - # aws.ec2_securitygroup_with_many_ingress_egress_rules --> by default is 50 rules - max_security_group_rules: 50 - # aws.ec2_instance_older_than_specific_days --> by default is 6 months (180 days) - max_ec2_instance_age_in_days: 180 +## GCP - # AWS VPC Configuration (vpc_endpoint_connections_trust_boundaries, vpc_endpoint_services_allowed_principals_trust_boundaries) - # Single account environment: No action required. The AWS account number will be automatically added by the checks. - # Multi account environment: Any additional trusted account number should be added as a space separated list, e.g. - # trusted_account_ids : ["123456789012", "098765432109", "678901234567"] - trusted_account_ids: [] +## Config YAML File Structure +> This is the new Prowler configuration file format. The old one without provider keys is still compatible just for the AWS provider. +```yaml +# AWS Configuration +aws: + # AWS EC2 Configuration + # aws.ec2_elastic_ip_shodan + shodan_api_key: null + # aws.ec2_securitygroup_with_many_ingress_egress_rules --> by default is 50 rules + max_security_group_rules: 50 + # aws.ec2_instance_older_than_specific_days --> by default is 6 months (180 days) + max_ec2_instance_age_in_days: 180 - # AWS Cloudwatch Configuration - # aws.cloudwatch_log_group_retention_policy_specific_days_enabled --> by default is 365 days - log_group_retention_days: 365 + # AWS VPC Configuration (vpc_endpoint_connections_trust_boundaries, vpc_endpoint_services_allowed_principals_trust_boundaries) + # Single account environment: No action required. The AWS account number will be automatically added by the checks. + # Multi account environment: Any additional trusted account number should be added as a space separated list, e.g. + # trusted_account_ids : ["123456789012", "098765432109", "678901234567"] + trusted_account_ids: [] - # AWS AppStream Session Configuration - # aws.appstream_fleet_session_idle_disconnect_timeout - max_idle_disconnect_timeout_in_seconds: 600 # 10 Minutes - # aws.appstream_fleet_session_disconnect_timeout - max_disconnect_timeout_in_seconds: 300 # 5 Minutes - # aws.appstream_fleet_maximum_session_duration - max_session_duration_seconds: 36000 # 10 Hours + # AWS Cloudwatch Configuration + # aws.cloudwatch_log_group_retention_policy_specific_days_enabled --> by default is 365 days + log_group_retention_days: 365 - # AWS Lambda Configuration - # aws.awslambda_function_using_supported_runtimes - obsolete_lambda_runtimes: + # AWS AppStream Session Configuration + # aws.appstream_fleet_session_idle_disconnect_timeout + max_idle_disconnect_timeout_in_seconds: 600 # 10 Minutes + # aws.appstream_fleet_session_disconnect_timeout + max_disconnect_timeout_in_seconds: 300 # 5 Minutes + # aws.appstream_fleet_maximum_session_duration + max_session_duration_seconds: 36000 # 10 Hours + + # AWS Lambda Configuration + # aws.awslambda_function_using_supported_runtimes + obsolete_lambda_runtimes: [ - "python3.6", - "python2.7", - "nodejs4.3", - "nodejs4.3-edge", - "nodejs6.10", - "nodejs", - "nodejs8.10", - "nodejs10.x", - "dotnetcore1.0", - "dotnetcore2.0", - "dotnetcore2.1", - "ruby2.5", + "python3.6", + "python2.7", + "nodejs4.3", + "nodejs4.3-edge", + "nodejs6.10", + "nodejs", + "nodejs8.10", + "nodejs10.x", + "dotnetcore1.0", + "dotnetcore2.0", + "dotnetcore2.1", + "ruby2.5", ] + + # AWS Organizations + # organizations_scp_check_deny_regions + # organizations_enabled_regions: [ + # 'eu-central-1', + # 'eu-west-1', + # "us-east-1" + # ] + organizations_enabled_regions: [] + organizations_trusted_delegated_administrators: [] + +# Azure Configuration +azure: + +# GCP Configuration +gcp: + +``` diff --git a/prowler/config/config.py b/prowler/config/config.py index 686983ae..958aa495 100644 --- a/prowler/config/config.py +++ b/prowler/config/config.py @@ -1,5 +1,6 @@ import os import pathlib +import sys from datetime import datetime, timezone from os import getcwd @@ -23,16 +24,23 @@ banner_color = "\033[1;92m" # Compliance actual_directory = pathlib.Path(os.path.dirname(os.path.realpath(__file__))) -available_compliance_frameworks = [] -for provider in ["aws", "gcp"]: - with os.scandir(f"{actual_directory}/../compliance/{provider}") as files: - files = [ - file.name - for file in files - if file.is_file() - and file.name.endswith(".json") - and available_compliance_frameworks.append(file.name.removesuffix(".json")) - ] + + +def get_available_compliance_frameworks(): + available_compliance_frameworks = [] + for provider in ["aws", "gcp", "azure"]: + with os.scandir(f"{actual_directory}/../compliance/{provider}") as files: + for file in files: + if file.is_file() and file.name.endswith(".json"): + available_compliance_frameworks.append( + file.name.removesuffix(".json") + ) + return available_compliance_frameworks + + +available_compliance_frameworks = get_available_compliance_frameworks() + + # AWS services-regions matrix json aws_services_json_file = "aws_regions_by_service.json" @@ -47,7 +55,9 @@ json_file_suffix = ".json" json_asff_file_suffix = ".asff.json" json_ocsf_file_suffix = ".ocsf.json" html_file_suffix = ".html" -config_yaml = f"{pathlib.Path(os.path.dirname(os.path.realpath(__file__)))}/config.yaml" +default_config_file_path = ( + f"{pathlib.Path(os.path.dirname(os.path.realpath(__file__)))}/config.yaml" +) def check_current_version(): @@ -62,29 +72,51 @@ def check_current_version(): else: return f"{prowler_version_string} (it is the latest version, yay!)" except Exception as error: - logger.error(f"{error.__class__.__name__}: {error}") + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}" + ) return f"{prowler_version_string}" -def change_config_var(variable, value): +def change_config_var(variable: str, value: str, audit_info): try: - with open(config_yaml) as f: - doc = yaml.safe_load(f) - - doc[variable] = value - - with open(config_yaml, "w") as f: - yaml.dump(doc, f) + if ( + hasattr(audit_info, "audit_config") + and audit_info.audit_config is not None + and variable in audit_info.audit_config + ): + audit_info.audit_config[variable] = value + return audit_info except Exception as error: - logger.error(f"{error.__class__.__name__}: {error}") + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}" + ) -def get_config_var(variable): +def load_and_validate_config_file(provider: str, config_file_path: str) -> dict: + """ + load_and_validate_config_file reads the Prowler config file in YAML format from the default location or the file passed with the --config-file flag + """ try: - with open(config_yaml) as f: - doc = yaml.safe_load(f) + with open(config_file_path) as f: + config = {} + config_file = yaml.safe_load(f) + + # Not to introduce a breaking change we have to allow the old format config file without any provider keys + # and a new format with a key for each provider to include their configuration values within + # Check if the new format is passed + if "aws" in config_file or "gcp" in config_file or "azure" in config_file: + config = config_file.get(provider, {}) + else: + config = config_file if config_file else {} + # Not to break Azure and GCP does not support neither use the old config format + if provider in ["azure", "gcp"]: + config = {} + + return config - return doc[variable] except Exception as error: - logger.error(f"{error.__class__.__name__}: {error}") - return "" + logger.critical( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}" + ) + sys.exit(1) diff --git a/prowler/config/config.yaml b/prowler/config/config.yaml index 73c8c612..24673100 100644 --- a/prowler/config/config.yaml +++ b/prowler/config/config.yaml @@ -1,57 +1,61 @@ -# AWS EC2 Configuration -# aws.ec2_elastic_ip_shodan -shodan_api_key: null -# aws.ec2_securitygroup_with_many_ingress_egress_rules --> by default is 50 rules -max_security_group_rules: 50 -# aws.ec2_instance_older_than_specific_days --> by default is 6 months (180 days) -max_ec2_instance_age_in_days: 180 +# AWS Configuration +aws: + # AWS EC2 Configuration + # aws.ec2_elastic_ip_shodan + shodan_api_key: null + # aws.ec2_securitygroup_with_many_ingress_egress_rules --> by default is 50 rules + max_security_group_rules: 50 + # aws.ec2_instance_older_than_specific_days --> by default is 6 months (180 days) + max_ec2_instance_age_in_days: 180 -# AWS VPC Configuration (vpc_endpoint_connections_trust_boundaries, vpc_endpoint_services_allowed_principals_trust_boundaries) -# Single account environment: No action required. The AWS account number will be automatically added by the checks. -# Multi account environment: Any additional trusted account number should be added as a space separated list, e.g. -# trusted_account_ids : ["123456789012", "098765432109", "678901234567"] -trusted_account_ids: [] + # AWS VPC Configuration (vpc_endpoint_connections_trust_boundaries, vpc_endpoint_services_allowed_principals_trust_boundaries) + # Single account environment: No action required. The AWS account number will be automatically added by the checks. + # Multi account environment: Any additional trusted account number should be added as a space separated list, e.g. + # trusted_account_ids : ["123456789012", "098765432109", "678901234567"] + trusted_account_ids: [] -# AWS Cloudwatch Configuration -# aws.cloudwatch_log_group_retention_policy_specific_days_enabled --> by default is 365 days -log_group_retention_days: 365 + # AWS Cloudwatch Configuration + # aws.cloudwatch_log_group_retention_policy_specific_days_enabled --> by default is 365 days + log_group_retention_days: 365 -# AWS AppStream Session Configuration -# aws.appstream_fleet_session_idle_disconnect_timeout -max_idle_disconnect_timeout_in_seconds: 600 # 10 Minutes -# aws.appstream_fleet_session_disconnect_timeout -max_disconnect_timeout_in_seconds: 300 # 5 Minutes -# aws.appstream_fleet_maximum_session_duration -max_session_duration_seconds: 36000 # 10 Hours + # AWS AppStream Session Configuration + # aws.appstream_fleet_session_idle_disconnect_timeout + max_idle_disconnect_timeout_in_seconds: 600 # 10 Minutes + # aws.appstream_fleet_session_disconnect_timeout + max_disconnect_timeout_in_seconds: 300 # 5 Minutes + # aws.appstream_fleet_maximum_session_duration + max_session_duration_seconds: 36000 # 10 Hours -# AWS Lambda Configuration -# aws.awslambda_function_using_supported_runtimes -obsolete_lambda_runtimes: - [ - "python3.6", - "python2.7", - "nodejs4.3", - "nodejs4.3-edge", - "nodejs6.10", - "nodejs", - "nodejs8.10", - "nodejs10.x", - "dotnetcore1.0", - "dotnetcore2.0", - "dotnetcore2.1", - "ruby2.5", - ] + # AWS Lambda Configuration + # aws.awslambda_function_using_supported_runtimes + obsolete_lambda_runtimes: + [ + "python3.6", + "python2.7", + "nodejs4.3", + "nodejs4.3-edge", + "nodejs6.10", + "nodejs", + "nodejs8.10", + "nodejs10.x", + "dotnetcore1.0", + "dotnetcore2.0", + "dotnetcore2.1", + "ruby2.5", + ] -# AWS Organizations -# organizations_scp_check_deny_regions -# organizations_enabled_regions: [ -# 'eu-central-1', -# 'eu-west-1', -# "us-east-1" -# ] -organizations_enabled_regions: [] -# organizations_delegated_administrators -# organizations_trusted_delegated_administrators: [ -# "12345678901" -# ] -organizations_trusted_delegated_administrators: [] + # AWS Organizations + # organizations_scp_check_deny_regions + # organizations_enabled_regions: [ + # 'eu-central-1', + # 'eu-west-1', + # "us-east-1" + # ] + organizations_enabled_regions: [] + organizations_trusted_delegated_administrators: [] + +# Azure Configuration +azure: + +# GCP Configuration +gcp: diff --git a/prowler/lib/cli/parser.py b/prowler/lib/cli/parser.py index da08bd38..32022835 100644 --- a/prowler/lib/cli/parser.py +++ b/prowler/lib/cli/parser.py @@ -5,6 +5,7 @@ from argparse import RawTextHelpFormatter from prowler.config.config import ( available_compliance_frameworks, check_current_version, + default_config_file_path, default_output_directory, ) from prowler.providers.aws.aws_provider import get_aws_available_regions @@ -45,6 +46,7 @@ Detailed documentation at https://docs.prowler.cloud self.__init_checks_parser__() self.__init_exclude_checks_parser__() self.__init_list_checks_parser__() + self.__init_config_parser__() # Init Providers Arguments self.__init_aws_parser__() @@ -260,6 +262,15 @@ Detailed documentation at https://docs.prowler.cloud help="List the available check's categories", ) + def __init_config_parser__(self): + config_parser = self.common_providers_parser.add_argument_group("Configuration") + config_parser.add_argument( + "--config-file", + nargs="?", + default=default_config_file_path, + help="Set configuration file path", + ) + def __init_aws_parser__(self): """Init the AWS Provider CLI parser""" aws_parser = self.subparsers.add_parser( diff --git a/prowler/providers/aws/lib/audit_info/audit_info.py b/prowler/providers/aws/lib/audit_info/audit_info.py index 70043ecc..bc1b0c5f 100644 --- a/prowler/providers/aws/lib/audit_info/audit_info.py +++ b/prowler/providers/aws/lib/audit_info/audit_info.py @@ -36,4 +36,5 @@ current_audit_info = AWS_Audit_Info( audited_regions=None, organizations_metadata=None, audit_metadata=None, + audit_config=None, ) diff --git a/prowler/providers/aws/lib/audit_info/models.py b/prowler/providers/aws/lib/audit_info/models.py index b04deddb..e810833b 100644 --- a/prowler/providers/aws/lib/audit_info/models.py +++ b/prowler/providers/aws/lib/audit_info/models.py @@ -51,3 +51,4 @@ class AWS_Audit_Info: audit_resources: list organizations_metadata: AWS_Organizations_Info audit_metadata: Optional[Any] = None + audit_config: Optional[dict] = None diff --git a/prowler/providers/aws/lib/service/service.py b/prowler/providers/aws/lib/service/service.py index f09453d2..fac34057 100644 --- a/prowler/providers/aws/lib/service/service.py +++ b/prowler/providers/aws/lib/service/service.py @@ -22,6 +22,7 @@ class AWSService: self.audited_partition = audit_info.audited_partition self.audit_resources = audit_info.audit_resources self.audited_checks = audit_info.audit_metadata.expected_checks + self.audit_config = audit_info.audit_config # AWS Session self.session = audit_info.audit_session diff --git a/prowler/providers/aws/services/appstream/appstream_fleet_maximum_session_duration/appstream_fleet_maximum_session_duration.py b/prowler/providers/aws/services/appstream/appstream_fleet_maximum_session_duration/appstream_fleet_maximum_session_duration.py index 49bfa96b..990464c8 100644 --- a/prowler/providers/aws/services/appstream/appstream_fleet_maximum_session_duration/appstream_fleet_maximum_session_duration.py +++ b/prowler/providers/aws/services/appstream/appstream_fleet_maximum_session_duration/appstream_fleet_maximum_session_duration.py @@ -1,16 +1,18 @@ -from prowler.config.config import get_config_var from prowler.lib.check.models import Check, Check_Report_AWS from prowler.providers.aws.services.appstream.appstream_client import appstream_client -max_session_duration_seconds = get_config_var("max_session_duration_seconds") -"""max_session_duration_seconds, default: 36000 seconds (10 hours)""" - class appstream_fleet_maximum_session_duration(Check): """Check if there are AppStream Fleets with the user maximum session duration no longer than 10 hours""" def execute(self): """Execute the appstream_fleet_maximum_session_duration check""" + + # max_session_duration_seconds, default: 36000 seconds (10 hours) + max_session_duration_seconds = appstream_client.audit_config.get( + "max_session_duration_seconds", 36000 + ) + findings = [] for fleet in appstream_client.fleets: report = Check_Report_AWS(self.metadata()) diff --git a/prowler/providers/aws/services/appstream/appstream_fleet_session_disconnect_timeout/appstream_fleet_session_disconnect_timeout.py b/prowler/providers/aws/services/appstream/appstream_fleet_session_disconnect_timeout/appstream_fleet_session_disconnect_timeout.py index fa0ff5e6..5cd5fbcb 100644 --- a/prowler/providers/aws/services/appstream/appstream_fleet_session_disconnect_timeout/appstream_fleet_session_disconnect_timeout.py +++ b/prowler/providers/aws/services/appstream/appstream_fleet_session_disconnect_timeout/appstream_fleet_session_disconnect_timeout.py @@ -1,16 +1,18 @@ -from prowler.config.config import get_config_var from prowler.lib.check.models import Check, Check_Report_AWS from prowler.providers.aws.services.appstream.appstream_client import appstream_client -max_disconnect_timeout_in_seconds = get_config_var("max_disconnect_timeout_in_seconds") -"""max_disconnect_timeout_in_seconds, default: 300 seconds (5 minutes)""" - class appstream_fleet_session_disconnect_timeout(Check): """Check if there are AppStream Fleets with the session disconnect timeout set to 5 minutes or less""" def execute(self): """Execute the appstream_fleet_maximum_session_duration check""" + + # max_disconnect_timeout_in_seconds, default: 300 seconds (5 minutes) + max_disconnect_timeout_in_seconds = appstream_client.audit_config.get( + "max_disconnect_timeout_in_seconds", 300 + ) + findings = [] for fleet in appstream_client.fleets: report = Check_Report_AWS(self.metadata()) diff --git a/prowler/providers/aws/services/appstream/appstream_fleet_session_idle_disconnect_timeout/appstream_fleet_session_idle_disconnect_timeout.py b/prowler/providers/aws/services/appstream/appstream_fleet_session_idle_disconnect_timeout/appstream_fleet_session_idle_disconnect_timeout.py index 71e6bef1..0e0cc296 100644 --- a/prowler/providers/aws/services/appstream/appstream_fleet_session_idle_disconnect_timeout/appstream_fleet_session_idle_disconnect_timeout.py +++ b/prowler/providers/aws/services/appstream/appstream_fleet_session_idle_disconnect_timeout/appstream_fleet_session_idle_disconnect_timeout.py @@ -1,18 +1,18 @@ -from prowler.config.config import get_config_var from prowler.lib.check.models import Check, Check_Report_AWS from prowler.providers.aws.services.appstream.appstream_client import appstream_client -max_idle_disconnect_timeout_in_seconds = get_config_var( - "max_idle_disconnect_timeout_in_seconds" -) -"""max_idle_disconnect_timeout_in_seconds, default: 600 seconds (10 minutes)""" - class appstream_fleet_session_idle_disconnect_timeout(Check): """Check if there are AppStream Fleets with the idle disconnect timeout set to 10 minutes or less""" def execute(self): """Execute the appstream_fleet_session_idle_disconnect_timeout check""" + + # max_idle_disconnect_timeout_in_seconds, default: 600 seconds (10 minutes) + max_idle_disconnect_timeout_in_seconds = appstream_client.audit_config.get( + "max_idle_disconnect_timeout_in_seconds", 600 + ) + findings = [] for fleet in appstream_client.fleets: report = Check_Report_AWS(self.metadata()) diff --git a/prowler/providers/aws/services/awslambda/awslambda_function_using_supported_runtimes/awslambda_function_using_supported_runtimes.py b/prowler/providers/aws/services/awslambda/awslambda_function_using_supported_runtimes/awslambda_function_using_supported_runtimes.py index 017bddd2..047f0ecc 100644 --- a/prowler/providers/aws/services/awslambda/awslambda_function_using_supported_runtimes/awslambda_function_using_supported_runtimes.py +++ b/prowler/providers/aws/services/awslambda/awslambda_function_using_supported_runtimes/awslambda_function_using_supported_runtimes.py @@ -1,4 +1,3 @@ -from prowler.config.config import get_config_var from prowler.lib.check.models import Check, Check_Report_AWS from prowler.providers.aws.services.awslambda.awslambda_client import awslambda_client @@ -14,7 +13,9 @@ class awslambda_function_using_supported_runtimes(Check): report.resource_arn = function.arn report.resource_tags = function.tags - if function.runtime in get_config_var("obsolete_lambda_runtimes"): + if function.runtime in awslambda_client.audit_config.get( + "obsolete_lambda_runtimes", [] + ): report.status = "FAIL" report.status_extended = f"Lambda function {function.name} is using {function.runtime} which is obsolete" else: diff --git a/prowler/providers/aws/services/cloudwatch/cloudwatch_log_group_retention_policy_specific_days_enabled/cloudwatch_log_group_retention_policy_specific_days_enabled.py b/prowler/providers/aws/services/cloudwatch/cloudwatch_log_group_retention_policy_specific_days_enabled/cloudwatch_log_group_retention_policy_specific_days_enabled.py index b8fe67ca..564e1f31 100644 --- a/prowler/providers/aws/services/cloudwatch/cloudwatch_log_group_retention_policy_specific_days_enabled/cloudwatch_log_group_retention_policy_specific_days_enabled.py +++ b/prowler/providers/aws/services/cloudwatch/cloudwatch_log_group_retention_policy_specific_days_enabled/cloudwatch_log_group_retention_policy_specific_days_enabled.py @@ -1,4 +1,3 @@ -from prowler.config.config import get_config_var from prowler.lib.check.models import Check, Check_Report_AWS from prowler.providers.aws.services.cloudwatch.logs_client import logs_client @@ -6,7 +5,11 @@ from prowler.providers.aws.services.cloudwatch.logs_client import logs_client class cloudwatch_log_group_retention_policy_specific_days_enabled(Check): def execute(self): findings = [] - specific_retention_days = get_config_var("log_group_retention_days") + + # log_group_retention_days, default: 365 days + specific_retention_days = logs_client.audit_config.get( + "log_group_retention_days", 365 + ) for log_group in logs_client.log_groups: report = Check_Report_AWS(self.metadata()) report.region = log_group.region diff --git a/prowler/providers/aws/services/ec2/ec2_elastic_ip_shodan/ec2_elastic_ip_shodan.py b/prowler/providers/aws/services/ec2/ec2_elastic_ip_shodan/ec2_elastic_ip_shodan.py index 12b48a2e..94df9e5c 100644 --- a/prowler/providers/aws/services/ec2/ec2_elastic_ip_shodan/ec2_elastic_ip_shodan.py +++ b/prowler/providers/aws/services/ec2/ec2_elastic_ip_shodan/ec2_elastic_ip_shodan.py @@ -1,6 +1,5 @@ import shodan -from prowler.config.config import get_config_var from prowler.lib.check.models import Check, Check_Report_AWS from prowler.lib.logger import logger from prowler.providers.aws.services.ec2.ec2_client import ec2_client @@ -9,7 +8,7 @@ from prowler.providers.aws.services.ec2.ec2_client import ec2_client class ec2_elastic_ip_shodan(Check): def execute(self): findings = [] - shodan_api_key = get_config_var("shodan_api_key") + shodan_api_key = ec2_client.audit_config.get("shodan_api_key") if shodan_api_key: api = shodan.Shodan(shodan_api_key) for eip in ec2_client.elastic_ips: diff --git a/prowler/providers/aws/services/ec2/ec2_instance_older_than_specific_days/ec2_instance_older_than_specific_days.py b/prowler/providers/aws/services/ec2/ec2_instance_older_than_specific_days/ec2_instance_older_than_specific_days.py index 049ea4d8..30947ff1 100644 --- a/prowler/providers/aws/services/ec2/ec2_instance_older_than_specific_days/ec2_instance_older_than_specific_days.py +++ b/prowler/providers/aws/services/ec2/ec2_instance_older_than_specific_days/ec2_instance_older_than_specific_days.py @@ -1,6 +1,5 @@ from datetime import datetime, timezone -from prowler.config.config import get_config_var from prowler.lib.check.models import Check, Check_Report_AWS from prowler.providers.aws.services.ec2.ec2_client import ec2_client @@ -8,7 +7,11 @@ from prowler.providers.aws.services.ec2.ec2_client import ec2_client class ec2_instance_older_than_specific_days(Check): def execute(self): findings = [] - max_ec2_instance_age_in_days = get_config_var("max_ec2_instance_age_in_days") + + # max_ec2_instance_age_in_days, default: 180 days + max_ec2_instance_age_in_days = ec2_client.audit_config.get( + "max_ec2_instance_age_in_days", 180 + ) for instance in ec2_client.instances: report = Check_Report_AWS(self.metadata()) report.region = instance.region diff --git a/prowler/providers/aws/services/ec2/ec2_securitygroup_with_many_ingress_egress_rules/ec2_securitygroup_with_many_ingress_egress_rules.py b/prowler/providers/aws/services/ec2/ec2_securitygroup_with_many_ingress_egress_rules/ec2_securitygroup_with_many_ingress_egress_rules.py index a6bab189..45881d64 100644 --- a/prowler/providers/aws/services/ec2/ec2_securitygroup_with_many_ingress_egress_rules/ec2_securitygroup_with_many_ingress_egress_rules.py +++ b/prowler/providers/aws/services/ec2/ec2_securitygroup_with_many_ingress_egress_rules/ec2_securitygroup_with_many_ingress_egress_rules.py @@ -1,4 +1,3 @@ -from prowler.config.config import get_config_var from prowler.lib.check.models import Check, Check_Report_AWS from prowler.providers.aws.services.ec2.ec2_client import ec2_client @@ -6,7 +5,11 @@ from prowler.providers.aws.services.ec2.ec2_client import ec2_client class ec2_securitygroup_with_many_ingress_egress_rules(Check): def execute(self): findings = [] - max_security_group_rules = get_config_var("max_security_group_rules") + + # max_security_group_rules, default: 50 + max_security_group_rules = ec2_client.audit_config.get( + "max_security_group_rules", 50 + ) for security_group in ec2_client.security_groups: report = Check_Report_AWS(self.metadata()) report.region = security_group.region diff --git a/prowler/providers/aws/services/organizations/organizations_delegated_administrators/organizations_delegated_administrators.py b/prowler/providers/aws/services/organizations/organizations_delegated_administrators/organizations_delegated_administrators.py index cac5ee0f..d0e00bad 100644 --- a/prowler/providers/aws/services/organizations/organizations_delegated_administrators/organizations_delegated_administrators.py +++ b/prowler/providers/aws/services/organizations/organizations_delegated_administrators/organizations_delegated_administrators.py @@ -1,4 +1,3 @@ -from prowler.config.config import get_config_var from prowler.lib.check.models import Check, Check_Report_AWS from prowler.providers.aws.services.organizations.organizations_client import ( organizations_client, @@ -8,8 +7,11 @@ from prowler.providers.aws.services.organizations.organizations_client import ( class organizations_delegated_administrators(Check): def execute(self): findings = [] - organizations_trusted_delegated_administrators = get_config_var( - "organizations_trusted_delegated_administrators" + + organizations_trusted_delegated_administrators = ( + organizations_client.audit_config.get( + "organizations_trusted_delegated_administrators", [] + ) ) for org in organizations_client.organizations: diff --git a/prowler/providers/aws/services/organizations/organizations_scp_check_deny_regions/organizations_scp_check_deny_regions.py b/prowler/providers/aws/services/organizations/organizations_scp_check_deny_regions/organizations_scp_check_deny_regions.py index 6962e979..f27073f7 100644 --- a/prowler/providers/aws/services/organizations/organizations_scp_check_deny_regions/organizations_scp_check_deny_regions.py +++ b/prowler/providers/aws/services/organizations/organizations_scp_check_deny_regions/organizations_scp_check_deny_regions.py @@ -1,4 +1,3 @@ -from prowler.config.config import get_config_var from prowler.lib.check.models import Check, Check_Report_AWS from prowler.providers.aws.services.organizations.organizations_client import ( organizations_client, @@ -8,7 +7,9 @@ from prowler.providers.aws.services.organizations.organizations_client import ( class organizations_scp_check_deny_regions(Check): def execute(self): findings = [] - organizations_enabled_regions = get_config_var("organizations_enabled_regions") + organizations_enabled_regions = organizations_client.audit_config.get( + "organizations_enabled_regions", [] + ) for org in organizations_client.organizations: report = Check_Report_AWS(self.metadata()) diff --git a/prowler/providers/aws/services/vpc/vpc_endpoint_connections_trust_boundaries/vpc_endpoint_connections_trust_boundaries.py b/prowler/providers/aws/services/vpc/vpc_endpoint_connections_trust_boundaries/vpc_endpoint_connections_trust_boundaries.py index bf803d1d..6a58b1b8 100644 --- a/prowler/providers/aws/services/vpc/vpc_endpoint_connections_trust_boundaries/vpc_endpoint_connections_trust_boundaries.py +++ b/prowler/providers/aws/services/vpc/vpc_endpoint_connections_trust_boundaries/vpc_endpoint_connections_trust_boundaries.py @@ -1,6 +1,5 @@ from re import compile -from prowler.config.config import get_config_var from prowler.lib.check.models import Check, Check_Report_AWS from prowler.providers.aws.lib.policy_condition_parser.policy_condition_parser import ( is_account_only_allowed_in_condition, @@ -12,7 +11,7 @@ class vpc_endpoint_connections_trust_boundaries(Check): def execute(self): findings = [] # Get trusted account_ids from prowler.config.yaml - trusted_account_ids = get_config_var("trusted_account_ids") + trusted_account_ids = vpc_client.audit_config.get("trusted_account_ids", []) # Always include the same account as trusted trusted_account_ids.append(vpc_client.audited_account) for endpoint in vpc_client.vpc_endpoints: diff --git a/prowler/providers/aws/services/vpc/vpc_endpoint_services_allowed_principals_trust_boundaries/vpc_endpoint_services_allowed_principals_trust_boundaries.py b/prowler/providers/aws/services/vpc/vpc_endpoint_services_allowed_principals_trust_boundaries/vpc_endpoint_services_allowed_principals_trust_boundaries.py index 33526b24..0b69fa55 100644 --- a/prowler/providers/aws/services/vpc/vpc_endpoint_services_allowed_principals_trust_boundaries/vpc_endpoint_services_allowed_principals_trust_boundaries.py +++ b/prowler/providers/aws/services/vpc/vpc_endpoint_services_allowed_principals_trust_boundaries/vpc_endpoint_services_allowed_principals_trust_boundaries.py @@ -1,4 +1,3 @@ -from prowler.config.config import get_config_var from prowler.lib.check.models import Check, Check_Report_AWS from prowler.providers.aws.services.vpc.vpc_client import vpc_client @@ -7,7 +6,7 @@ class vpc_endpoint_services_allowed_principals_trust_boundaries(Check): def execute(self): findings = [] # Get trusted account_ids from prowler.config.yaml - trusted_account_ids = get_config_var("trusted_account_ids") + trusted_account_ids = vpc_client.audit_config.get("trusted_account_ids", []) for service in vpc_client.vpc_endpoint_services: if not service.allowed_principals: report = Check_Report_AWS(self.metadata()) diff --git a/prowler/providers/azure/lib/audit_info/audit_info.py b/prowler/providers/azure/lib/audit_info/audit_info.py index 02f823a5..62144444 100644 --- a/prowler/providers/azure/lib/audit_info/audit_info.py +++ b/prowler/providers/azure/lib/audit_info/audit_info.py @@ -8,4 +8,5 @@ azure_audit_info = Azure_Audit_Info( identity=Azure_Identity_Info(), audit_resources=None, audit_metadata=None, + audit_config=None, ) diff --git a/prowler/providers/azure/lib/audit_info/models.py b/prowler/providers/azure/lib/audit_info/models.py index 7ea45250..dcbe1ade 100644 --- a/prowler/providers/azure/lib/audit_info/models.py +++ b/prowler/providers/azure/lib/audit_info/models.py @@ -19,9 +19,13 @@ class Azure_Audit_Info: identity: Azure_Identity_Info audit_resources: Optional[Any] audit_metadata: Optional[Any] + audit_config: dict - def __init__(self, credentials, identity, audit_metadata, audit_resources): + def __init__( + self, credentials, identity, audit_metadata, audit_resources, audit_config + ): self.credentials = credentials self.identity = identity self.audit_metadata = audit_metadata self.audit_resources = audit_resources + self.audit_config = audit_config diff --git a/prowler/providers/common/audit_info.py b/prowler/providers/common/audit_info.py index 06e6ef87..35b83a91 100644 --- a/prowler/providers/common/audit_info.py +++ b/prowler/providers/common/audit_info.py @@ -3,6 +3,7 @@ import sys from botocore.config import Config from colorama import Fore, Style +from prowler.config.config import load_and_validate_config_file from prowler.lib.logger import logger from prowler.providers.aws.aws_provider import ( AWS_Provider, @@ -351,6 +352,11 @@ def set_provider_audit_info(provider: str, arguments: dict): try: provider_set_audit_info = f"set_{provider}_audit_info" provider_audit_info = getattr(Audit_Info(), provider_set_audit_info)(arguments) + + # Set the audit configuration from the config file + provider_audit_info.audit_config = load_and_validate_config_file( + provider, arguments["config_file"] + ) except Exception as error: logger.critical( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" diff --git a/prowler/providers/common/outputs.py b/prowler/providers/common/outputs.py index 011c510f..e5a4c301 100644 --- a/prowler/providers/common/outputs.py +++ b/prowler/providers/common/outputs.py @@ -100,7 +100,9 @@ class Aws_Output_Options(Provider_Output_Options): # Confire Shodan API if arguments.shodan: - change_config_var("shodan_api_key", arguments.shodan) + audit_info = change_config_var( + "shodan_api_key", arguments.shodan, audit_info + ) # Check if custom output filename was input, if not, set the default if ( diff --git a/prowler/providers/gcp/lib/audit_info/audit_info.py b/prowler/providers/gcp/lib/audit_info/audit_info.py index 82dff5e4..5bc5e878 100644 --- a/prowler/providers/gcp/lib/audit_info/audit_info.py +++ b/prowler/providers/gcp/lib/audit_info/audit_info.py @@ -6,4 +6,5 @@ gcp_audit_info = GCP_Audit_Info( project_ids=[], audit_resources=None, audit_metadata=None, + audit_config=None, ) diff --git a/prowler/providers/gcp/lib/audit_info/models.py b/prowler/providers/gcp/lib/audit_info/models.py index 96ddc2e7..4cb8fcfb 100644 --- a/prowler/providers/gcp/lib/audit_info/models.py +++ b/prowler/providers/gcp/lib/audit_info/models.py @@ -11,6 +11,7 @@ class GCP_Audit_Info: project_ids: list audit_resources: Optional[Any] audit_metadata: Optional[Any] + audit_config: Optional[dict] def __init__( self, @@ -19,9 +20,11 @@ class GCP_Audit_Info: project_ids, audit_metadata, audit_resources, + audit_config, ): self.credentials = credentials self.default_project_id = default_project_id self.project_ids = project_ids self.audit_metadata = audit_metadata self.audit_resources = audit_resources + self.audit_config = audit_config diff --git a/tests/config/config_test.py b/tests/config/config_test.py index 1d79e8f6..ddf8257b 100644 --- a/tests/config/config_test.py +++ b/tests/config/config_test.py @@ -1,9 +1,17 @@ +import os +import pathlib from unittest import mock from requests import Response -from prowler.config.config import check_current_version +from prowler.config.config import ( + change_config_var, + check_current_version, + get_available_compliance_frameworks, + load_and_validate_config_file, +) from prowler.providers.aws.aws_provider import get_aws_available_regions +from prowler.providers.aws.lib.audit_info.models import AWS_Audit_Info MOCK_PROWLER_VERSION = "3.3.0" MOCK_OLD_PROWLER_VERSION = "0.0.0" @@ -16,6 +24,34 @@ def mock_prowler_get_latest_release(_): return response +config_aws = { + "shodan_api_key": None, + "max_security_group_rules": 50, + "max_ec2_instance_age_in_days": 180, + "trusted_account_ids": [], + "log_group_retention_days": 365, + "max_idle_disconnect_timeout_in_seconds": 600, + "max_disconnect_timeout_in_seconds": 300, + "max_session_duration_seconds": 36000, + "obsolete_lambda_runtimes": [ + "python3.6", + "python2.7", + "nodejs4.3", + "nodejs4.3-edge", + "nodejs6.10", + "nodejs", + "nodejs8.10", + "nodejs10.x", + "dotnetcore1.0", + "dotnetcore2.0", + "dotnetcore2.1", + "ruby2.5", + ], + "organizations_enabled_regions": [], + "organizations_trusted_delegated_administrators": [], +} + + class Test_Config: def test_get_aws_available_regions(self): assert len(get_aws_available_regions()) == 32 @@ -39,3 +75,121 @@ class Test_Config: check_current_version() == f"Prowler {MOCK_OLD_PROWLER_VERSION} (latest is {MOCK_PROWLER_VERSION}, upgrade for the latest features)" ) + + def test_change_config_var_aws(self): + audit_info = AWS_Audit_Info( + session_config=None, + original_session=None, + audit_session=None, + audited_account=None, + audited_account_arn=None, + audited_user_id=None, + audited_partition="aws", + audited_identity_arn=None, + profile=None, + profile_region=None, + credentials=None, + assumed_role_info=None, + audited_regions=["us-east-1", "eu-west-1"], + organizations_metadata=None, + audit_resources=None, + mfa_enabled=False, + audit_metadata=None, + audit_config={"shodan_api_key": ""}, + ) + + updated_audit_info = change_config_var("shodan_api_key", "XXXXXX", audit_info) + assert audit_info == updated_audit_info + assert audit_info.audit_config.get( + "shodan_api_key" + ) == updated_audit_info.audit_config.get("shodan_api_key") + + def test_change_config_var_aws_not_present(self): + audit_info = AWS_Audit_Info( + session_config=None, + original_session=None, + audit_session=None, + audited_account=None, + audited_account_arn=None, + audited_user_id=None, + audited_partition="aws", + audited_identity_arn=None, + profile=None, + profile_region=None, + credentials=None, + assumed_role_info=None, + audited_regions=["us-east-1", "eu-west-1"], + organizations_metadata=None, + audit_resources=None, + mfa_enabled=False, + audit_metadata=None, + audit_config={}, + ) + + updated_audit_info = change_config_var("not_found", "no_value", audit_info) + assert audit_info == updated_audit_info + assert updated_audit_info.audit_config.get("not_found") is None + + # Test load_and_validate_config_file + + def test_get_available_compliance_frameworks(self): + compliance_frameworks = [ + "cisa_aws", + "soc2_aws", + "cis_1.4_aws", + "cis_1.5_aws", + "mitre_attack_aws", + "gdpr_aws", + "aws_foundational_security_best_practices_aws", + "iso27001_2013_aws", + "hipaa_aws", + "cis_2.0_aws", + "gxp_21_cfr_part_11_aws", + "aws_well_architected_framework_security_pillar_aws", + "gxp_eu_annex_11_aws", + "nist_800_171_revision_2_aws", + "nist_800_53_revision_4_aws", + "nist_800_53_revision_5_aws", + "ens_rd2022_aws", + "nist_csf_1.1_aws", + "aws_well_architected_framework_reliability_pillar_aws", + "aws_audit_manager_control_tower_guardrails_aws", + "rbi_cyber_security_framework_aws", + "ffiec_aws", + "pci_3.2.1_aws", + "fedramp_moderate_revision_4_aws", + "fedramp_low_revision_4_aws", + "cis_2.0_gcp", + ] + assert ( + get_available_compliance_frameworks().sort() == compliance_frameworks.sort() + ) + + def test_load_and_validate_config_file_aws(self): + path = pathlib.Path(os.path.dirname(os.path.realpath(__file__))) + config_test_file = f"{path}/fixtures/config.yaml" + provider = "aws" + + assert load_and_validate_config_file(provider, config_test_file) == config_aws + + def test_load_and_validate_config_file_gcp(self): + path = pathlib.Path(os.path.dirname(os.path.realpath(__file__))) + config_test_file = f"{path}/fixtures/config.yaml" + provider = "gcp" + + assert load_and_validate_config_file(provider, config_test_file) is None + + def test_load_and_validate_config_file_azure(self): + path = pathlib.Path(os.path.dirname(os.path.realpath(__file__))) + config_test_file = f"{path}/fixtures/config.yaml" + provider = "azure" + + assert load_and_validate_config_file(provider, config_test_file) is None + + def test_load_and_validate_config_file_old_format(self): + path = pathlib.Path(os.path.dirname(os.path.realpath(__file__))) + config_test_file = f"{path}/fixtures/config_old.yaml" + + assert load_and_validate_config_file("aws", config_test_file) == config_aws + assert load_and_validate_config_file("gcp", config_test_file) == {} + assert load_and_validate_config_file("azure", config_test_file) == {} diff --git a/tests/config/fixtures/config.yaml b/tests/config/fixtures/config.yaml new file mode 100644 index 00000000..24673100 --- /dev/null +++ b/tests/config/fixtures/config.yaml @@ -0,0 +1,61 @@ +# AWS Configuration +aws: + # AWS EC2 Configuration + # aws.ec2_elastic_ip_shodan + shodan_api_key: null + # aws.ec2_securitygroup_with_many_ingress_egress_rules --> by default is 50 rules + max_security_group_rules: 50 + # aws.ec2_instance_older_than_specific_days --> by default is 6 months (180 days) + max_ec2_instance_age_in_days: 180 + + # AWS VPC Configuration (vpc_endpoint_connections_trust_boundaries, vpc_endpoint_services_allowed_principals_trust_boundaries) + # Single account environment: No action required. The AWS account number will be automatically added by the checks. + # Multi account environment: Any additional trusted account number should be added as a space separated list, e.g. + # trusted_account_ids : ["123456789012", "098765432109", "678901234567"] + trusted_account_ids: [] + + # AWS Cloudwatch Configuration + # aws.cloudwatch_log_group_retention_policy_specific_days_enabled --> by default is 365 days + log_group_retention_days: 365 + + # AWS AppStream Session Configuration + # aws.appstream_fleet_session_idle_disconnect_timeout + max_idle_disconnect_timeout_in_seconds: 600 # 10 Minutes + # aws.appstream_fleet_session_disconnect_timeout + max_disconnect_timeout_in_seconds: 300 # 5 Minutes + # aws.appstream_fleet_maximum_session_duration + max_session_duration_seconds: 36000 # 10 Hours + + # AWS Lambda Configuration + # aws.awslambda_function_using_supported_runtimes + obsolete_lambda_runtimes: + [ + "python3.6", + "python2.7", + "nodejs4.3", + "nodejs4.3-edge", + "nodejs6.10", + "nodejs", + "nodejs8.10", + "nodejs10.x", + "dotnetcore1.0", + "dotnetcore2.0", + "dotnetcore2.1", + "ruby2.5", + ] + + # AWS Organizations + # organizations_scp_check_deny_regions + # organizations_enabled_regions: [ + # 'eu-central-1', + # 'eu-west-1', + # "us-east-1" + # ] + organizations_enabled_regions: [] + organizations_trusted_delegated_administrators: [] + +# Azure Configuration +azure: + +# GCP Configuration +gcp: diff --git a/tests/config/fixtures/config_old.yaml b/tests/config/fixtures/config_old.yaml new file mode 100644 index 00000000..8b1fbac8 --- /dev/null +++ b/tests/config/fixtures/config_old.yaml @@ -0,0 +1,53 @@ +# AWS EC2 Configuration +# aws.ec2_elastic_ip_shodan +shodan_api_key: null +# aws.ec2_securitygroup_with_many_ingress_egress_rules --> by default is 50 rules +max_security_group_rules: 50 +# aws.ec2_instance_older_than_specific_days --> by default is 6 months (180 days) +max_ec2_instance_age_in_days: 180 + +# AWS VPC Configuration (vpc_endpoint_connections_trust_boundaries, vpc_endpoint_services_allowed_principals_trust_boundaries) +# Single account environment: No action required. The AWS account number will be automatically added by the checks. +# Multi account environment: Any additional trusted account number should be added as a space separated list, e.g. +# trusted_account_ids : ["123456789012", "098765432109", "678901234567"] +trusted_account_ids: [] + +# AWS Cloudwatch Configuration +# aws.cloudwatch_log_group_retention_policy_specific_days_enabled --> by default is 365 days +log_group_retention_days: 365 + +# AWS AppStream Session Configuration +# aws.appstream_fleet_session_idle_disconnect_timeout +max_idle_disconnect_timeout_in_seconds: 600 # 10 Minutes +# aws.appstream_fleet_session_disconnect_timeout +max_disconnect_timeout_in_seconds: 300 # 5 Minutes +# aws.appstream_fleet_maximum_session_duration +max_session_duration_seconds: 36000 # 10 Hours + +# AWS Lambda Configuration +# aws.awslambda_function_using_supported_runtimes +obsolete_lambda_runtimes: + [ + "python3.6", + "python2.7", + "nodejs4.3", + "nodejs4.3-edge", + "nodejs6.10", + "nodejs", + "nodejs8.10", + "nodejs10.x", + "dotnetcore1.0", + "dotnetcore2.0", + "dotnetcore2.1", + "ruby2.5", + ] + +# AWS Organizations +# organizations_scp_check_deny_regions +# organizations_enabled_regions: [ +# 'eu-central-1', +# 'eu-west-1', +# "us-east-1" +# ] +organizations_enabled_regions: [] +organizations_trusted_delegated_administrators: [] diff --git a/tests/lib/cli/parser_test.py b/tests/lib/cli/parser_test.py index b3f45659..3894a0ca 100644 --- a/tests/lib/cli/parser_test.py +++ b/tests/lib/cli/parser_test.py @@ -916,6 +916,20 @@ class Test_Parser: parsed = self.parser.parse(command) assert parsed.aws_retries_max_attempts == int(max_retries) + def test_aws_parser_config_file(self): + argument = "--config-file" + config_file = "./test-config.yaml" + command = [prowler_command, argument, config_file] + parsed = self.parser.parse(command) + assert parsed.config_file == config_file + + def test_aws_parser_sts_endpoint_region(self): + argument = "--sts-endpoint-region" + sts_endpoint_region = "eu-west-1" + command = [prowler_command, argument, sts_endpoint_region] + parsed = self.parser.parse(command) + assert parsed.sts_endpoint_region == sts_endpoint_region + def test_parser_azure_auth_sp(self): argument = "--sp-env-auth" command = [prowler_command, "azure", argument] diff --git a/tests/lib/outputs/slack_test.py b/tests/lib/outputs/slack_test.py index baf66c93..b6609356 100644 --- a/tests/lib/outputs/slack_test.py +++ b/tests/lib/outputs/slack_test.py @@ -51,6 +51,7 @@ class Test_Slack_Integration: completed_checks=0, audit_progress=0, ), + audit_config=None, ) gcp_audit_info = GCP_Audit_Info( credentials=None, @@ -58,6 +59,7 @@ class Test_Slack_Integration: project_ids=["test-project1", "test-project2"], audit_resources=None, audit_metadata=None, + audit_config=None, ) azure_audit_info = Azure_Audit_Info( credentials=None, @@ -73,6 +75,7 @@ class Test_Slack_Integration: ), audit_resources=None, audit_metadata=None, + audit_config=None, ) assert create_message_identity("aws", aws_audit_info) == ( f"AWS Account *{aws_audit_info.audited_account}*", diff --git a/tests/providers/aws/services/appstream/appstream_fleet_maximum_session_duration/appstream_fleet_maximum_session_duration_test.py b/tests/providers/aws/services/appstream/appstream_fleet_maximum_session_duration/appstream_fleet_maximum_session_duration_test.py index 9901d804..dca94fbb 100644 --- a/tests/providers/aws/services/appstream/appstream_fleet_maximum_session_duration/appstream_fleet_maximum_session_duration_test.py +++ b/tests/providers/aws/services/appstream/appstream_fleet_maximum_session_duration/appstream_fleet_maximum_session_duration_test.py @@ -40,6 +40,8 @@ class Test_appstream_fleet_maximum_session_duration: appstream_client.fleets.append(fleet1) + appstream_client.audit_config = {"max_session_duration_seconds": 36000} + with mock.patch( "prowler.providers.aws.services.appstream.appstream_service.AppStream", new=appstream_client, @@ -78,6 +80,8 @@ class Test_appstream_fleet_maximum_session_duration: appstream_client.fleets.append(fleet1) + appstream_client.audit_config = {"max_session_duration_seconds": 36000} + with mock.patch( "prowler.providers.aws.services.appstream.appstream_service.AppStream", new=appstream_client, @@ -129,6 +133,8 @@ class Test_appstream_fleet_maximum_session_duration: appstream_client.fleets.append(fleet1) appstream_client.fleets.append(fleet2) + appstream_client.audit_config = {"max_session_duration_seconds": 36000} + with mock.patch( "prowler.providers.aws.services.appstream.appstream_service.AppStream", new=appstream_client, diff --git a/tests/providers/aws/services/appstream/appstream_fleet_session_disconnect_timeout/appstream_fleet_session_disconnect_timeout_test.py b/tests/providers/aws/services/appstream/appstream_fleet_session_disconnect_timeout/appstream_fleet_session_disconnect_timeout_test.py index b380e592..19b4bc4d 100644 --- a/tests/providers/aws/services/appstream/appstream_fleet_session_disconnect_timeout/appstream_fleet_session_disconnect_timeout_test.py +++ b/tests/providers/aws/services/appstream/appstream_fleet_session_disconnect_timeout/appstream_fleet_session_disconnect_timeout_test.py @@ -39,6 +39,7 @@ class Test_appstream_fleet_session_disconnect_timeout: ) appstream_client.fleets.append(fleet1) + appstream_client.audit_config = {"max_disconnect_timeout_in_seconds": 300} with mock.patch( "prowler.providers.aws.services.appstream.appstream_service.AppStream", @@ -78,6 +79,8 @@ class Test_appstream_fleet_session_disconnect_timeout: appstream_client.fleets.append(fleet1) + appstream_client.audit_config = {"max_disconnect_timeout_in_seconds": 300} + with mock.patch( "prowler.providers.aws.services.appstream.appstream_service.AppStream", new=appstream_client, @@ -129,6 +132,8 @@ class Test_appstream_fleet_session_disconnect_timeout: appstream_client.fleets.append(fleet1) appstream_client.fleets.append(fleet2) + appstream_client.audit_config = {"max_disconnect_timeout_in_seconds": 300} + with mock.patch( "prowler.providers.aws.services.appstream.appstream_service.AppStream", new=appstream_client, diff --git a/tests/providers/aws/services/appstream/appstream_fleet_session_idle_disconnect_timeout/appstream_fleet_session_idle_disconnect_timeout_test.py b/tests/providers/aws/services/appstream/appstream_fleet_session_idle_disconnect_timeout/appstream_fleet_session_idle_disconnect_timeout_test.py index a96b193e..d74f2f3f 100644 --- a/tests/providers/aws/services/appstream/appstream_fleet_session_idle_disconnect_timeout/appstream_fleet_session_idle_disconnect_timeout_test.py +++ b/tests/providers/aws/services/appstream/appstream_fleet_session_idle_disconnect_timeout/appstream_fleet_session_idle_disconnect_timeout_test.py @@ -40,6 +40,8 @@ class Test_appstream_fleet_session_idle_disconnect_timeout: appstream_client.fleets.append(fleet1) + appstream_client.audit_config = {"max_idle_disconnect_timeout_in_seconds": 300} + with mock.patch( "prowler.providers.aws.services.appstream.appstream_service.AppStream", new=appstream_client, @@ -78,6 +80,8 @@ class Test_appstream_fleet_session_idle_disconnect_timeout: appstream_client.fleets.append(fleet1) + appstream_client.audit_config = {"max_idle_disconnect_timeout_in_seconds": 600} + with mock.patch( "prowler.providers.aws.services.appstream.appstream_service.AppStream", new=appstream_client, @@ -129,6 +133,8 @@ class Test_appstream_fleet_session_idle_disconnect_timeout: appstream_client.fleets.append(fleet1) appstream_client.fleets.append(fleet2) + appstream_client.audit_config = {"max_idle_disconnect_timeout_in_seconds": 300} + with mock.patch( "prowler.providers.aws.services.appstream.appstream_service.AppStream", new=appstream_client, diff --git a/tests/providers/aws/services/awslambda/awslambda_function_using_supported_runtimes/awslambda_function_using_supported_runtimes_test.py b/tests/providers/aws/services/awslambda/awslambda_function_using_supported_runtimes/awslambda_function_using_supported_runtimes_test.py index 31d6cae2..9eb87215 100644 --- a/tests/providers/aws/services/awslambda/awslambda_function_using_supported_runtimes/awslambda_function_using_supported_runtimes_test.py +++ b/tests/providers/aws/services/awslambda/awslambda_function_using_supported_runtimes/awslambda_function_using_supported_runtimes_test.py @@ -7,23 +7,6 @@ from prowler.providers.aws.services.awslambda.awslambda_service import Function AWS_REGION = "us-east-1" -def mock_get_config_var(config_var: str): - return [ - "python3.6", - "python2.7", - "nodejs4.3", - "nodejs4.3-edge", - "nodejs6.10", - "nodejs", - "nodejs8.10", - "nodejs10.x", - "dotnetcore1.0", - "dotnetcore2.0", - "dotnetcore2.1", - "ruby2.5", - ] - - class Test_awslambda_function_using_supported_runtimes: def test_no_functions(self): lambda_client = mock.MagicMock @@ -59,12 +42,27 @@ class Test_awslambda_function_using_supported_runtimes: ) } + # Mock config + lambda_client.audit_config = { + "obsolete_lambda_runtimes": [ + "python3.6", + "python2.7", + "nodejs4.3", + "nodejs4.3-edge", + "nodejs6.10", + "nodejs", + "nodejs8.10", + "nodejs10.x", + "dotnetcore1.0", + "dotnetcore2.0", + "dotnetcore2.1", + "ruby2.5", + ] + } + with mock.patch( "prowler.providers.aws.services.awslambda.awslambda_service.Lambda", new=lambda_client, - ), mock.patch( - "prowler.providers.aws.services.awslambda.awslambda_function_using_supported_runtimes.awslambda_function_using_supported_runtimes.get_config_var", - new=mock_get_config_var, ): # Test Check from prowler.providers.aws.services.awslambda.awslambda_function_using_supported_runtimes.awslambda_function_using_supported_runtimes import ( @@ -100,12 +98,27 @@ class Test_awslambda_function_using_supported_runtimes: ) } + # Mock config + lambda_client.audit_config = { + "obsolete_lambda_runtimes": [ + "python3.6", + "python2.7", + "nodejs4.3", + "nodejs4.3-edge", + "nodejs6.10", + "nodejs", + "nodejs8.10", + "nodejs10.x", + "dotnetcore1.0", + "dotnetcore2.0", + "dotnetcore2.1", + "ruby2.5", + ] + } + with mock.patch( "prowler.providers.aws.services.awslambda.awslambda_service.Lambda", new=lambda_client, - ), mock.patch( - "prowler.providers.aws.services.awslambda.awslambda_function_using_supported_runtimes.awslambda_function_using_supported_runtimes.get_config_var", - new=mock_get_config_var, ): # Test Check from prowler.providers.aws.services.awslambda.awslambda_function_using_supported_runtimes.awslambda_function_using_supported_runtimes import ( @@ -137,12 +150,27 @@ class Test_awslambda_function_using_supported_runtimes: ) } + # Mock config + lambda_client.audit_config = { + "obsolete_lambda_runtimes": [ + "python3.6", + "python2.7", + "nodejs4.3", + "nodejs4.3-edge", + "nodejs6.10", + "nodejs", + "nodejs8.10", + "nodejs10.x", + "dotnetcore1.0", + "dotnetcore2.0", + "dotnetcore2.1", + "ruby2.5", + ] + } + with mock.patch( "prowler.providers.aws.services.awslambda.awslambda_service.Lambda", new=lambda_client, - ), mock.patch( - "prowler.providers.aws.services.awslambda.awslambda_function_using_supported_runtimes.awslambda_function_using_supported_runtimes.get_config_var", - new=mock_get_config_var, ): # Test Check from prowler.providers.aws.services.awslambda.awslambda_function_using_supported_runtimes.awslambda_function_using_supported_runtimes import ( diff --git a/tests/providers/aws/services/cloudwatch/cloudwatch_log_group_retention_policy_specific_days_enabled/cloudwatch_log_group_retention_policy_specific_days_enabled_test.py b/tests/providers/aws/services/cloudwatch/cloudwatch_log_group_retention_policy_specific_days_enabled/cloudwatch_log_group_retention_policy_specific_days_enabled_test.py index 80e6876a..17aaac34 100644 --- a/tests/providers/aws/services/cloudwatch/cloudwatch_log_group_retention_policy_specific_days_enabled/cloudwatch_log_group_retention_policy_specific_days_enabled_test.py +++ b/tests/providers/aws/services/cloudwatch/cloudwatch_log_group_retention_policy_specific_days_enabled/cloudwatch_log_group_retention_policy_specific_days_enabled_test.py @@ -46,6 +46,7 @@ class Test_cloudwatch_log_group_retention_policy_specific_days_enabled: from prowler.providers.aws.services.cloudwatch.cloudwatch_service import Logs current_audit_info = self.set_mocked_audit_info() + current_audit_info.audit_config = {"log_group_retention_days": 365} from prowler.providers.common.models import Audit_Metadata @@ -85,6 +86,7 @@ class Test_cloudwatch_log_group_retention_policy_specific_days_enabled: from prowler.providers.aws.services.cloudwatch.cloudwatch_service import Logs current_audit_info = self.set_mocked_audit_info() + current_audit_info.audit_config = {"log_group_retention_days": 365} from prowler.providers.common.models import Audit_Metadata @@ -136,6 +138,7 @@ class Test_cloudwatch_log_group_retention_policy_specific_days_enabled: from prowler.providers.aws.services.cloudwatch.cloudwatch_service import Logs current_audit_info = self.set_mocked_audit_info() + current_audit_info.audit_config = {"log_group_retention_days": 365} from prowler.providers.common.models import Audit_Metadata @@ -187,6 +190,7 @@ class Test_cloudwatch_log_group_retention_policy_specific_days_enabled: from prowler.providers.aws.services.cloudwatch.cloudwatch_service import Logs current_audit_info = self.set_mocked_audit_info() + current_audit_info.audit_config = {"log_group_retention_days": 365} from prowler.providers.common.models import Audit_Metadata diff --git a/tests/providers/aws/services/ec2/ec2_elastic_ip_shodan/ec2_elastic_ip_shodan_test.py b/tests/providers/aws/services/ec2/ec2_elastic_ip_shodan/ec2_elastic_ip_shodan_test.py index 9645ff03..143a75a3 100644 --- a/tests/providers/aws/services/ec2/ec2_elastic_ip_shodan/ec2_elastic_ip_shodan_test.py +++ b/tests/providers/aws/services/ec2/ec2_elastic_ip_shodan/ec2_elastic_ip_shodan_test.py @@ -3,13 +3,12 @@ from unittest import mock from boto3 import client, session from moto import mock_ec2 -from prowler.config.config import get_config_var from prowler.providers.aws.lib.audit_info.models import AWS_Audit_Info from prowler.providers.common.models import Audit_Metadata EXAMPLE_AMI_ID = "ami-12c6146b" -shodan_api_key = get_config_var("shodan_api_key") AWS_ACCOUNT_NUMBER = "123456789012" +AWS_REGION = "eu-west-1" class Test_ec2_elastic_ip_shodan: @@ -40,99 +39,156 @@ class Test_ec2_elastic_ip_shodan: completed_checks=0, audit_progress=0, ), + audit_config={"shodan_api_key": ""}, ) return audit_info - if shodan_api_key: + @mock_ec2 + def test_ec2_one_instances_no_public_ip(self): + # Create EC2 Mocked Resources + ec2_client = client("ec2", AWS_REGION) + # Create EC2 Instance + ec2_client.run_instances(ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1) - @mock_ec2 - def test_ec2_one_instances_no_public_ip(self): - # Create EC2 Mocked Resources - ec2_client = client("ec2") - # Create EC2 Instance - ec2_client.run_instances(ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1) + from prowler.providers.aws.services.ec2.ec2_service import EC2 - from prowler.providers.aws.services.ec2.ec2_service import EC2 + current_audit_info = self.set_mocked_audit_info() - current_audit_info = self.set_mocked_audit_info() - - with mock.patch( - "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", - new=current_audit_info, - ), mock.patch( - "prowler.providers.aws.services.ec2.ec2_elastic_ip_shodan.ec2_elastic_ip_shodan.ec2_client", - new=EC2(current_audit_info), - ): - # Test Check - from prowler.providers.aws.services.ec2.ec2_elastic_ip_shodan.ec2_elastic_ip_shodan import ( - ec2_elastic_ip_shodan, - ) - - check = ec2_elastic_ip_shodan() - result = check.execute() - - assert len(result) == 0 - - @mock_ec2 - def test_ec2_one_unattached_eip(self): - # Create EC2 Mocked Resources - ec2_client = client("ec2") - # Create EC2 Instance - ec2_client.allocate_address(Domain="vpc") - - from prowler.providers.aws.services.ec2.ec2_service import EC2 - - current_audit_info = self.set_mocked_audit_info() - - with mock.patch( - "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", - new=current_audit_info, - ), mock.patch( - "prowler.providers.aws.services.ec2.ec2_elastic_ip_shodan.ec2_elastic_ip_shodan.ec2_client", - new=EC2(current_audit_info), - ): - # Test Check - from prowler.providers.aws.services.ec2.ec2_elastic_ip_shodan.ec2_elastic_ip_shodan import ( - ec2_elastic_ip_shodan, - ) - - check = ec2_elastic_ip_shodan() - result = check.execute() - - assert len(result) == 0 - - @mock_ec2 - def test_ec2_one_attached_eip(self): - # Create EC2 Mocked Resources - ec2_client = client("ec2") - # Create EC2 Instance - instance = ec2_client.run_instances( - ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 - ) - allocation = ec2_client.allocate_address(Domain="vpc") - ec2_client.associate_address( - AllocationId=allocation["AllocationId"], - InstanceId=instance["Instances"][0]["InstanceId"], + with mock.patch( + "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", + new=current_audit_info, + ), mock.patch( + "prowler.providers.aws.services.ec2.ec2_elastic_ip_shodan.ec2_elastic_ip_shodan.ec2_client", + new=EC2(current_audit_info), + ): + # Test Check + from prowler.providers.aws.services.ec2.ec2_elastic_ip_shodan.ec2_elastic_ip_shodan import ( + ec2_elastic_ip_shodan, ) - from prowler.providers.aws.services.ec2.ec2_service import EC2 + check = ec2_elastic_ip_shodan() + result = check.execute() - current_audit_info = self.set_mocked_audit_info() + assert len(result) == 0 - with mock.patch( - "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", - new=current_audit_info, - ), mock.patch( - "prowler.providers.aws.services.ec2.ec2_elastic_ip_shodan.ec2_elastic_ip_shodan.ec2_client", - new=EC2(current_audit_info), - ): - # Test Check - from prowler.providers.aws.services.ec2.ec2_elastic_ip_shodan.ec2_elastic_ip_shodan import ( - ec2_elastic_ip_shodan, - ) + @mock_ec2 + def test_ec2_one_unattached_eip(self): + # Create EC2 Mocked Resources + ec2_client = client("ec2", AWS_REGION) + # Create EC2 Instance + ec2_client.allocate_address(Domain="vpc") - check = ec2_elastic_ip_shodan() - result = check.execute() + from prowler.providers.aws.services.ec2.ec2_service import EC2 - assert len(result) == 1 + current_audit_info = self.set_mocked_audit_info() + + with mock.patch( + "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", + new=current_audit_info, + ), mock.patch( + "prowler.providers.aws.services.ec2.ec2_elastic_ip_shodan.ec2_elastic_ip_shodan.ec2_client", + new=EC2(current_audit_info), + ): + # Test Check + from prowler.providers.aws.services.ec2.ec2_elastic_ip_shodan.ec2_elastic_ip_shodan import ( + ec2_elastic_ip_shodan, + ) + + check = ec2_elastic_ip_shodan() + result = check.execute() + + assert len(result) == 0 + + @mock_ec2 + def test_ec2_one_attached_eip_no_shodan_api_key(self): + # Create EC2 Mocked Resources + ec2_client = client("ec2", AWS_REGION) + # Create EC2 Instance + instance = ec2_client.run_instances( + ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 + ) + allocation = ec2_client.allocate_address(Domain="vpc") + ec2_client.associate_address( + AllocationId=allocation["AllocationId"], + InstanceId=instance["Instances"][0]["InstanceId"], + ) + + from prowler.providers.aws.services.ec2.ec2_service import EC2 + + current_audit_info = self.set_mocked_audit_info() + + with mock.patch( + "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", + new=current_audit_info, + ), mock.patch( + "prowler.providers.aws.services.ec2.ec2_elastic_ip_shodan.ec2_elastic_ip_shodan.ec2_client", + new=EC2(current_audit_info), + ): + # Test Check + from prowler.providers.aws.services.ec2.ec2_elastic_ip_shodan.ec2_elastic_ip_shodan import ( + ec2_elastic_ip_shodan, + ) + + check = ec2_elastic_ip_shodan() + result = check.execute() + + assert len(result) == 0 + + @mock_ec2 + def test_ec2_one_attached_eip_shodan_api_key(self): + # Create EC2 Mocked Resources + ec2_client = client("ec2", AWS_REGION) + # Create EC2 Instance + instance = ec2_client.run_instances( + ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1 + ) + allocation = ec2_client.allocate_address(Domain="vpc") + public_ip = allocation["PublicIp"] + allocation_id = allocation["AllocationId"] + + ec2_client.associate_address( + AllocationId=allocation["AllocationId"], + InstanceId=instance["Instances"][0]["InstanceId"], + ) + + from prowler.providers.aws.services.ec2.ec2_service import EC2 + + current_audit_info = self.set_mocked_audit_info() + current_audit_info.audit_config = {"shodan_api_key": "XXXXXXX"} + + ports = ["22", "443"] + isp = "test-isp" + country = "france" + + with mock.patch( + "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", + new=current_audit_info, + ), mock.patch( + "prowler.providers.aws.services.ec2.ec2_elastic_ip_shodan.ec2_elastic_ip_shodan.ec2_client", + new=EC2(current_audit_info), + ), mock.patch( + "prowler.providers.aws.services.ec2.ec2_elastic_ip_shodan.ec2_elastic_ip_shodan.shodan.Shodan.host", + return_value={"ports": ports, "isp": isp, "country_name": country}, + ): + # Test Check + from prowler.providers.aws.services.ec2.ec2_elastic_ip_shodan.ec2_elastic_ip_shodan import ( + ec2_elastic_ip_shodan, + ) + + check = ec2_elastic_ip_shodan() + result = check.execute() + + assert len(result) == 1 + assert result[0].resource_id == public_ip + assert ( + result[0].resource_arn + == f"arn:aws:ec2:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:eip-allocation/{allocation_id}" + ) + assert result[0].region == AWS_REGION + assert result[0].resource_tags == [] + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Elastic IP {public_ip} listed in Shodan with open ports {str(ports)} and ISP {isp} in {country}. More info https://www.shodan.io/host/{public_ip}" + ) diff --git a/tests/providers/aws/services/ec2/ec2_instance_older_than_specific_days/ec2_instance_older_than_specific_days_test.py b/tests/providers/aws/services/ec2/ec2_instance_older_than_specific_days/ec2_instance_older_than_specific_days_test.py index 6c7d3571..4ee8f1d2 100644 --- a/tests/providers/aws/services/ec2/ec2_instance_older_than_specific_days/ec2_instance_older_than_specific_days_test.py +++ b/tests/providers/aws/services/ec2/ec2_instance_older_than_specific_days/ec2_instance_older_than_specific_days_test.py @@ -51,6 +51,7 @@ class Test_ec2_instance_older_than_specific_days: from prowler.providers.aws.services.ec2.ec2_service import EC2 current_audit_info = self.set_mocked_audit_info() + current_audit_info.audit_config = {"max_ec2_instance_age_in_days": 180} with mock.patch( "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", @@ -82,6 +83,7 @@ class Test_ec2_instance_older_than_specific_days: from prowler.providers.aws.services.ec2.ec2_service import EC2 current_audit_info = self.set_mocked_audit_info() + current_audit_info.audit_config = {"max_ec2_instance_age_in_days": 180} with mock.patch( "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", @@ -121,6 +123,7 @@ class Test_ec2_instance_older_than_specific_days: from prowler.providers.aws.services.ec2.ec2_service import EC2 current_audit_info = self.set_mocked_audit_info() + current_audit_info.audit_config = {"max_ec2_instance_age_in_days": 180} with mock.patch( "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", diff --git a/tests/providers/aws/services/ec2/ec2_securitygroup_with_many_ingress_egress_rules/ec2_securitygroup_with_many_ingress_egress_rules_test.py b/tests/providers/aws/services/ec2/ec2_securitygroup_with_many_ingress_egress_rules/ec2_securitygroup_with_many_ingress_egress_rules_test.py index b2ab55ab..f61c5c56 100644 --- a/tests/providers/aws/services/ec2/ec2_securitygroup_with_many_ingress_egress_rules/ec2_securitygroup_with_many_ingress_egress_rules_test.py +++ b/tests/providers/aws/services/ec2/ec2_securitygroup_with_many_ingress_egress_rules/ec2_securitygroup_with_many_ingress_egress_rules_test.py @@ -52,6 +52,7 @@ class Test_ec2_securitygroup_with_many_ingress_egress_rules: from prowler.providers.aws.services.ec2.ec2_service import EC2 current_audit_info = self.set_mocked_audit_info() + current_audit_info.audit_config = {"max_security_group_rules": 50} with mock.patch( "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", @@ -101,6 +102,7 @@ class Test_ec2_securitygroup_with_many_ingress_egress_rules: from prowler.providers.aws.services.ec2.ec2_service import EC2 current_audit_info = self.set_mocked_audit_info() + current_audit_info.audit_config = {"max_security_group_rules": 50} with mock.patch( "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", @@ -158,6 +160,7 @@ class Test_ec2_securitygroup_with_many_ingress_egress_rules: from prowler.providers.aws.services.ec2.ec2_service import EC2 current_audit_info = self.set_mocked_audit_info() + current_audit_info.audit_config = {"max_security_group_rules": 50} with mock.patch( "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", diff --git a/tests/providers/aws/services/organizations/organizations_delegated_administrators/organizations_delegated_administrators_test.py b/tests/providers/aws/services/organizations/organizations_delegated_administrators/organizations_delegated_administrators_test.py index dc4fe9ba..d255dd3f 100644 --- a/tests/providers/aws/services/organizations/organizations_delegated_administrators/organizations_delegated_administrators_test.py +++ b/tests/providers/aws/services/organizations/organizations_delegated_administrators/organizations_delegated_administrators_test.py @@ -48,7 +48,7 @@ class Test_organizations_delegated_administrators: @mock_organizations def test_no_organization(self): audit_info = self.set_mocked_audit_info() - + audit_info.audit_config = {"organizations_trusted_delegated_administrators": []} with mock.patch( "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", new=audit_info, @@ -70,6 +70,7 @@ class Test_organizations_delegated_administrators: @mock_organizations def test_organization_no_delegations(self): audit_info = self.set_mocked_audit_info() + audit_info.audit_config = {"organizations_trusted_delegated_administrators": []} # Create Organization conn = client("organizations", region_name=AWS_REGION) @@ -119,6 +120,13 @@ class Test_organizations_delegated_administrators: ServicePrincipal="config-multiaccountsetup.amazonaws.com", ) + # Set config variable + audit_info.audit_config = { + "organizations_trusted_delegated_administrators": [ + account["CreateAccountStatus"]["AccountId"] + ] + } + with mock.patch( "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", new=audit_info, @@ -127,27 +135,23 @@ class Test_organizations_delegated_administrators: "prowler.providers.aws.services.organizations.organizations_delegated_administrators.organizations_delegated_administrators.organizations_client", new=Organizations(audit_info), ): - with mock.patch( - "prowler.providers.aws.services.organizations.organizations_delegated_administrators.organizations_delegated_administrators.get_config_var", - return_value=[account["CreateAccountStatus"]["AccountId"]], - ): - # Test Check - from prowler.providers.aws.services.organizations.organizations_delegated_administrators.organizations_delegated_administrators import ( - organizations_delegated_administrators, - ) + # Test Check + from prowler.providers.aws.services.organizations.organizations_delegated_administrators.organizations_delegated_administrators import ( + organizations_delegated_administrators, + ) - check = organizations_delegated_administrators() - result = check.execute() + check = organizations_delegated_administrators() + result = check.execute() - assert len(result) == 1 - assert result[0].status == "PASS" - assert result[0].resource_id == response["Organization"]["Id"] - assert result[0].resource_arn == response["Organization"]["Arn"] - assert search( - "Trusted Delegated Administrator", - result[0].status_extended, - ) - assert result[0].region == AWS_REGION + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == response["Organization"]["Id"] + assert result[0].resource_arn == response["Organization"]["Arn"] + assert search( + "Trusted Delegated Administrator", + result[0].status_extended, + ) + assert result[0].region == AWS_REGION @mock_organizations def test_organization_untrusted_delegated(self): @@ -167,6 +171,9 @@ class Test_organizations_delegated_administrators: ServicePrincipal="config-multiaccountsetup.amazonaws.com", ) + # Set config variable + audit_info.audit_config = {"organizations_trusted_delegated_administrators": []} + with mock.patch( "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", new=audit_info, diff --git a/tests/providers/aws/services/organizations/organizations_scp_check_deny_regions/organizations_scp_check_deny_regions_test.py b/tests/providers/aws/services/organizations/organizations_scp_check_deny_regions/organizations_scp_check_deny_regions_test.py index 01a5232d..bd826135 100644 --- a/tests/providers/aws/services/organizations/organizations_scp_check_deny_regions/organizations_scp_check_deny_regions_test.py +++ b/tests/providers/aws/services/organizations/organizations_scp_check_deny_regions/organizations_scp_check_deny_regions_test.py @@ -52,7 +52,7 @@ class Test_organizations_scp_check_deny_regions: @mock_organizations def test_no_organization(self): audit_info = self.set_mocked_audit_info() - + audit_info.audit_config = {"organizations_enabled_regions": [AWS_REGION]} with mock.patch( "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", new=audit_info, @@ -82,6 +82,7 @@ class Test_organizations_scp_check_deny_regions: @mock_organizations def test_organization_without_scp_deny_regions(self): audit_info = self.set_mocked_audit_info() + audit_info.audit_config = {"organizations_enabled_regions": [AWS_REGION]} # Create Organization conn = client("organizations", region_name=AWS_REGION) @@ -128,6 +129,9 @@ class Test_organizations_scp_check_deny_regions: Type="SERVICE_CONTROL_POLICY", ) + # Set config variable + audit_info.audit_config = {"organizations_enabled_regions": ["eu-central-1"]} + with mock.patch( "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", new=audit_info, @@ -136,27 +140,23 @@ class Test_organizations_scp_check_deny_regions: "prowler.providers.aws.services.organizations.organizations_scp_check_deny_regions.organizations_scp_check_deny_regions.organizations_client", new=Organizations(audit_info), ): - with mock.patch( - "prowler.providers.aws.services.organizations.organizations_scp_check_deny_regions.organizations_scp_check_deny_regions.get_config_var", - return_value=["eu-central-1"], - ): - # Test Check - from prowler.providers.aws.services.organizations.organizations_scp_check_deny_regions.organizations_scp_check_deny_regions import ( - organizations_scp_check_deny_regions, - ) + # Test Check + from prowler.providers.aws.services.organizations.organizations_scp_check_deny_regions.organizations_scp_check_deny_regions import ( + organizations_scp_check_deny_regions, + ) - check = organizations_scp_check_deny_regions() - result = check.execute() + check = organizations_scp_check_deny_regions() + result = check.execute() - assert len(result) == 1 - assert result[0].status == "PASS" - assert result[0].resource_id == response["Organization"]["Id"] - assert result[0].resource_arn == response["Organization"]["Arn"] - assert search( - "restricting all configured regions found", - result[0].status_extended, - ) - assert result[0].region == AWS_REGION + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].resource_id == response["Organization"]["Id"] + assert result[0].resource_arn == response["Organization"]["Arn"] + assert search( + "restricting all configured regions found", + result[0].status_extended, + ) + assert result[0].region == AWS_REGION @mock_organizations def test_organization_with_scp_deny_regions_not_valid(self): @@ -173,6 +173,9 @@ class Test_organizations_scp_check_deny_regions: Type="SERVICE_CONTROL_POLICY", ) + # Set config variable + audit_info.audit_config = {"organizations_enabled_regions": ["us-east-1"]} + with mock.patch( "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", new=audit_info, @@ -181,24 +184,20 @@ class Test_organizations_scp_check_deny_regions: "prowler.providers.aws.services.organizations.organizations_scp_check_deny_regions.organizations_scp_check_deny_regions.organizations_client", new=Organizations(audit_info), ): - with mock.patch( - "prowler.providers.aws.services.organizations.organizations_scp_check_deny_regions.organizations_scp_check_deny_regions.get_config_var", - return_value=["us-east-1"], - ): - # Test Check - from prowler.providers.aws.services.organizations.organizations_scp_check_deny_regions.organizations_scp_check_deny_regions import ( - organizations_scp_check_deny_regions, - ) + # Test Check + from prowler.providers.aws.services.organizations.organizations_scp_check_deny_regions.organizations_scp_check_deny_regions import ( + organizations_scp_check_deny_regions, + ) - check = organizations_scp_check_deny_regions() - result = check.execute() + check = organizations_scp_check_deny_regions() + result = check.execute() - assert len(result) == 1 - assert result[0].status == "FAIL" - assert result[0].resource_id == response["Organization"]["Id"] - assert result[0].resource_arn == response["Organization"]["Arn"] - assert search( - "restricting some AWS Regions, but not all the configured ones, please check config...", - result[0].status_extended, - ) - assert result[0].region == AWS_REGION + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].resource_id == response["Organization"]["Id"] + assert result[0].resource_arn == response["Organization"]["Arn"] + assert search( + "restricting some AWS Regions, but not all the configured ones, please check config...", + result[0].status_extended, + ) + assert result[0].region == AWS_REGION diff --git a/tests/providers/aws/services/vpc/vpc_endpoint_connections_trust_boundaries/vpc_endpoint_connections_trust_boundaries_test.py b/tests/providers/aws/services/vpc/vpc_endpoint_connections_trust_boundaries/vpc_endpoint_connections_trust_boundaries_test.py index eb940bc1..43c72e6a 100644 --- a/tests/providers/aws/services/vpc/vpc_endpoint_connections_trust_boundaries/vpc_endpoint_connections_trust_boundaries_test.py +++ b/tests/providers/aws/services/vpc/vpc_endpoint_connections_trust_boundaries/vpc_endpoint_connections_trust_boundaries_test.py @@ -13,12 +13,6 @@ TRUSTED_AWS_ACCOUNT_NUMBER = "111122223333" NON_TRUSTED_AWS_ACCOUNT_NUMBER = "000011112222" -def mock_get_config_var(config_var): - if config_var == "trusted_account_ids": - return [TRUSTED_AWS_ACCOUNT_NUMBER] - return [] - - class Test_vpc_endpoint_connections_trust_boundaries: def set_mocked_audit_info(self): audit_info = AWS_Audit_Info( @@ -56,6 +50,8 @@ class Test_vpc_endpoint_connections_trust_boundaries: from prowler.providers.aws.services.vpc.vpc_service import VPC current_audit_info = self.set_mocked_audit_info() + # Set config variable + current_audit_info.audit_config = {"trusted_account_ids": []} with mock.patch( "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", @@ -105,6 +101,8 @@ class Test_vpc_endpoint_connections_trust_boundaries: from prowler.providers.aws.services.vpc.vpc_service import VPC current_audit_info = self.set_mocked_audit_info() + # Set config variable + current_audit_info.audit_config = {"trusted_account_ids": []} with mock.patch( "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", @@ -165,6 +163,8 @@ class Test_vpc_endpoint_connections_trust_boundaries: from prowler.providers.aws.services.vpc.vpc_service import VPC current_audit_info = self.set_mocked_audit_info() + # Set config variable + current_audit_info.audit_config = {"trusted_account_ids": []} with mock.patch( "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", @@ -223,6 +223,8 @@ class Test_vpc_endpoint_connections_trust_boundaries: from prowler.providers.aws.services.vpc.vpc_service import VPC current_audit_info = self.set_mocked_audit_info() + # Set config variable + current_audit_info.audit_config = {"trusted_account_ids": []} with mock.patch( "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", @@ -284,6 +286,8 @@ class Test_vpc_endpoint_connections_trust_boundaries: from prowler.providers.aws.services.vpc.vpc_service import VPC current_audit_info = self.set_mocked_audit_info() + # Set config variable + current_audit_info.audit_config = {"trusted_account_ids": []} with mock.patch( "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", @@ -344,6 +348,11 @@ class Test_vpc_endpoint_connections_trust_boundaries: current_audit_info = self.set_mocked_audit_info() + # Set config variable + current_audit_info.audit_config = { + "trusted_account_ids": [TRUSTED_AWS_ACCOUNT_NUMBER] + } + with mock.patch( "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", new=current_audit_info, @@ -352,29 +361,25 @@ class Test_vpc_endpoint_connections_trust_boundaries: "prowler.providers.aws.services.vpc.vpc_endpoint_connections_trust_boundaries.vpc_endpoint_connections_trust_boundaries.vpc_client", new=VPC(current_audit_info), ): - with mock.patch( - "prowler.providers.aws.services.vpc.vpc_endpoint_connections_trust_boundaries.vpc_endpoint_connections_trust_boundaries.get_config_var", - new=mock_get_config_var, - ): - # Test Check - from prowler.providers.aws.services.vpc.vpc_endpoint_connections_trust_boundaries.vpc_endpoint_connections_trust_boundaries import ( - vpc_endpoint_connections_trust_boundaries, - ) + # Test Check + from prowler.providers.aws.services.vpc.vpc_endpoint_connections_trust_boundaries.vpc_endpoint_connections_trust_boundaries import ( + vpc_endpoint_connections_trust_boundaries, + ) - check = vpc_endpoint_connections_trust_boundaries() - result = check.execute() + check = vpc_endpoint_connections_trust_boundaries() + result = check.execute() - assert len(result) == 1 - assert result[0].status == "PASS" - assert ( - result[0].status_extended - == f"VPC Endpoint {vpc_endpoint['VpcEndpoint']['VpcEndpointId']} in VPC {vpc['VpcId']} can only be accessed from trusted accounts." - ) - assert ( - result[0].resource_id - == vpc_endpoint["VpcEndpoint"]["VpcEndpointId"] - ) - assert result[0].region == AWS_REGION + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"VPC Endpoint {vpc_endpoint['VpcEndpoint']['VpcEndpointId']} in VPC {vpc['VpcId']} can only be accessed from trusted accounts." + ) + assert ( + result[0].resource_id + == vpc_endpoint["VpcEndpoint"]["VpcEndpointId"] + ) + assert result[0].region == AWS_REGION @mock_ec2 def test_vpc_endpoint_with_config_trusted_account(self): @@ -406,6 +411,11 @@ class Test_vpc_endpoint_connections_trust_boundaries: current_audit_info = self.set_mocked_audit_info() + # Set config variable + current_audit_info.audit_config = { + "trusted_account_ids": [TRUSTED_AWS_ACCOUNT_NUMBER] + } + with mock.patch( "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", new=current_audit_info, @@ -414,29 +424,25 @@ class Test_vpc_endpoint_connections_trust_boundaries: "prowler.providers.aws.services.vpc.vpc_endpoint_connections_trust_boundaries.vpc_endpoint_connections_trust_boundaries.vpc_client", new=VPC(current_audit_info), ): - with mock.patch( - "prowler.providers.aws.services.vpc.vpc_endpoint_connections_trust_boundaries.vpc_endpoint_connections_trust_boundaries.get_config_var", - new=mock_get_config_var, - ): - # Test Check - from prowler.providers.aws.services.vpc.vpc_endpoint_connections_trust_boundaries.vpc_endpoint_connections_trust_boundaries import ( - vpc_endpoint_connections_trust_boundaries, - ) + # Test Check + from prowler.providers.aws.services.vpc.vpc_endpoint_connections_trust_boundaries.vpc_endpoint_connections_trust_boundaries import ( + vpc_endpoint_connections_trust_boundaries, + ) - check = vpc_endpoint_connections_trust_boundaries() - result = check.execute() + check = vpc_endpoint_connections_trust_boundaries() + result = check.execute() - assert len(result) == 1 - assert result[0].status == "PASS" - assert ( - result[0].status_extended - == f"VPC Endpoint {vpc_endpoint['VpcEndpoint']['VpcEndpointId']} in VPC {vpc['VpcId']} can only be accessed from trusted accounts." - ) - assert ( - result[0].resource_id - == vpc_endpoint["VpcEndpoint"]["VpcEndpointId"] - ) - assert result[0].region == AWS_REGION + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"VPC Endpoint {vpc_endpoint['VpcEndpoint']['VpcEndpointId']} in VPC {vpc['VpcId']} can only be accessed from trusted accounts." + ) + assert ( + result[0].resource_id + == vpc_endpoint["VpcEndpoint"]["VpcEndpointId"] + ) + assert result[0].region == AWS_REGION @mock_ec2 def test_vpc_endpoint_with_two_account_ids_one_trusted_one_not(self): @@ -472,6 +478,8 @@ class Test_vpc_endpoint_connections_trust_boundaries: from prowler.providers.aws.services.vpc.vpc_service import VPC current_audit_info = self.set_mocked_audit_info() + # Set config variable + current_audit_info.audit_config = {"trusted_account_ids": []} with mock.patch( "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", @@ -530,6 +538,8 @@ class Test_vpc_endpoint_connections_trust_boundaries: from prowler.providers.aws.services.vpc.vpc_service import VPC current_audit_info = self.set_mocked_audit_info() + # Set config variable + current_audit_info.audit_config = {"trusted_account_ids": []} with mock.patch( "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", @@ -595,6 +605,8 @@ class Test_vpc_endpoint_connections_trust_boundaries: from prowler.providers.aws.services.vpc.vpc_service import VPC current_audit_info = self.set_mocked_audit_info() + # Set config variable + current_audit_info.audit_config = {"trusted_account_ids": []} with mock.patch( "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", @@ -660,6 +672,8 @@ class Test_vpc_endpoint_connections_trust_boundaries: from prowler.providers.aws.services.vpc.vpc_service import VPC current_audit_info = self.set_mocked_audit_info() + # Set config variable + current_audit_info.audit_config = {"trusted_account_ids": []} with mock.patch( "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", diff --git a/tests/providers/aws/services/vpc/vpc_endpoint_services_allowed_principals_trust_boundaries/vpc_endpoint_services_allowed_principals_trust_boundaries_test.py b/tests/providers/aws/services/vpc/vpc_endpoint_services_allowed_principals_trust_boundaries/vpc_endpoint_services_allowed_principals_trust_boundaries_test.py index 9f302213..24244bc7 100644 --- a/tests/providers/aws/services/vpc/vpc_endpoint_services_allowed_principals_trust_boundaries/vpc_endpoint_services_allowed_principals_trust_boundaries_test.py +++ b/tests/providers/aws/services/vpc/vpc_endpoint_services_allowed_principals_trust_boundaries/vpc_endpoint_services_allowed_principals_trust_boundaries_test.py @@ -73,6 +73,8 @@ class Test_vpc_endpoint_services_allowed_principals_trust_boundaries: from prowler.providers.aws.services.vpc.vpc_service import VPC current_audit_info = self.set_mocked_audit_info() + # Set config variable + current_audit_info.audit_config = {"trusted_account_ids": []} with mock.patch( "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", @@ -123,6 +125,8 @@ class Test_vpc_endpoint_services_allowed_principals_trust_boundaries: from prowler.providers.aws.services.vpc.vpc_service import VPC current_audit_info = self.set_mocked_audit_info() + # Set config variable + current_audit_info.audit_config = {"trusted_account_ids": []} with mock.patch( "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", diff --git a/tests/providers/common/audit_info_test.py b/tests/providers/common/audit_info_test.py index fb4c85fc..66542a65 100644 --- a/tests/providers/common/audit_info_test.py +++ b/tests/providers/common/audit_info_test.py @@ -6,6 +6,7 @@ from boto3 import session from mock import patch from moto import mock_ec2, mock_resourcegroupstaggingapi +from prowler.config.config import default_config_file_path from prowler.providers.aws.lib.audit_info.models import AWS_Assume_Role, AWS_Audit_Info from prowler.providers.azure.azure_provider import Azure_Provider from prowler.providers.azure.lib.audit_info.models import ( @@ -30,6 +31,7 @@ mock_azure_audit_info = Azure_Audit_Info( identity=Azure_Identity_Info(), audit_metadata=None, audit_resources=None, + audit_config=None, ) mock_set_audit_info = Audit_Info() @@ -148,6 +150,7 @@ class Test_Set_Audit_Info: "sp_env_auth": None, "browser_auth": None, "managed_entity_auth": None, + "config_file": default_config_file_path, } audit_info = set_provider_audit_info(provider, arguments) @@ -169,6 +172,7 @@ class Test_Set_Audit_Info: # We need to set exactly one auth method "credentials_file": None, "project_ids": ["project"], + "config_file": default_config_file_path, } audit_info = set_provider_audit_info(provider, arguments) @@ -244,6 +248,7 @@ class Test_Set_Audit_Info: "external_id": None, "regions": None, "organizations_role": None, + "config_file": default_config_file_path, } audit_info = set_provider_audit_info(provider, arguments) diff --git a/tests/providers/common/common_outputs_test.py b/tests/providers/common/common_outputs_test.py index b058323d..a6f38cf6 100644 --- a/tests/providers/common/common_outputs_test.py +++ b/tests/providers/common/common_outputs_test.py @@ -22,14 +22,6 @@ AWS_ACCOUNT_NUMBER = "012345678912" DATETIME = "20230101120000" -def mock_change_config_var(*_): - pass - - -@patch( - "prowler.providers.common.outputs.change_config_var", - new=mock_change_config_var, -) @patch("prowler.providers.common.outputs.output_file_timestamp", new=DATETIME) class Test_Common_Output_Options: # Mocked Azure Audit Info @@ -39,6 +31,7 @@ class Test_Common_Output_Options: identity=Azure_Identity_Info(), audit_metadata=None, audit_resources=None, + audit_config=None, ) return audit_info @@ -50,6 +43,7 @@ class Test_Common_Output_Options: project_ids=["test-project1", "test-project2"], audit_resources=None, audit_metadata=None, + audit_config=None, ) return audit_info