From 26c70976c09734b7de491168c896f2102b7e2d92 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Thu, 12 Dec 2024 16:10:43 +0100 Subject: [PATCH] feat(s3): add new fixer `s3_bucket_public_write_acl_fixer` (#5855) --- .../s3_bucket_public_write_acl_fixer.py | 36 ++ .../s3_bucket_public_write_acl_fixer_test.py | 432 ++++++++++++++++++ 2 files changed, 468 insertions(+) create mode 100644 prowler/providers/aws/services/s3/s3_bucket_public_write_acl/s3_bucket_public_write_acl_fixer.py create mode 100644 tests/providers/aws/services/s3/s3_bucket_public_write_acl/s3_bucket_public_write_acl_fixer_test.py diff --git a/prowler/providers/aws/services/s3/s3_bucket_public_write_acl/s3_bucket_public_write_acl_fixer.py b/prowler/providers/aws/services/s3/s3_bucket_public_write_acl/s3_bucket_public_write_acl_fixer.py new file mode 100644 index 0000000000..e27787a967 --- /dev/null +++ b/prowler/providers/aws/services/s3/s3_bucket_public_write_acl/s3_bucket_public_write_acl_fixer.py @@ -0,0 +1,36 @@ +from prowler.lib.logger import logger +from prowler.providers.aws.services.s3.s3_client import s3_client + + +def fixer(resource_id: str, region: str) -> bool: + """ + Modify the S3 bucket ACL to restrict public write access. + Specifically, this fixer sets the ACL of the bucket to 'private' to prevent + public write access to the S3 bucket. Requires the s3:PutBucketAcl permission. + Permissions: + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": "s3:PutBucketAcl", + "Resource": "*" + } + ] + } + Args: + resource_id (str): The S3 bucket id. + region (str): AWS region where the S3 bucket exists. + Returns: + bool: True if the operation is successful (bucket access is updated), False otherwise. + """ + try: + regional_client = s3_client.regional_clients[region] + regional_client.put_bucket_acl(Bucket=resource_id, ACL="private") + except Exception as error: + logger.error( + f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return False + else: + return True diff --git a/tests/providers/aws/services/s3/s3_bucket_public_write_acl/s3_bucket_public_write_acl_fixer_test.py b/tests/providers/aws/services/s3/s3_bucket_public_write_acl/s3_bucket_public_write_acl_fixer_test.py new file mode 100644 index 0000000000..768ad12f79 --- /dev/null +++ b/tests/providers/aws/services/s3/s3_bucket_public_write_acl/s3_bucket_public_write_acl_fixer_test.py @@ -0,0 +1,432 @@ +from unittest import mock + +from boto3 import client +from moto import mock_aws + +from tests.providers.aws.utils import ( + AWS_ACCOUNT_NUMBER, + AWS_REGION_US_EAST_1, + set_mocked_aws_provider, +) + + +class Test_s3_bucket_public_write_acl_fixer: + @mock_aws + def test_bucket_public_write_ACL_AllUsers_WRITE(self): + s3_client = client("s3", region_name=AWS_REGION_US_EAST_1) + bucket_name_us = "bucket_test_us" + s3_client.create_bucket(Bucket=bucket_name_us) + bucket_owner = s3_client.get_bucket_acl(Bucket=bucket_name_us)["Owner"] + # Generate S3Control Client + s3control_client = client("s3control", region_name=AWS_REGION_US_EAST_1) + s3control_client.put_public_access_block( + AccountId=AWS_ACCOUNT_NUMBER, + PublicAccessBlockConfiguration={ + "BlockPublicAcls": False, + "IgnorePublicAcls": False, + "BlockPublicPolicy": False, + "RestrictPublicBuckets": False, + }, + ) + s3_client.put_public_access_block( + Bucket=bucket_name_us, + PublicAccessBlockConfiguration={ + "BlockPublicAcls": False, + "IgnorePublicAcls": False, + "BlockPublicPolicy": False, + "RestrictPublicBuckets": False, + }, + ) + s3_client.put_bucket_acl( + Bucket=bucket_name_us, + AccessControlPolicy={ + "Grants": [ + { + "Grantee": { + "URI": "http://acs.amazonaws.com/groups/global/AllUsers", + "Type": "Group", + }, + "Permission": "WRITE", + }, + ], + "Owner": bucket_owner, + }, + ) + from prowler.providers.aws.services.s3.s3_service import S3 + + aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ): + with mock.patch( + "prowler.providers.aws.services.s3.s3_bucket_public_write_acl.s3_bucket_public_write_acl_fixer.s3_client", + new=S3(aws_provider), + ): + # Test Fixer + from prowler.providers.aws.services.s3.s3_bucket_public_write_acl.s3_bucket_public_write_acl_fixer import ( + fixer, + ) + + assert fixer(bucket_name_us, AWS_REGION_US_EAST_1) + + @mock_aws + def test_bucket_public_write_ACL_AllUsers_WRITE_ACP(self): + s3_client = client("s3", region_name=AWS_REGION_US_EAST_1) + bucket_name_us = "bucket_test_us" + s3_client.create_bucket(Bucket=bucket_name_us) + bucket_owner = s3_client.get_bucket_acl(Bucket=bucket_name_us)["Owner"] + # Generate S3Control Client + s3control_client = client("s3control", region_name=AWS_REGION_US_EAST_1) + s3control_client.put_public_access_block( + AccountId=AWS_ACCOUNT_NUMBER, + PublicAccessBlockConfiguration={ + "BlockPublicAcls": False, + "IgnorePublicAcls": False, + "BlockPublicPolicy": False, + "RestrictPublicBuckets": False, + }, + ) + s3_client.put_public_access_block( + Bucket=bucket_name_us, + PublicAccessBlockConfiguration={ + "BlockPublicAcls": False, + "IgnorePublicAcls": False, + "BlockPublicPolicy": False, + "RestrictPublicBuckets": False, + }, + ) + s3_client.put_bucket_acl( + Bucket=bucket_name_us, + AccessControlPolicy={ + "Grants": [ + { + "Grantee": { + "URI": "http://acs.amazonaws.com/groups/global/AllUsers", + "Type": "Group", + }, + "Permission": "WRITE_ACP", + }, + ], + "Owner": bucket_owner, + }, + ) + from prowler.providers.aws.services.s3.s3_service import S3 + + aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ): + with mock.patch( + "prowler.providers.aws.services.s3.s3_bucket_public_write_acl.s3_bucket_public_write_acl_fixer.s3_client", + new=S3(aws_provider), + ): + # Test Fixer + from prowler.providers.aws.services.s3.s3_bucket_public_write_acl.s3_bucket_public_write_acl_fixer import ( + fixer, + ) + + assert fixer(bucket_name_us, AWS_REGION_US_EAST_1) + + @mock_aws + def test_bucket_public_write_ACL_AllUsers_FULL_CONTROL(self): + s3_client = client("s3", region_name=AWS_REGION_US_EAST_1) + bucket_name_us = "bucket_test_us" + s3_client.create_bucket(Bucket=bucket_name_us) + bucket_owner = s3_client.get_bucket_acl(Bucket=bucket_name_us)["Owner"] + # Generate S3Control Client + s3control_client = client("s3control", region_name=AWS_REGION_US_EAST_1) + s3control_client.put_public_access_block( + AccountId=AWS_ACCOUNT_NUMBER, + PublicAccessBlockConfiguration={ + "BlockPublicAcls": False, + "IgnorePublicAcls": False, + "BlockPublicPolicy": False, + "RestrictPublicBuckets": False, + }, + ) + s3_client.put_public_access_block( + Bucket=bucket_name_us, + PublicAccessBlockConfiguration={ + "BlockPublicAcls": False, + "IgnorePublicAcls": False, + "BlockPublicPolicy": False, + "RestrictPublicBuckets": False, + }, + ) + s3_client.put_bucket_acl( + Bucket=bucket_name_us, + AccessControlPolicy={ + "Grants": [ + { + "Grantee": { + "URI": "http://acs.amazonaws.com/groups/global/AllUsers", + "Type": "Group", + }, + "Permission": "FULL_CONTROL", + }, + ], + "Owner": bucket_owner, + }, + ) + from prowler.providers.aws.services.s3.s3_service import S3 + + aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ): + with mock.patch( + "prowler.providers.aws.services.s3.s3_bucket_public_write_acl.s3_bucket_public_write_acl_fixer.s3_client", + new=S3(aws_provider), + ): + # Test Fixer + from prowler.providers.aws.services.s3.s3_bucket_public_write_acl.s3_bucket_public_write_acl_fixer import ( + fixer, + ) + + assert fixer(bucket_name_us, AWS_REGION_US_EAST_1) + + @mock_aws + def test_bucket_public_write_ACL_AuthenticatedUsers_WRITE(self): + s3_client = client("s3", region_name=AWS_REGION_US_EAST_1) + bucket_name_us = "bucket_test_us" + s3_client.create_bucket(Bucket=bucket_name_us) + bucket_owner = s3_client.get_bucket_acl(Bucket=bucket_name_us)["Owner"] + # Generate S3Control Client + s3control_client = client("s3control", region_name=AWS_REGION_US_EAST_1) + s3control_client.put_public_access_block( + AccountId=AWS_ACCOUNT_NUMBER, + PublicAccessBlockConfiguration={ + "BlockPublicAcls": False, + "IgnorePublicAcls": False, + "BlockPublicPolicy": False, + "RestrictPublicBuckets": False, + }, + ) + s3_client.put_public_access_block( + Bucket=bucket_name_us, + PublicAccessBlockConfiguration={ + "BlockPublicAcls": False, + "IgnorePublicAcls": False, + "BlockPublicPolicy": False, + "RestrictPublicBuckets": False, + }, + ) + s3_client.put_bucket_acl( + Bucket=bucket_name_us, + AccessControlPolicy={ + "Grants": [ + { + "Grantee": { + "URI": "http://acs.amazonaws.com/groups/global/AuthenticatedUsers", + "Type": "Group", + }, + "Permission": "WRITE", + }, + ], + "Owner": bucket_owner, + }, + ) + from prowler.providers.aws.services.s3.s3_service import S3 + + aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ): + with mock.patch( + "prowler.providers.aws.services.s3.s3_bucket_public_write_acl.s3_bucket_public_write_acl_fixer.s3_client", + new=S3(aws_provider), + ): + # Test Fixer + from prowler.providers.aws.services.s3.s3_bucket_public_write_acl.s3_bucket_public_write_acl_fixer import ( + fixer, + ) + + assert fixer(bucket_name_us, AWS_REGION_US_EAST_1) + + @mock_aws + def test_bucket_public_write_ACL_AuthenticatedUsers_WRITE_ACP(self): + s3_client = client("s3", region_name=AWS_REGION_US_EAST_1) + bucket_name_us = "bucket_test_us" + s3_client.create_bucket(Bucket=bucket_name_us) + bucket_owner = s3_client.get_bucket_acl(Bucket=bucket_name_us)["Owner"] + # Generate S3Control Client + s3control_client = client("s3control", region_name=AWS_REGION_US_EAST_1) + s3control_client.put_public_access_block( + AccountId=AWS_ACCOUNT_NUMBER, + PublicAccessBlockConfiguration={ + "BlockPublicAcls": False, + "IgnorePublicAcls": False, + "BlockPublicPolicy": False, + "RestrictPublicBuckets": False, + }, + ) + s3_client.put_public_access_block( + Bucket=bucket_name_us, + PublicAccessBlockConfiguration={ + "BlockPublicAcls": False, + "IgnorePublicAcls": False, + "BlockPublicPolicy": False, + "RestrictPublicBuckets": False, + }, + ) + s3_client.put_bucket_acl( + Bucket=bucket_name_us, + AccessControlPolicy={ + "Grants": [ + { + "Grantee": { + "URI": "http://acs.amazonaws.com/groups/global/AuthenticatedUsers", + "Type": "Group", + }, + "Permission": "WRITE_ACP", + }, + ], + "Owner": bucket_owner, + }, + ) + from prowler.providers.aws.services.s3.s3_service import S3 + + aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ): + with mock.patch( + "prowler.providers.aws.services.s3.s3_bucket_public_write_acl.s3_bucket_public_write_acl_fixer.s3_client", + new=S3(aws_provider), + ): + # Test Fixer + from prowler.providers.aws.services.s3.s3_bucket_public_write_acl.s3_bucket_public_write_acl_fixer import ( + fixer, + ) + + assert fixer(bucket_name_us, AWS_REGION_US_EAST_1) + + @mock_aws + def test_bucket_public_write_ACL_AuthenticatedUsers_FULL_CONTROL(self): + s3_client = client("s3", region_name=AWS_REGION_US_EAST_1) + bucket_name_us = "bucket_test_us" + s3_client.create_bucket(Bucket=bucket_name_us) + bucket_owner = s3_client.get_bucket_acl(Bucket=bucket_name_us)["Owner"] + # Generate S3Control Client + s3control_client = client("s3control", region_name=AWS_REGION_US_EAST_1) + s3control_client.put_public_access_block( + AccountId=AWS_ACCOUNT_NUMBER, + PublicAccessBlockConfiguration={ + "BlockPublicAcls": False, + "IgnorePublicAcls": False, + "BlockPublicPolicy": False, + "RestrictPublicBuckets": False, + }, + ) + s3_client.put_public_access_block( + Bucket=bucket_name_us, + PublicAccessBlockConfiguration={ + "BlockPublicAcls": False, + "IgnorePublicAcls": False, + "BlockPublicPolicy": False, + "RestrictPublicBuckets": False, + }, + ) + s3_client.put_bucket_acl( + Bucket=bucket_name_us, + AccessControlPolicy={ + "Grants": [ + { + "Grantee": { + "URI": "http://acs.amazonaws.com/groups/global/AuthenticatedUsers", + "Type": "Group", + }, + "Permission": "FULL_CONTROL", + }, + ], + "Owner": bucket_owner, + }, + ) + from prowler.providers.aws.services.s3.s3_service import S3 + + aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ): + with mock.patch( + "prowler.providers.aws.services.s3.s3_bucket_public_write_acl.s3_bucket_public_write_acl_fixer.s3_client", + new=S3(aws_provider), + ): + # Test Fixer + from prowler.providers.aws.services.s3.s3_bucket_public_write_acl.s3_bucket_public_write_acl_fixer import ( + fixer, + ) + + assert fixer(bucket_name_us, AWS_REGION_US_EAST_1) + + @mock_aws + def test_bucket_public_write_ACL_AllUsers_WRITE_error(self): + s3_client = client("s3", region_name=AWS_REGION_US_EAST_1) + bucket_name_us = "bucket_test_us" + s3_client.create_bucket(Bucket=bucket_name_us) + bucket_owner = s3_client.get_bucket_acl(Bucket=bucket_name_us)["Owner"] + # Generate S3Control Client + s3control_client = client("s3control", region_name=AWS_REGION_US_EAST_1) + s3control_client.put_public_access_block( + AccountId=AWS_ACCOUNT_NUMBER, + PublicAccessBlockConfiguration={ + "BlockPublicAcls": False, + "IgnorePublicAcls": False, + "BlockPublicPolicy": False, + "RestrictPublicBuckets": False, + }, + ) + s3_client.put_public_access_block( + Bucket=bucket_name_us, + PublicAccessBlockConfiguration={ + "BlockPublicAcls": False, + "IgnorePublicAcls": False, + "BlockPublicPolicy": False, + "RestrictPublicBuckets": False, + }, + ) + s3_client.put_bucket_acl( + Bucket=bucket_name_us, + AccessControlPolicy={ + "Grants": [ + { + "Grantee": { + "URI": "http://acs.amazonaws.com/groups/global/AllUsers", + "Type": "Group", + }, + "Permission": "WRITE", + }, + ], + "Owner": bucket_owner, + }, + ) + from prowler.providers.aws.services.s3.s3_service import S3 + + aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ): + with mock.patch( + "prowler.providers.aws.services.s3.s3_bucket_public_write_acl.s3_bucket_public_write_acl_fixer.s3_client", + new=S3(aws_provider), + ): + # Test Fixer + from prowler.providers.aws.services.s3.s3_bucket_public_write_acl.s3_bucket_public_write_acl_fixer import ( + fixer, + ) + + assert not fixer("bucket_name_us_non_existing", AWS_REGION_US_EAST_1)