diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 7c36bddbb9..8268e7e52a 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -73,7 +73,7 @@ jobs: - name: Safety if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true' run: | - poetry run safety check --ignore 67599 + poetry run safety check --ignore 67599 --ignore 70612 - name: Vulture if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true' run: | diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f4f748499e..e8fbaa5bec 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -96,7 +96,7 @@ repos: - id: safety name: safety description: "Safety is a tool that checks your installed dependencies for known security vulnerabilities" - entry: bash -c 'safety check --ignore 67599' + entry: bash -c 'safety check --ignore 67599 --ignore 70612' language: system - id: vulture diff --git a/prowler/providers/aws/services/cloudtrail/cloudtrail_bucket_requires_mfa_delete/cloudtrail_bucket_requires_mfa_delete.py b/prowler/providers/aws/services/cloudtrail/cloudtrail_bucket_requires_mfa_delete/cloudtrail_bucket_requires_mfa_delete.py index 8feec3de79..518214b6c6 100644 --- a/prowler/providers/aws/services/cloudtrail/cloudtrail_bucket_requires_mfa_delete/cloudtrail_bucket_requires_mfa_delete.py +++ b/prowler/providers/aws/services/cloudtrail/cloudtrail_bucket_requires_mfa_delete/cloudtrail_bucket_requires_mfa_delete.py @@ -14,7 +14,7 @@ class cloudtrail_bucket_requires_mfa_delete(Check): trail_bucket_is_in_account = False trail_bucket = trail.s3_bucket report = Check_Report_AWS(self.metadata()) - report.region = trail.region + report.region = trail.home_region report.resource_id = trail.name report.resource_arn = trail.arn report.resource_tags = trail.tags diff --git a/prowler/providers/aws/services/cloudtrail/cloudtrail_cloudwatch_logging_enabled/cloudtrail_cloudwatch_logging_enabled.py b/prowler/providers/aws/services/cloudtrail/cloudtrail_cloudwatch_logging_enabled/cloudtrail_cloudwatch_logging_enabled.py index 6d502d0884..0f9b64a5d9 100644 --- a/prowler/providers/aws/services/cloudtrail/cloudtrail_cloudwatch_logging_enabled/cloudtrail_cloudwatch_logging_enabled.py +++ b/prowler/providers/aws/services/cloudtrail/cloudtrail_cloudwatch_logging_enabled/cloudtrail_cloudwatch_logging_enabled.py @@ -15,7 +15,7 @@ class cloudtrail_cloudwatch_logging_enabled(Check): for trail in cloudtrail_client.trails.values(): if trail.name: report = Check_Report_AWS(self.metadata()) - report.region = trail.region + report.region = trail.home_region report.resource_id = trail.name report.resource_arn = trail.arn report.resource_tags = trail.tags diff --git a/prowler/providers/aws/services/cloudtrail/cloudtrail_insights_exist/cloudtrail_insights_exist.py b/prowler/providers/aws/services/cloudtrail/cloudtrail_insights_exist/cloudtrail_insights_exist.py index c24aaa2c26..c21fbb9b75 100644 --- a/prowler/providers/aws/services/cloudtrail/cloudtrail_insights_exist/cloudtrail_insights_exist.py +++ b/prowler/providers/aws/services/cloudtrail/cloudtrail_insights_exist/cloudtrail_insights_exist.py @@ -11,7 +11,7 @@ class cloudtrail_insights_exist(Check): for trail in cloudtrail_client.trails.values(): if trail.is_logging: report = Check_Report_AWS(self.metadata()) - report.region = trail.region + report.region = trail.home_region report.resource_id = trail.name report.resource_arn = trail.arn report.resource_tags = trail.tags diff --git a/prowler/providers/aws/services/cloudtrail/cloudtrail_kms_encryption_enabled/cloudtrail_kms_encryption_enabled.py b/prowler/providers/aws/services/cloudtrail/cloudtrail_kms_encryption_enabled/cloudtrail_kms_encryption_enabled.py index 85fb994541..d846fe7c32 100644 --- a/prowler/providers/aws/services/cloudtrail/cloudtrail_kms_encryption_enabled/cloudtrail_kms_encryption_enabled.py +++ b/prowler/providers/aws/services/cloudtrail/cloudtrail_kms_encryption_enabled/cloudtrail_kms_encryption_enabled.py @@ -11,7 +11,7 @@ class cloudtrail_kms_encryption_enabled(Check): for trail in cloudtrail_client.trails.values(): if trail.name: report = Check_Report_AWS(self.metadata()) - report.region = trail.region + report.region = trail.home_region report.resource_id = trail.name report.resource_arn = trail.arn report.resource_tags = trail.tags diff --git a/prowler/providers/aws/services/cloudtrail/cloudtrail_log_file_validation_enabled/cloudtrail_log_file_validation_enabled.py b/prowler/providers/aws/services/cloudtrail/cloudtrail_log_file_validation_enabled/cloudtrail_log_file_validation_enabled.py index a2d6c6fee3..32dcd5347f 100644 --- a/prowler/providers/aws/services/cloudtrail/cloudtrail_log_file_validation_enabled/cloudtrail_log_file_validation_enabled.py +++ b/prowler/providers/aws/services/cloudtrail/cloudtrail_log_file_validation_enabled/cloudtrail_log_file_validation_enabled.py @@ -11,7 +11,7 @@ class cloudtrail_log_file_validation_enabled(Check): for trail in cloudtrail_client.trails.values(): if trail.name: report = Check_Report_AWS(self.metadata()) - report.region = trail.region + report.region = trail.home_region report.resource_id = trail.name report.resource_arn = trail.arn report.resource_tags = trail.tags diff --git a/prowler/providers/aws/services/cloudtrail/cloudtrail_logs_s3_bucket_access_logging_enabled/cloudtrail_logs_s3_bucket_access_logging_enabled.py b/prowler/providers/aws/services/cloudtrail/cloudtrail_logs_s3_bucket_access_logging_enabled/cloudtrail_logs_s3_bucket_access_logging_enabled.py index 0f2c0643f9..821da91b45 100644 --- a/prowler/providers/aws/services/cloudtrail/cloudtrail_logs_s3_bucket_access_logging_enabled/cloudtrail_logs_s3_bucket_access_logging_enabled.py +++ b/prowler/providers/aws/services/cloudtrail/cloudtrail_logs_s3_bucket_access_logging_enabled/cloudtrail_logs_s3_bucket_access_logging_enabled.py @@ -14,7 +14,7 @@ class cloudtrail_logs_s3_bucket_access_logging_enabled(Check): trail_bucket_is_in_account = False trail_bucket = trail.s3_bucket report = Check_Report_AWS(self.metadata()) - report.region = trail.region + report.region = trail.home_region report.resource_id = trail.name report.resource_arn = trail.arn report.resource_tags = trail.tags diff --git a/prowler/providers/aws/services/cloudtrail/cloudtrail_logs_s3_bucket_is_not_publicly_accessible/cloudtrail_logs_s3_bucket_is_not_publicly_accessible.py b/prowler/providers/aws/services/cloudtrail/cloudtrail_logs_s3_bucket_is_not_publicly_accessible/cloudtrail_logs_s3_bucket_is_not_publicly_accessible.py index ef503f8f94..2293c4bd20 100644 --- a/prowler/providers/aws/services/cloudtrail/cloudtrail_logs_s3_bucket_is_not_publicly_accessible/cloudtrail_logs_s3_bucket_is_not_publicly_accessible.py +++ b/prowler/providers/aws/services/cloudtrail/cloudtrail_logs_s3_bucket_is_not_publicly_accessible/cloudtrail_logs_s3_bucket_is_not_publicly_accessible.py @@ -14,7 +14,7 @@ class cloudtrail_logs_s3_bucket_is_not_publicly_accessible(Check): trail_bucket_is_in_account = False trail_bucket = trail.s3_bucket report = Check_Report_AWS(self.metadata()) - report.region = trail.region + report.region = trail.home_region report.resource_id = trail.name report.resource_arn = trail.arn report.resource_tags = trail.tags diff --git a/prowler/providers/aws/services/cloudtrail/cloudtrail_multi_region_enabled_logging_management_events/cloudtrail_multi_region_enabled_logging_management_events.py b/prowler/providers/aws/services/cloudtrail/cloudtrail_multi_region_enabled_logging_management_events/cloudtrail_multi_region_enabled_logging_management_events.py index ac6b5a9db1..8d6bc56253 100644 --- a/prowler/providers/aws/services/cloudtrail/cloudtrail_multi_region_enabled_logging_management_events/cloudtrail_multi_region_enabled_logging_management_events.py +++ b/prowler/providers/aws/services/cloudtrail/cloudtrail_multi_region_enabled_logging_management_events/cloudtrail_multi_region_enabled_logging_management_events.py @@ -8,48 +8,55 @@ class cloudtrail_multi_region_enabled_logging_management_events(Check): def execute(self): findings = [] if cloudtrail_client.trails is not None: - report = Check_Report_AWS(self.metadata()) - report.status = "FAIL" - report.status_extended = "No trail found with multi-region enabled and logging management events." - report.region = cloudtrail_client.region - report.resource_id = cloudtrail_client.audited_account - report.resource_arn = cloudtrail_client.trail_arn_template - - for trail in cloudtrail_client.trails.values(): - if trail.is_logging: - if trail.is_multiregion: - for event in trail.data_events: - # Classic event selectors - if not event.is_advanced: - # Check if trail has IncludeManagementEvents and ReadWriteType is All - if ( - event.event_selector["ReadWriteType"] == "All" - and event.event_selector["IncludeManagementEvents"] - ): - report.region = trail.region - report.resource_id = trail.name - report.resource_arn = trail.arn - report.resource_tags = trail.tags - report.status = "PASS" - report.status_extended = f"Trail {trail.name} from home region {trail.home_region} is multi-region, is logging and have management events enabled." - - # Advanced event selectors - elif event.is_advanced: - if event.event_selector.get( - "Name" - ) == "Management events selector" and all( - [ - field["Field"] != "readOnly" - for field in event.event_selector[ - "FieldSelectors" + for region in cloudtrail_client.regional_clients.keys(): + report = Check_Report_AWS(self.metadata()) + report.status = "FAIL" + report.status_extended = "No CloudTrail trails enabled and logging management events were found." + report.region = region + report.resource_id = cloudtrail_client.audited_account + report.resource_arn = cloudtrail_client.trail_arn_template + trail_is_logging_management_events = False + for trail in cloudtrail_client.trails.values(): + if trail.region == region or trail.is_multiregion: + if trail.is_logging: + for event in trail.data_events: + # Classic event selectors + if not event.is_advanced: + # Check if trail has IncludeManagementEvents and ReadWriteType is All + if ( + event.event_selector["ReadWriteType"] == "All" + and event.event_selector[ + "IncludeManagementEvents" ] - ] - ): - report.region = trail.region - report.resource_id = trail.name - report.resource_arn = trail.arn - report.resource_tags = trail.tags - report.status = "PASS" - report.status_extended = f"Trail {trail.name} from home region {trail.home_region} is multi-region, is logging and have management events enabled." - findings.append(report) + ): + trail_is_logging_management_events = True + + # Advanced event selectors + elif event.is_advanced: + if event.event_selector.get( + "Name" + ) == "Management events selector" and all( + [ + field["Field"] != "readOnly" + for field in event.event_selector[ + "FieldSelectors" + ] + ] + ): + trail_is_logging_management_events = True + if trail_is_logging_management_events: + report.resource_id = trail.name + report.resource_arn = trail.arn + report.resource_tags = trail.tags + report.status = "PASS" + if trail.is_multiregion: + report.status_extended = f"Trail {trail.name} from home region {trail.home_region} is multi-region, is logging and have management events enabled." + else: + report.status_extended = f"Trail {trail.name} in region {trail.home_region} is logging and have management events enabled." + # Since there exists a logging trail in that region there is no point in checking the remaining trails + # Store the finding and exit the loop + findings.append(report) + break + if report.status == "FAIL": + findings.append(report) return findings diff --git a/prowler/providers/aws/services/cloudtrail/cloudtrail_s3_dataevents_read_enabled/cloudtrail_s3_dataevents_read_enabled.py b/prowler/providers/aws/services/cloudtrail/cloudtrail_s3_dataevents_read_enabled/cloudtrail_s3_dataevents_read_enabled.py index 237054b1be..25113bdfdb 100644 --- a/prowler/providers/aws/services/cloudtrail/cloudtrail_s3_dataevents_read_enabled/cloudtrail_s3_dataevents_read_enabled.py +++ b/prowler/providers/aws/services/cloudtrail/cloudtrail_s3_dataevents_read_enabled/cloudtrail_s3_dataevents_read_enabled.py @@ -28,7 +28,7 @@ class cloudtrail_s3_dataevents_read_enabled(Check): in resource["Values"] ): report = Check_Report_AWS(self.metadata()) - report.region = trail.region + report.region = trail.home_region report.resource_id = trail.name report.resource_arn = trail.arn report.resource_tags = trail.tags @@ -45,7 +45,7 @@ class cloudtrail_s3_dataevents_read_enabled(Check): and field_selector["Equals"][0] == "AWS::S3::Object" ): report = Check_Report_AWS(self.metadata()) - report.region = trail.region + report.region = trail.home_region report.resource_id = trail.name report.resource_arn = trail.arn report.resource_tags = trail.tags diff --git a/prowler/providers/aws/services/cloudtrail/cloudtrail_s3_dataevents_write_enabled/cloudtrail_s3_dataevents_write_enabled.py b/prowler/providers/aws/services/cloudtrail/cloudtrail_s3_dataevents_write_enabled/cloudtrail_s3_dataevents_write_enabled.py index 247c85971d..a710bc79ee 100644 --- a/prowler/providers/aws/services/cloudtrail/cloudtrail_s3_dataevents_write_enabled/cloudtrail_s3_dataevents_write_enabled.py +++ b/prowler/providers/aws/services/cloudtrail/cloudtrail_s3_dataevents_write_enabled/cloudtrail_s3_dataevents_write_enabled.py @@ -28,7 +28,7 @@ class cloudtrail_s3_dataevents_write_enabled(Check): in resource["Values"] ): report = Check_Report_AWS(self.metadata()) - report.region = trail.region + report.region = trail.home_region report.resource_id = trail.name report.resource_arn = trail.arn report.resource_tags = trail.tags @@ -45,7 +45,7 @@ class cloudtrail_s3_dataevents_write_enabled(Check): and field_selector["Equals"][0] == "AWS::S3::Object" ): report = Check_Report_AWS(self.metadata()) - report.region = trail.region + report.region = trail.home_region report.resource_id = trail.name report.resource_arn = trail.arn report.resource_tags = trail.tags diff --git a/prowler/providers/aws/services/cloudtrail/cloudtrail_service.py b/prowler/providers/aws/services/cloudtrail/cloudtrail_service.py index c0eb926fac..b4cda543df 100644 --- a/prowler/providers/aws/services/cloudtrail/cloudtrail_service.py +++ b/prowler/providers/aws/services/cloudtrail/cloudtrail_service.py @@ -36,6 +36,10 @@ class Cloudtrail(AWSService): describe_trails = regional_client.describe_trails()["trailList"] trails_count = 0 for trail in describe_trails: + # If a multi region trail was already retrieved in another region + if trail["TrailARN"] in self.trails.keys(): + continue + if not self.audit_resources or ( is_resource_filtered(trail["TrailARN"], self.audit_resources) ): @@ -192,16 +196,21 @@ class Cloudtrail(AWSService): logger.info("CloudTrail - List Tags...") try: for trail in self.trails.values(): - # Check if trails are in this account and region - if ( - trail.region == trail.home_region - and self.audited_account in trail.arn - ): - regional_client = self.regional_clients[trail.region] - response = regional_client.list_tags(ResourceIdList=[trail.arn])[ - "ResourceTagList" - ][0] - trail.tags = response.get("TagsList") + try: + # Check if trails are in this account and region + if ( + trail.region == trail.home_region + and self.audited_account in trail.arn + ): + regional_client = self.regional_clients[trail.region] + response = regional_client.list_tags( + ResourceIdList=[trail.arn] + )["ResourceTagList"][0] + trail.tags = response.get("TagsList") + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) except Exception as error: logger.error( f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" @@ -218,6 +227,7 @@ class Trail(BaseModel): is_multiregion: bool = None home_region: str = None arn: str = None + # Region holds the region where the trail is audited region: str is_logging: bool = None log_file_validation_enabled: bool = None diff --git a/prowler/providers/aws/services/iam/iam_no_custom_policy_permissive_role_assumption/iam_no_custom_policy_permissive_role_assumption.metadata.json b/prowler/providers/aws/services/iam/iam_no_custom_policy_permissive_role_assumption/iam_no_custom_policy_permissive_role_assumption.metadata.json index 67390a818b..b6c76a5c2d 100644 --- a/prowler/providers/aws/services/iam/iam_no_custom_policy_permissive_role_assumption/iam_no_custom_policy_permissive_role_assumption.metadata.json +++ b/prowler/providers/aws/services/iam/iam_no_custom_policy_permissive_role_assumption/iam_no_custom_policy_permissive_role_assumption.metadata.json @@ -8,11 +8,11 @@ "ServiceName": "iam", "SubServiceName": "", "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", - "Severity": "critical", + "Severity": "high", "ResourceType": "AwsIamPolicy", "Description": "Ensure that no custom IAM policies exist which allow permissive role assumption (e.g. sts:AssumeRole on *)", "Risk": "If not restricted unintended access could happen.", - "RelatedUrl": "", + "RelatedUrl": "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_permissions-to-switch.html#roles-usingrole-createpolicy", "Remediation": { "Code": { "CLI": "", diff --git a/prowler/providers/aws/services/rds/rds_service.py b/prowler/providers/aws/services/rds/rds_service.py index 7151eaf2ea..e755688930 100644 --- a/prowler/providers/aws/services/rds/rds_service.py +++ b/prowler/providers/aws/services/rds/rds_service.py @@ -24,6 +24,7 @@ class RDS(AWSService): self.__threading_call__(self.__describe_db_snapshots__) self.__threading_call__(self.__describe_db_snapshot_attributes__) self.__threading_call__(self.__describe_db_clusters__) + self.__threading_call__(self.__describe_db_cluster_parameters__) self.__threading_call__(self.__describe_db_cluster_snapshots__) self.__threading_call__(self.__describe_db_cluster_snapshot_attributes__) self.__threading_call__(self.__describe_db_engine_versions__) @@ -164,57 +165,98 @@ class RDS(AWSService): "describe_db_clusters" ) for page in describe_db_clusters_paginator.paginate(): - for cluster in page["DBClusters"]: - db_cluster_arn = f"arn:{self.audited_partition}:rds:{regional_client.region}:{self.audited_account}:cluster:{cluster['DBClusterIdentifier']}" - if not self.audit_resources or ( - is_resource_filtered(db_cluster_arn, self.audit_resources) - ): - if cluster["Engine"] != "docdb": - describe_db_parameters_paginator = ( - regional_client.get_paginator("describe_db_parameters") - ) - db_cluster = DBCluster( - id=cluster["DBClusterIdentifier"], - arn=db_cluster_arn, - endpoint=cluster.get("Endpoint"), - engine=cluster["Engine"], - status=cluster["Status"], - public=cluster.get("PubliclyAccessible", False), - encrypted=cluster["StorageEncrypted"], - auto_minor_version_upgrade=cluster.get( - "AutoMinorVersionUpgrade", False - ), - backup_retention_period=cluster.get( - "BackupRetentionPeriod" - ), - cloudwatch_logs=cluster.get( - "EnabledCloudwatchLogsExports" - ), - deletion_protection=cluster["DeletionProtection"], - parameter_group=cluster["DBClusterParameterGroup"], - multi_az=cluster["MultiAZ"], - region=regional_client.region, - tags=cluster.get("TagList", []), - ) - for page in describe_db_parameters_paginator.paginate( - DBParameterGroupName=cluster["DBClusterParameterGroup"] + try: + for cluster in page["DBClusters"]: + try: + db_cluster_arn = f"arn:{self.audited_partition}:rds:{regional_client.region}:{self.audited_account}:cluster:{cluster['DBClusterIdentifier']}" + if not self.audit_resources or ( + is_resource_filtered( + db_cluster_arn, self.audit_resources + ) ): - for parameter in page["Parameters"]: - if parameter["ParameterName"] == "rds.force_ssl": - db_cluster.force_ssl = parameter[ - "ParameterValue" - ] - if ( - parameter["ParameterName"] - == "require_secure_transport" - ): - db_cluster.require_secure_transport = parameter[ - "ParameterValue" - ] - - # We must use a unique value as the dict key to have unique keys - self.db_clusters[db_cluster_arn] = db_cluster + if cluster["Engine"] != "docdb": + db_cluster = DBCluster( + id=cluster["DBClusterIdentifier"], + arn=db_cluster_arn, + endpoint=cluster.get("Endpoint"), + engine=cluster["Engine"], + status=cluster["Status"], + public=cluster.get("PubliclyAccessible", False), + encrypted=cluster["StorageEncrypted"], + auto_minor_version_upgrade=cluster.get( + "AutoMinorVersionUpgrade", False + ), + backup_retention_period=cluster.get( + "BackupRetentionPeriod" + ), + cloudwatch_logs=cluster.get( + "EnabledCloudwatchLogsExports" + ), + deletion_protection=cluster[ + "DeletionProtection" + ], + parameter_group=cluster[ + "DBClusterParameterGroup" + ], + multi_az=cluster["MultiAZ"], + region=regional_client.region, + tags=cluster.get("TagList", []), + ) + # We must use a unique value as the dict key to have unique keys + self.db_clusters[db_cluster_arn] = db_cluster + except Exception as error: + logger.error( + f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + except Exception as error: + logger.error( + f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + except Exception as error: + logger.error( + f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + def __describe_db_cluster_parameters__(self, regional_client): + logger.info("RDS - Describe DB Cluster Parameters...") + try: + for cluster in self.db_clusters.values(): + if cluster.region == regional_client.region: + try: + describe_db_cluster_parameters_paginator = ( + regional_client.get_paginator( + "describe_db_cluster_parameters" + ) + ) + for page in describe_db_cluster_parameters_paginator.paginate( + DBClusterParameterGroupName=cluster.parameter_group + ): + for parameter in page["Parameters"]: + if parameter["ParameterName"] == "rds.force_ssl": + cluster.force_ssl = parameter["ParameterValue"] + if ( + parameter["ParameterName"] + == "require_secure_transport" + ): + cluster.require_secure_transport = parameter[ + "ParameterValue" + ] + except ClientError as error: + if ( + error.response["Error"]["Code"] + == "DBClusterParameterGroupName" + ): + logger.warning( + f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + else: + logger.error( + f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + except Exception as error: + logger.error( + f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) except Exception as error: logger.error( f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" @@ -346,8 +388,8 @@ class DBCluster(BaseModel): auto_minor_version_upgrade: bool multi_az: bool parameter_group: str - force_ssl: Optional[bool] - require_secure_transport: Optional[str] + force_ssl: str = "0" + require_secure_transport: str = "OFF" region: str tags: Optional[list] = [] diff --git a/prowler/providers/aws/services/trustedadvisor/trustedadvisor_service.py b/prowler/providers/aws/services/trustedadvisor/trustedadvisor_service.py index 2f999f9153..bb8d52fcae 100644 --- a/prowler/providers/aws/services/trustedadvisor/trustedadvisor_service.py +++ b/prowler/providers/aws/services/trustedadvisor/trustedadvisor_service.py @@ -28,7 +28,7 @@ class TrustedAdvisor(AWSService): ) self.client.region = support_region self.__describe_services__() - if self.premium_support.enabled: + if getattr(self.premium_support, "enabled", False): self.__describe_trusted_advisor_checks__() self.__describe_trusted_advisor_check_result__() diff --git a/prowler/providers/azure/services/defender/defender_service.py b/prowler/providers/azure/services/defender/defender_service.py index 6e8b9ebb34..131bbe4e75 100644 --- a/prowler/providers/azure/services/defender/defender_service.py +++ b/prowler/providers/azure/services/defender/defender_service.py @@ -30,7 +30,9 @@ class Defender(AzureService): pricings = {} for subscription_name, client in self.clients.items(): try: - pricings_list = client.pricings.list() + pricings_list = client.pricings.list( + scope_id=f"subscriptions/{self.subscriptions[subscription_name]}" + ) pricings.update({subscription_name: {}}) for pricing in pricings_list.value: pricings[subscription_name].update( diff --git a/tests/providers/aws/services/cloudtrail/cloudtrail_cloudwatch_logging_enabled/cloudtrail_cloudwatch_logging_enabled_test.py b/tests/providers/aws/services/cloudtrail/cloudtrail_cloudwatch_logging_enabled/cloudtrail_cloudwatch_logging_enabled_test.py index 99267c0f49..e2e0abc7ef 100644 --- a/tests/providers/aws/services/cloudtrail/cloudtrail_cloudwatch_logging_enabled/cloudtrail_cloudwatch_logging_enabled_test.py +++ b/tests/providers/aws/services/cloudtrail/cloudtrail_cloudwatch_logging_enabled/cloudtrail_cloudwatch_logging_enabled_test.py @@ -201,6 +201,7 @@ class Test_cloudtrail_cloudwatch_logging_enabled: report.status_extended, f"Multiregion trail {trail_name_us} has been logging the last 24h.", ) + assert report.region == AWS_REGION_US_EAST_1 assert report.resource_tags == [] if ( report.resource_id == trail_name_eu @@ -213,6 +214,7 @@ class Test_cloudtrail_cloudwatch_logging_enabled: report.status_extended, f"Single region trail {trail_name_eu} is not logging in the last 24h.", ) + assert report.region == AWS_REGION_EU_WEST_1 assert report.resource_tags == [] @mock_aws @@ -287,6 +289,7 @@ class Test_cloudtrail_cloudwatch_logging_enabled: report.status_extended == f"Single region trail {trail_name_us} has been logging the last 24h." ) + assert report.region == AWS_REGION_US_EAST_1 assert report.resource_tags == [] if report.resource_id == trail_name_eu: assert report.resource_id == trail_name_eu @@ -296,6 +299,7 @@ class Test_cloudtrail_cloudwatch_logging_enabled: report.status_extended == f"Single region trail {trail_name_eu} is not logging in the last 24h or not configured to deliver logs." ) + assert report.region == AWS_REGION_EU_WEST_1 assert report.resource_tags == [] @mock_aws diff --git a/tests/providers/aws/services/cloudtrail/cloudtrail_logs_s3_bucket_access_logging_enabled/cloudtrail_logs_s3_bucket_access_logging_enabled_test.py b/tests/providers/aws/services/cloudtrail/cloudtrail_logs_s3_bucket_access_logging_enabled/cloudtrail_logs_s3_bucket_access_logging_enabled_test.py index 4a3c82c30a..22101d0a28 100644 --- a/tests/providers/aws/services/cloudtrail/cloudtrail_logs_s3_bucket_access_logging_enabled/cloudtrail_logs_s3_bucket_access_logging_enabled_test.py +++ b/tests/providers/aws/services/cloudtrail/cloudtrail_logs_s3_bucket_access_logging_enabled/cloudtrail_logs_s3_bucket_access_logging_enabled_test.py @@ -221,7 +221,6 @@ class Test_cloudtrail_logs_s3_bucket_access_logging_enabled: @mock_aws def test_access_denied(self): - from prowler.providers.aws.services.cloudtrail.cloudtrail_service import ( Cloudtrail, ) diff --git a/tests/providers/aws/services/cloudtrail/cloudtrail_multi_region_enabled_logging_management_events/cloudtrail_multi_region_enabled_logging_management_events_test.py b/tests/providers/aws/services/cloudtrail/cloudtrail_multi_region_enabled_logging_management_events/cloudtrail_multi_region_enabled_logging_management_events_test.py index 026d249be8..10fc90daac 100644 --- a/tests/providers/aws/services/cloudtrail/cloudtrail_multi_region_enabled_logging_management_events/cloudtrail_multi_region_enabled_logging_management_events_test.py +++ b/tests/providers/aws/services/cloudtrail/cloudtrail_multi_region_enabled_logging_management_events/cloudtrail_multi_region_enabled_logging_management_events_test.py @@ -6,6 +6,7 @@ from moto import mock_aws from tests.providers.aws.audit_info_utils import ( AWS_ACCOUNT_NUMBER, AWS_REGION_US_EAST_1, + AWS_REGION_US_EAST_2, set_mocked_aws_audit_info, ) @@ -44,7 +45,7 @@ class Test_cloudtrail_multi_region_enabled_logging_management_events: assert result[0].status == "FAIL" assert ( result[0].status_extended - == "No trail found with multi-region enabled and logging management events." + == "No CloudTrail trails enabled and logging management events were found." ) @mock_aws @@ -159,7 +160,7 @@ class Test_cloudtrail_multi_region_enabled_logging_management_events: assert result[0].status == "FAIL" assert ( result[0].status_extended - == "No trail found with multi-region enabled and logging management events." + == "No CloudTrail trails enabled and logging management events were found." ) @mock_aws @@ -271,7 +272,7 @@ class Test_cloudtrail_multi_region_enabled_logging_management_events: assert result[0].status == "FAIL" assert ( result[0].status_extended - == "No trail found with multi-region enabled and logging management events." + == "No CloudTrail trails enabled and logging management events were found." ) @mock_aws @@ -299,3 +300,36 @@ class Test_cloudtrail_multi_region_enabled_logging_management_events: check = cloudtrail_multi_region_enabled_logging_management_events() result = check.execute() assert len(result) == 0 + + def test_no_trails_two_regions(self): + from prowler.providers.aws.services.cloudtrail.cloudtrail_service import ( + Cloudtrail, + ) + + audit_info = set_mocked_aws_audit_info( + [AWS_REGION_US_EAST_1, AWS_REGION_US_EAST_2] + ) + + with mock.patch( + "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", + new=audit_info, + ): + with mock.patch( + "prowler.providers.aws.services.cloudtrail.cloudtrail_multi_region_enabled_logging_management_events.cloudtrail_multi_region_enabled_logging_management_events.cloudtrail_client", + new=Cloudtrail(audit_info), + ): + # Test Check + from prowler.providers.aws.services.cloudtrail.cloudtrail_multi_region_enabled_logging_management_events.cloudtrail_multi_region_enabled_logging_management_events import ( + cloudtrail_multi_region_enabled_logging_management_events, + ) + + check = cloudtrail_multi_region_enabled_logging_management_events() + result = check.execute() + assert len(result) == 2 + for r in result: + assert r.resource_id == AWS_ACCOUNT_NUMBER + assert r.status == "FAIL" + assert ( + r.status_extended + == "No CloudTrail trails enabled and logging management events were found." + ) diff --git a/tests/providers/aws/services/cloudtrail/cloudtrail_service_test.py b/tests/providers/aws/services/cloudtrail/cloudtrail_service_test.py index 24ee6001aa..2c0cc03a1e 100644 --- a/tests/providers/aws/services/cloudtrail/cloudtrail_service_test.py +++ b/tests/providers/aws/services/cloudtrail/cloudtrail_service_test.py @@ -4,6 +4,7 @@ from moto import mock_aws from prowler.providers.aws.services.cloudtrail.cloudtrail_service import Cloudtrail from tests.providers.aws.audit_info_utils import ( AWS_ACCOUNT_NUMBER, + AWS_REGION_EU_SOUTH_2, AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1, set_mocked_aws_audit_info, @@ -50,23 +51,14 @@ class Test_Cloudtrail_Service: @mock_aws def test_describe_trails(self): + # USA cloudtrail_client_us_east_1 = client( "cloudtrail", region_name=AWS_REGION_US_EAST_1 ) s3_client_us_east_1 = client("s3", region_name=AWS_REGION_US_EAST_1) - cloudtrail_client_eu_west_1 = client( - "cloudtrail", region_name=AWS_REGION_EU_WEST_1 - ) - s3_client_eu_west_1 = client("s3", region_name=AWS_REGION_EU_WEST_1) trail_name_us = "trail_test_us" bucket_name_us = "bucket_test_us" - trail_name_eu = "trail_test_eu" - bucket_name_eu = "bucket_test_eu" s3_client_us_east_1.create_bucket(Bucket=bucket_name_us) - s3_client_eu_west_1.create_bucket( - Bucket=bucket_name_eu, - CreateBucketConfiguration={"LocationConstraint": AWS_REGION_EU_WEST_1}, - ) cloudtrail_client_us_east_1.create_trail( Name=trail_name_us, S3BucketName=bucket_name_us, @@ -75,6 +67,18 @@ class Test_Cloudtrail_Service: {"Key": "test", "Value": "test"}, ], ) + + # IRELAND + cloudtrail_client_eu_west_1 = client( + "cloudtrail", region_name=AWS_REGION_EU_WEST_1 + ) + s3_client_eu_west_1 = client("s3", region_name=AWS_REGION_EU_WEST_1) + trail_name_eu = "trail_test_eu" + bucket_name_eu = "bucket_test_eu" + s3_client_eu_west_1.create_bucket( + Bucket=bucket_name_eu, + CreateBucketConfiguration={"LocationConstraint": AWS_REGION_EU_WEST_1}, + ) cloudtrail_client_eu_west_1.create_trail( Name=trail_name_eu, S3BucketName=bucket_name_eu, @@ -83,19 +87,60 @@ class Test_Cloudtrail_Service: {"Key": "test", "Value": "test"}, ], ) + # SPAIN + cloudtrail_client_eu_south_2 = client( + "cloudtrail", region_name=AWS_REGION_EU_SOUTH_2 + ) + s3_client_eu_south_2 = client("s3", region_name=AWS_REGION_EU_SOUTH_2) + trail_name_sp = "trail_test_sp" + bucket_name_sp = "bucket_test_sp" + s3_client_eu_south_2.create_bucket( + Bucket=bucket_name_sp, + CreateBucketConfiguration={"LocationConstraint": AWS_REGION_EU_SOUTH_2}, + ) + cloudtrail_client_eu_south_2.create_trail( + Name=trail_name_sp, + S3BucketName=bucket_name_sp, + IsMultiRegionTrail=True, + TagsList=[ + {"Key": "test", "Value": "test"}, + ], + ) + + # We are not going to include AWS_REGION_EU_SOUTH_2 in the audited + # regions, but that trail is regional so it'll appear audit_info = set_mocked_aws_audit_info( [AWS_REGION_US_EAST_1, AWS_REGION_EU_WEST_1] ) cloudtrail = Cloudtrail(audit_info) - assert len(cloudtrail.trails) == 2 + assert len(cloudtrail.trails) == 3 for trail in cloudtrail.trails.values(): - if trail.name: - assert trail.name == trail_name_us or trail.name == trail_name_eu + if trail.name == trail_name_us: assert not trail.is_multiregion - assert ( - trail.home_region == AWS_REGION_US_EAST_1 - or trail.home_region == AWS_REGION_EU_WEST_1 - ) + assert trail.home_region == AWS_REGION_US_EAST_1 + assert trail.region == AWS_REGION_US_EAST_1 + assert not trail.is_logging + assert not trail.log_file_validation_enabled + assert not trail.latest_cloudwatch_delivery_time + assert trail.s3_bucket == bucket_name_us + assert trail.tags == [ + {"Key": "test", "Value": "test"}, + ] + if trail.name == trail_name_eu: + assert not trail.is_multiregion + assert trail.home_region == AWS_REGION_EU_WEST_1 + assert trail.region == AWS_REGION_EU_WEST_1 + assert not trail.is_logging + assert not trail.log_file_validation_enabled + assert not trail.latest_cloudwatch_delivery_time + assert trail.s3_bucket == bucket_name_eu + assert trail.tags == [ + {"Key": "test", "Value": "test"}, + ] + if trail.name == trail_name_sp: + assert trail.is_multiregion + assert trail.home_region == AWS_REGION_EU_SOUTH_2 + # The region is the first audited region since the trail home region is not audited assert ( trail.region == AWS_REGION_US_EAST_1 or trail.region == AWS_REGION_EU_WEST_1 @@ -103,13 +148,9 @@ class Test_Cloudtrail_Service: assert not trail.is_logging assert not trail.log_file_validation_enabled assert not trail.latest_cloudwatch_delivery_time - assert ( - trail.s3_bucket == bucket_name_eu - or trail.s3_bucket == bucket_name_us - ) - assert trail.tags == [ - {"Key": "test", "Value": "test"}, - ] + assert trail.s3_bucket == bucket_name_sp + # No tags since the trail region is not audited and the tags are retrieved from the regional endpoint + assert trail.tags == [] @mock_aws def test_status_trails(self): diff --git a/tests/providers/aws/services/rds/rds_instance_transport_encrypted/rds_instance_transport_encrypted_test.py b/tests/providers/aws/services/rds/rds_instance_transport_encrypted/rds_instance_transport_encrypted_test.py index 85bcd6eea2..0079d19214 100644 --- a/tests/providers/aws/services/rds/rds_instance_transport_encrypted/rds_instance_transport_encrypted_test.py +++ b/tests/providers/aws/services/rds/rds_instance_transport_encrypted/rds_instance_transport_encrypted_test.py @@ -11,6 +11,9 @@ from tests.providers.aws.audit_info_utils import ( ) make_api_call = botocore.client.BaseClient._make_api_call +cluster_arn = ( + f"arn:aws:rds:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:cluster:db-cluster-1" +) def mock_make_api_call(self, operation_name, kwarg): @@ -160,10 +163,7 @@ class Test_rds_instance_transport_encrypted: ) assert result[0].resource_id == "db-cluster-1" assert result[0].region == AWS_REGION_US_EAST_1 - assert ( - result[0].resource_arn - == f"arn:aws:rds:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:cluster:db-cluster-1" - ) + assert result[0].resource_arn == cluster_arn assert result[0].resource_tags == [] @mock_aws @@ -433,16 +433,6 @@ class Test_rds_instance_transport_encrypted: MasterUserPassword="password", Tags=[], ) - conn.modify_db_parameter_group( - DBParameterGroupName="test", - Parameters=[ - { - "ParameterName": "rds.force_ssl", - "ParameterValue": "1", - "ApplyMethod": "immediate", - }, - ], - ) from prowler.providers.aws.services.rds.rds_service import RDS audit_info = set_mocked_aws_audit_info([AWS_REGION_US_EAST_1]) @@ -454,12 +444,14 @@ class Test_rds_instance_transport_encrypted: with mock.patch( "prowler.providers.aws.services.rds.rds_instance_transport_encrypted.rds_instance_transport_encrypted.rds_client", new=RDS(audit_info), - ): + ) as rds_client: # Test Check from prowler.providers.aws.services.rds.rds_instance_transport_encrypted.rds_instance_transport_encrypted import ( rds_instance_transport_encrypted, ) + # Change DB Cluster parameter group to support SSL since Moto does not support it + rds_client.db_clusters[cluster_arn].require_secure_transport = "ON" check = rds_instance_transport_encrypted() result = check.execute() @@ -471,10 +463,7 @@ class Test_rds_instance_transport_encrypted: ) assert result[0].resource_id == "db-cluster-1" assert result[0].region == AWS_REGION_US_EAST_1 - assert ( - result[0].resource_arn - == f"arn:aws:rds:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:cluster:db-cluster-1" - ) + assert result[0].resource_arn == cluster_arn assert result[0].resource_tags == [] @mock_aws @@ -517,12 +506,14 @@ class Test_rds_instance_transport_encrypted: with mock.patch( "prowler.providers.aws.services.rds.rds_instance_transport_encrypted.rds_instance_transport_encrypted.rds_client", new=RDS(audit_info), - ): + ) as rds_client: # Test Check from prowler.providers.aws.services.rds.rds_instance_transport_encrypted.rds_instance_transport_encrypted import ( rds_instance_transport_encrypted, ) + # Change DB Cluster parameter group to support SSL since Moto does not support it + rds_client.db_clusters[cluster_arn].require_secure_transport = "ON" check = rds_instance_transport_encrypted() result = check.execute() @@ -534,8 +525,5 @@ class Test_rds_instance_transport_encrypted: ) assert result[0].resource_id == "db-cluster-1" assert result[0].region == AWS_REGION_US_EAST_1 - assert ( - result[0].resource_arn - == f"arn:aws:rds:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:cluster:db-cluster-1" - ) + assert result[0].resource_arn == cluster_arn assert result[0].resource_tags == [] diff --git a/tests/providers/aws/services/rds/rds_service_test.py b/tests/providers/aws/services/rds/rds_service_test.py index 6f45e11b10..6dfb2f7172 100644 --- a/tests/providers/aws/services/rds/rds_service_test.py +++ b/tests/providers/aws/services/rds/rds_service_test.py @@ -183,8 +183,8 @@ class Test_RDS_Service: def test__describe_db_clusters__(self): conn = client("rds", region_name=AWS_REGION_US_EAST_1) cluster_id = "db-master-1" - conn.create_db_parameter_group( - DBParameterGroupName="test", + conn.create_db_cluster_parameter_group( + DBClusterParameterGroupName="test", DBParameterGroupFamily="default.postgres9.3", Description="test parameter group", ) @@ -232,6 +232,8 @@ class Test_RDS_Service: {"Key": "test", "Value": "test"}, ] assert rds.db_clusters[db_cluster_arn].parameter_group == "test" + assert rds.db_clusters[db_cluster_arn].force_ssl == "0" + assert rds.db_clusters[db_cluster_arn].require_secure_transport == "OFF" # Test RDS Describe DB Cluster Snapshots @mock_aws