Skip to content

Commit

Permalink
chore(tests): Improve CloudTrail tests checking for multiregional tra…
Browse files Browse the repository at this point in the history
…ils (#4177)

Co-authored-by: Sergio <[email protected]>
  • Loading branch information
jfagoagas and sergargar authored Jun 26, 2024
1 parent e5c911a commit cee5064
Show file tree
Hide file tree
Showing 19 changed files with 829 additions and 284 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def execute(self):
# check if trail bucket is a cross account bucket
if not trail_bucket_is_in_account:
report.status = "MANUAL"
report.status_extended = f"Trail {trail.name} bucket ({trail_bucket}) is a cross-account bucket in another account out of Prowler's permissions scope, please check it manually."
report.status_extended = f"Trail {trail.name} bucket ({trail_bucket}) is a cross-account bucket or out of Prowler's audit scope, please check it manually."

findings.append(report)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ def execute(self):
report.resource_tags = trail.tags
report.status = "PASS"
if trail.is_multiregion:
report.status_extended = f"Multiregion trail {trail.name} has been logging the last 24h."
report.status_extended = f"Multiregion trail {trail.name} has been logging in the last 24h."
else:
report.status_extended = f"Single region trail {trail.name} has been logging the last 24h."
report.status_extended = f"Single region trail {trail.name} has been logging in the last 24h."
if trail.latest_cloudwatch_delivery_time:
last_log_delivery = (
datetime.now().replace(tzinfo=timezone.utc)
Expand All @@ -34,15 +34,15 @@ def execute(self):
):
report.status = "FAIL"
if trail.is_multiregion:
report.status_extended = f"Multiregion trail {trail.name} is not logging in the last 24h."
report.status_extended = f"Multiregion trail {trail.name} has not been logging in the last 24h."
else:
report.status_extended = f"Single region trail {trail.name} is not logging in the last 24h."
report.status_extended = f"Single region trail {trail.name} has not been logging in the last 24h."
else:
report.status = "FAIL"
if trail.is_multiregion:
report.status_extended = f"Multiregion trail {trail.name} is not logging in the last 24h or not configured to deliver logs."
report.status_extended = f"Multiregion trail {trail.name} has not been logging in the last 24h or is not configured to deliver logs."
else:
report.status_extended = f"Single region trail {trail.name} is not logging in the last 24h or not configured to deliver logs."
report.status_extended = f"Single region trail {trail.name} has not been logging in the last 24h or is not configured to deliver logs."
findings.append(report)

return findings
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ def execute(self):
report.resource_tags = trail.tags
report.status = "FAIL"
if trail.is_multiregion:
report.status_extended = f"Multiregion trail {trail.name} log file validation disabled."
report.status_extended = f"Multiregion trail {trail.name} has log file validation disabled."
else:
report.status_extended = f"Single region trail {trail.name} log file validation disabled."
report.status_extended = f"Single region trail {trail.name} has log file validation disabled."
if trail.log_file_validation_enabled:
report.status = "PASS"
if trail.is_multiregion:
report.status_extended = f"Multiregion trail {trail.name} log file validation enabled."
report.status_extended = f"Multiregion trail {trail.name} has log file validation enabled."
else:
report.status_extended = f"Single region trail {trail.name} log file validation enabled."
report.status_extended = f"Single region trail {trail.name} has log file validation enabled."
findings.append(report)

return findings
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ def execute(self):
if bucket.logging:
report.status = "PASS"
if trail.is_multiregion:
report.status_extended = f"Multiregion trail {trail.name} S3 bucket access logging is enabled for bucket {trail_bucket}."
report.status_extended = f"Multiregion Trail {trail.name} S3 bucket access logging is enabled for bucket {trail_bucket}."
else:
report.status_extended = f"Single region trail {trail.name} S3 bucket access logging is enabled for bucket {trail_bucket}."
report.status_extended = f"Single region Trail {trail.name} S3 bucket access logging is enabled for bucket {trail_bucket}."
break

# check if trail is delivering logs in a cross account bucket
# check if trail is delivering logs in a cross account bucket or another region out of Prowler's audit scope
if not trail_bucket_is_in_account:
report.status = "MANUAL"
report.status_extended = f"Trail {trail.name} is delivering logs in a cross-account bucket {trail_bucket} in another account out of Prowler's permissions scope, please check it manually."
report.status_extended = f"Trail {trail.name} is delivering logs to bucket {trail_bucket} which is a cross-account bucket or out of Prowler's audit scope, please check it manually."
findings.append(report)

return findings
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def execute(self):
# check if trail bucket is a cross account bucket
if not trail_bucket_is_in_account:
report.status = "MANUAL"
report.status_extended = f"Trail {trail.name} bucket ({trail_bucket}) is a cross-account bucket in another account out of Prowler's permissions scope, please check it manually."
report.status_extended = f"Trail {trail.name} bucket ({trail_bucket}) is a cross-account bucket or out of Prowler's audit scope, please check it manually."
findings.append(report)

return findings
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def execute(self):
else:
report.status = "FAIL"
report.status_extended = (
"No CloudTrail trails enabled and logging were found."
"No CloudTrail trails enabled with logging were found."
)
report.resource_arn = (
cloudtrail_client.__get_trail_arn_template__(region)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ def execute(self):
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
report.resource_arn = cloudtrail_client.__get_trail_arn_template__(
region
)
trail_is_logging_management_events = False
for trail in cloudtrail_client.trails.values():
if trail.region == region or trail.is_multiregion:
Expand Down Expand Up @@ -48,6 +50,7 @@ def execute(self):
report.resource_id = trail.name
report.resource_arn = trail.arn
report.resource_tags = trail.tags
report.region = trail.home_region
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."
Expand Down
1 change: 1 addition & 0 deletions prowler/providers/aws/services/s3/s3_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ def __list_buckets__(self, provider):
self.regions_with_buckets.append(bucket_region)
# Check if there are filter regions
if provider.identity.audited_regions:
# FIXME: what if the bucket comes from a CloudTrail bucket in another audited region
if bucket_region in provider.identity.audited_regions:
buckets.append(
Bucket(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ def test_trails_with_no_mfa_bucket_cross(self):
assert result[0].status == "MANUAL"
assert (
result[0].status_extended
== f"Trail {trail_name_us} bucket ({bucket_name_us}) is a cross-account bucket in another account out of Prowler's permissions scope, please check it manually."
== f"Trail {trail_name_us} bucket ({bucket_name_us}) is a cross-account bucket or out of Prowler's audit scope, please check it manually."
)
assert result[0].resource_id == trail_name_us
assert result[0].region == AWS_REGION_US_EAST_1
Expand Down Expand Up @@ -248,7 +248,7 @@ def test_trails_with_mfa_bucket_cross(self):
assert result[0].status == "MANUAL"
assert (
result[0].status_extended
== f"Trail {trail_name_us} bucket ({bucket_name_us}) is a cross-account bucket in another account out of Prowler's permissions scope, please check it manually."
== f"Trail {trail_name_us} bucket ({bucket_name_us}) is a cross-account bucket or out of Prowler's audit scope, please check it manually."
)
assert result[0].resource_id == trail_name_us
assert result[0].region == AWS_REGION_US_EAST_1
Expand Down Expand Up @@ -286,3 +286,49 @@ def test_access_denied(self):
check = cloudtrail_bucket_requires_mfa_delete()
result = check.execute()
assert len(result) == 0

@mock_aws
def test_trail_multi_region_auditing_other_region(self):
aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1])

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)
trail_name_us = "trail_test_us"
bucket_name_us = "bucket_test_us"
s3_client_us_east_1.create_bucket(Bucket=bucket_name_us)
trail_us = cloudtrail_client_us_east_1.create_trail(
Name=trail_name_us, S3BucketName=bucket_name_us, IsMultiRegionTrail=True
)
cloudtrail_client_us_east_1.start_logging(Name=trail_name_us)
cloudtrail_client_us_east_1.get_trail_status(Name=trail_name_us)

with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
), mock.patch(
"prowler.providers.aws.services.cloudtrail.cloudtrail_bucket_requires_mfa_delete.cloudtrail_bucket_requires_mfa_delete.cloudtrail_client",
new=Cloudtrail(aws_provider),
), mock.patch(
"prowler.providers.aws.services.cloudtrail.cloudtrail_bucket_requires_mfa_delete.cloudtrail_bucket_requires_mfa_delete.s3_client",
new=S3(aws_provider),
):
# Test Check
from prowler.providers.aws.services.cloudtrail.cloudtrail_bucket_requires_mfa_delete.cloudtrail_bucket_requires_mfa_delete import (
cloudtrail_bucket_requires_mfa_delete,
)

check = cloudtrail_bucket_requires_mfa_delete()
result = check.execute()
assert len(result) == 1
# This is MANUAL since S3 bucket is in another region not audited
assert result[0].status == "MANUAL"
assert (
result[0].status_extended
== f"Trail {trail_name_us} bucket ({bucket_name_us}) is a cross-account bucket or out of Prowler's audit scope, please check it manually."
)
assert result[0].resource_id == trail_name_us
assert result[0].region == AWS_REGION_US_EAST_1
assert result[0].resource_arn == trail_us["TrailARN"]
assert result[0].resource_tags == []
Loading

0 comments on commit cee5064

Please sign in to comment.