From 78f0b823a989fb01fa347dc0551a27da62feae76 Mon Sep 17 00:00:00 2001 From: Sergio Garcia <38561120+sergargar@users.noreply.github.com> Date: Tue, 1 Aug 2023 11:24:58 +0200 Subject: [PATCH] fix(s3_bucket_level_public_access_block): check s3 public access block at account level (#2653) --- .../s3_bucket_level_public_access_block.py | 12 +- ...3_bucket_level_public_access_block_test.py | 221 +++++++++++++----- 2 files changed, 176 insertions(+), 57 deletions(-) diff --git a/prowler/providers/aws/services/s3/s3_bucket_level_public_access_block/s3_bucket_level_public_access_block.py b/prowler/providers/aws/services/s3/s3_bucket_level_public_access_block/s3_bucket_level_public_access_block.py index ddf71d87..dbfbfcfd 100644 --- a/prowler/providers/aws/services/s3/s3_bucket_level_public_access_block/s3_bucket_level_public_access_block.py +++ b/prowler/providers/aws/services/s3/s3_bucket_level_public_access_block/s3_bucket_level_public_access_block.py @@ -1,5 +1,6 @@ from prowler.lib.check.models import Check, Check_Report_AWS from prowler.providers.aws.services.s3.s3_client import s3_client +from prowler.providers.aws.services.s3.s3control_client import s3control_client class s3_bucket_level_public_access_block(Check): @@ -18,7 +19,14 @@ class s3_bucket_level_public_access_block(Check): bucket.public_access_block.ignore_public_acls and bucket.public_access_block.restrict_public_buckets ): - report.status = "FAIL" - report.status_extended = f"Block Public Access is not configured for the S3 Bucket {bucket.name}." + if ( + s3control_client.account_public_access_block + and s3control_client.account_public_access_block.ignore_public_acls + and s3control_client.account_public_access_block.restrict_public_buckets + ): + report.status_extended = f"Block Public Access is configured for the S3 Bucket {bucket.name} at account {s3_client.audited_account} level." + else: + report.status = "FAIL" + report.status_extended = f"Block Public Access is not configured for the S3 Bucket {bucket.name}." findings.append(report) return findings diff --git a/tests/providers/aws/services/s3/s3_bucket_level_public_access_block/s3_bucket_level_public_access_block_test.py b/tests/providers/aws/services/s3/s3_bucket_level_public_access_block/s3_bucket_level_public_access_block_test.py index 9230e20c..f657b28c 100644 --- a/tests/providers/aws/services/s3/s3_bucket_level_public_access_block/s3_bucket_level_public_access_block_test.py +++ b/tests/providers/aws/services/s3/s3_bucket_level_public_access_block/s3_bucket_level_public_access_block_test.py @@ -2,7 +2,7 @@ from re import search from unittest import mock from boto3 import client, session -from moto import mock_s3 +from moto import mock_s3, mock_s3control from prowler.providers.aws.lib.audit_info.models import AWS_Audit_Info from prowler.providers.common.models import Audit_Metadata @@ -47,7 +47,7 @@ class Test_s3_bucket_level_public_access_block: @mock_s3 def test_no_buckets(self): - from prowler.providers.aws.services.s3.s3_service import S3 + from prowler.providers.aws.services.s3.s3_service import S3, S3Control audit_info = self.set_mocked_audit_info() @@ -59,17 +59,22 @@ class Test_s3_bucket_level_public_access_block: "prowler.providers.aws.services.s3.s3_bucket_level_public_access_block.s3_bucket_level_public_access_block.s3_client", new=S3(audit_info), ): - # Test Check - from prowler.providers.aws.services.s3.s3_bucket_level_public_access_block.s3_bucket_level_public_access_block import ( - s3_bucket_level_public_access_block, - ) + with mock.patch( + "prowler.providers.aws.services.s3.s3_bucket_level_public_access_block.s3_bucket_level_public_access_block.s3control_client", + new=S3Control(audit_info), + ): + # Test Check + from prowler.providers.aws.services.s3.s3_bucket_level_public_access_block.s3_bucket_level_public_access_block import ( + s3_bucket_level_public_access_block, + ) - check = s3_bucket_level_public_access_block() - result = check.execute() + check = s3_bucket_level_public_access_block() + result = check.execute() - assert len(result) == 0 + assert len(result) == 0 @mock_s3 + @mock_s3control def test_bucket_without_public_block(self): s3_client = client("s3", region_name=AWS_REGION) bucket_name_us = "bucket_test_us" @@ -83,7 +88,17 @@ class Test_s3_bucket_level_public_access_block: "RestrictPublicBuckets": False, }, ) - from prowler.providers.aws.services.s3.s3_service import S3 + s3control_client = client("s3control", region_name=AWS_REGION) + s3control_client.put_public_access_block( + AccountId=AWS_ACCOUNT_NUMBER, + PublicAccessBlockConfiguration={ + "BlockPublicAcls": False, + "IgnorePublicAcls": False, + "BlockPublicPolicy": False, + "RestrictPublicBuckets": False, + }, + ) + from prowler.providers.aws.services.s3.s3_service import S3, S3Control audit_info = self.set_mocked_audit_info() @@ -95,28 +110,33 @@ class Test_s3_bucket_level_public_access_block: "prowler.providers.aws.services.s3.s3_bucket_level_public_access_block.s3_bucket_level_public_access_block.s3_client", new=S3(audit_info), ): - # Test Check - from prowler.providers.aws.services.s3.s3_bucket_level_public_access_block.s3_bucket_level_public_access_block import ( - s3_bucket_level_public_access_block, - ) + with mock.patch( + "prowler.providers.aws.services.s3.s3_bucket_level_public_access_block.s3_bucket_level_public_access_block.s3control_client", + new=S3Control(audit_info), + ): + # Test Check + from prowler.providers.aws.services.s3.s3_bucket_level_public_access_block.s3_bucket_level_public_access_block import ( + s3_bucket_level_public_access_block, + ) - check = s3_bucket_level_public_access_block() - result = check.execute() + check = s3_bucket_level_public_access_block() + result = check.execute() - assert len(result) == 1 - assert result[0].status == "FAIL" - assert search( - "Block Public Access is not configured", - result[0].status_extended, - ) - assert result[0].resource_id == bucket_name_us - assert ( - result[0].resource_arn - == f"arn:{audit_info.audited_partition}:s3:::{bucket_name_us}" - ) - assert result[0].region == AWS_REGION + assert len(result) == 1 + assert result[0].status == "FAIL" + assert search( + "Block Public Access is not configured", + result[0].status_extended, + ) + assert result[0].resource_id == bucket_name_us + assert ( + result[0].resource_arn + == f"arn:{audit_info.audited_partition}:s3:::{bucket_name_us}" + ) + assert result[0].region == AWS_REGION @mock_s3 + @mock_s3control def test_bucket_public_block(self): s3_client = client("s3", region_name=AWS_REGION) bucket_name_us = "bucket_test_us" @@ -130,7 +150,17 @@ class Test_s3_bucket_level_public_access_block: "RestrictPublicBuckets": True, }, ) - from prowler.providers.aws.services.s3.s3_service import S3 + s3control_client = client("s3control", region_name=AWS_REGION) + s3control_client.put_public_access_block( + AccountId=AWS_ACCOUNT_NUMBER, + PublicAccessBlockConfiguration={ + "BlockPublicAcls": False, + "IgnorePublicAcls": False, + "BlockPublicPolicy": False, + "RestrictPublicBuckets": False, + }, + ) + from prowler.providers.aws.services.s3.s3_service import S3, S3Control audit_info = self.set_mocked_audit_info() @@ -142,28 +172,95 @@ class Test_s3_bucket_level_public_access_block: "prowler.providers.aws.services.s3.s3_bucket_level_public_access_block.s3_bucket_level_public_access_block.s3_client", new=S3(audit_info), ): - # Test Check - from prowler.providers.aws.services.s3.s3_bucket_level_public_access_block.s3_bucket_level_public_access_block import ( - s3_bucket_level_public_access_block, - ) + with mock.patch( + "prowler.providers.aws.services.s3.s3_bucket_level_public_access_block.s3_bucket_level_public_access_block.s3control_client", + new=S3Control(audit_info), + ): + # Test Check + from prowler.providers.aws.services.s3.s3_bucket_level_public_access_block.s3_bucket_level_public_access_block import ( + s3_bucket_level_public_access_block, + ) - check = s3_bucket_level_public_access_block() - result = check.execute() + check = s3_bucket_level_public_access_block() + result = check.execute() - assert len(result) == 1 - assert result[0].status == "PASS" - assert search( - "Block Public Access is configured", - result[0].status_extended, - ) - assert result[0].resource_id == bucket_name_us - assert ( - result[0].resource_arn - == f"arn:{audit_info.audited_partition}:s3:::{bucket_name_us}" - ) - assert result[0].region == AWS_REGION + assert len(result) == 1 + assert result[0].status == "PASS" + assert search( + "Block Public Access is configured", + result[0].status_extended, + ) + assert result[0].resource_id == bucket_name_us + assert ( + result[0].resource_arn + == f"arn:{audit_info.audited_partition}:s3:::{bucket_name_us}" + ) + assert result[0].region == AWS_REGION @mock_s3 + @mock_s3control + def test_bucket_public_block_at_account(self): + s3_client = client("s3", region_name=AWS_REGION) + bucket_name_us = "bucket_test_us" + s3_client.create_bucket(Bucket=bucket_name_us) + s3_client.put_public_access_block( + Bucket=bucket_name_us, + PublicAccessBlockConfiguration={ + "BlockPublicAcls": False, + "IgnorePublicAcls": False, + "BlockPublicPolicy": False, + "RestrictPublicBuckets": False, + }, + ) + s3control_client = client("s3control", region_name=AWS_REGION) + s3control_client.put_public_access_block( + AccountId=AWS_ACCOUNT_NUMBER, + PublicAccessBlockConfiguration={ + "BlockPublicAcls": True, + "IgnorePublicAcls": True, + "BlockPublicPolicy": True, + "RestrictPublicBuckets": True, + }, + ) + from prowler.providers.aws.services.s3.s3_service import S3, S3Control + + audit_info = self.set_mocked_audit_info() + + with mock.patch( + "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", + new=audit_info, + ): + with mock.patch( + "prowler.providers.aws.services.s3.s3_bucket_level_public_access_block.s3_bucket_level_public_access_block.s3_client", + new=S3(audit_info), + ): + with mock.patch( + "prowler.providers.aws.services.s3.s3_bucket_level_public_access_block.s3_bucket_level_public_access_block.s3control_client", + new=S3Control(audit_info), + ): + # Test Check + from prowler.providers.aws.services.s3.s3_bucket_level_public_access_block.s3_bucket_level_public_access_block import ( + s3_bucket_level_public_access_block, + ) + + check = s3_bucket_level_public_access_block() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert search( + f"Block Public Access is configured for the S3 Bucket {bucket_name_us} at account {AWS_ACCOUNT_NUMBER} level.", + result[0].status_extended, + ) + assert result[0].resource_id == bucket_name_us + assert ( + result[0].resource_arn + == f"arn:{audit_info.audited_partition}:s3:::{bucket_name_us}" + ) + assert result[0].region == AWS_REGION + + @mock_s3 + @mock_s3control def test_bucket_can_not_retrieve_public_access_block(self): s3_client = client("s3", region_name=AWS_REGION) bucket_name_us = "bucket_test_us" @@ -177,7 +274,17 @@ class Test_s3_bucket_level_public_access_block: "RestrictPublicBuckets": True, }, ) - from prowler.providers.aws.services.s3.s3_service import S3 + s3control_client = client("s3control", region_name=AWS_REGION) + s3control_client.put_public_access_block( + AccountId=AWS_ACCOUNT_NUMBER, + PublicAccessBlockConfiguration={ + "BlockPublicAcls": False, + "IgnorePublicAcls": False, + "BlockPublicPolicy": False, + "RestrictPublicBuckets": False, + }, + ) + from prowler.providers.aws.services.s3.s3_service import S3, S3Control audit_info = self.set_mocked_audit_info() @@ -193,12 +300,16 @@ class Test_s3_bucket_level_public_access_block: "prowler.providers.aws.services.s3.s3_bucket_level_public_access_block.s3_bucket_level_public_access_block.s3_client", new=s3, ): - # Test Check - from prowler.providers.aws.services.s3.s3_bucket_level_public_access_block.s3_bucket_level_public_access_block import ( - s3_bucket_level_public_access_block, - ) + with mock.patch( + "prowler.providers.aws.services.s3.s3_bucket_level_public_access_block.s3_bucket_level_public_access_block.s3control_client", + new=S3Control(audit_info), + ): + # Test Check + from prowler.providers.aws.services.s3.s3_bucket_level_public_access_block.s3_bucket_level_public_access_block import ( + s3_bucket_level_public_access_block, + ) - check = s3_bucket_level_public_access_block() - result = check.execute() + check = s3_bucket_level_public_access_block() + result = check.execute() - assert len(result) == 0 + assert len(result) == 0