From 3f1e90a5b3975c47cc4921de280b6c20b09ac3aa Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Mon, 16 Dec 2024 16:01:38 +0100 Subject: [PATCH] feat(s3): add new fixer `s3_bucket_policy_public_write_access_fixer` (#6173) --- ...bucket_policy_public_write_access_fixer.py | 38 ++++++++++ ...t_policy_public_write_access_fixer_test.py | 70 +++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 prowler/providers/aws/services/s3/s3_bucket_policy_public_write_access/s3_bucket_policy_public_write_access_fixer.py create mode 100644 tests/providers/aws/services/s3/s3_bucket_policy_public_write_access/s3_bucket_policy_public_write_access_fixer_test.py diff --git a/prowler/providers/aws/services/s3/s3_bucket_policy_public_write_access/s3_bucket_policy_public_write_access_fixer.py b/prowler/providers/aws/services/s3/s3_bucket_policy_public_write_access/s3_bucket_policy_public_write_access_fixer.py new file mode 100644 index 0000000000..4edd4b39dd --- /dev/null +++ b/prowler/providers/aws/services/s3/s3_bucket_policy_public_write_access/s3_bucket_policy_public_write_access_fixer.py @@ -0,0 +1,38 @@ +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's policy to remove public access. + Specifically, this fixer delete the policy of the public bucket. + Requires the s3:DeleteBucketPolicy permission. + Permissions: + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": "s3:DeleteBucketPolicy", + "Resource": "*" + } + ] + } + Args: + resource_id (str): The S3 bucket name. + region (str): AWS region where the S3 bucket exists. + Returns: + bool: True if the operation is successful (policy updated), False otherwise. + """ + try: + regional_client = s3_client.regional_clients[region] + + regional_client.delete_bucket_policy(Bucket=resource_id) + + 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_policy_public_write_access/s3_bucket_policy_public_write_access_fixer_test.py b/tests/providers/aws/services/s3/s3_bucket_policy_public_write_access/s3_bucket_policy_public_write_access_fixer_test.py new file mode 100644 index 0000000000..3f4687cab9 --- /dev/null +++ b/tests/providers/aws/services/s3/s3_bucket_policy_public_write_access/s3_bucket_policy_public_write_access_fixer_test.py @@ -0,0 +1,70 @@ +from unittest import mock + +from boto3 import client +from moto import mock_aws + +from tests.providers.aws.utils import AWS_REGION_US_EAST_1, set_mocked_aws_provider + + +class Test_s3_bucket_policy_public_write_access_fixer: + @mock_aws + def test_bucket_public_write_policy(self): + s3_client_us_east_1 = client("s3", region_name=AWS_REGION_US_EAST_1) + bucket_name_us = "bucket_test_us" + s3_client_us_east_1.create_bucket( + Bucket=bucket_name_us, ObjectOwnership="BucketOwnerEnforced" + ) + public_write_policy = '{"Version": "2012-10-17","Id": "PutObjPolicy","Statement": [{"Sid": "PublicWritePolicy","Effect": "Allow","Principal": "*","Action": "s3:PutObject","Resource": "arn:aws:s3:::bucket_test_us/*"}]}' + s3_client_us_east_1.put_bucket_policy( + Bucket=bucket_name_us, + Policy=public_write_policy, + ) + + 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, + ), mock.patch( + "prowler.providers.aws.services.s3.s3_bucket_policy_public_write_access.s3_bucket_policy_public_write_access_fixer.s3_client", + new=S3(aws_provider), + ): + # Test Fixer + from prowler.providers.aws.services.s3.s3_bucket_policy_public_write_access.s3_bucket_policy_public_write_access_fixer import ( + fixer, + ) + + assert fixer(bucket_name_us, AWS_REGION_US_EAST_1) + + @mock_aws + def test_bucket_public_write_policy_error(self): + s3_client_us_east_1 = client("s3", region_name=AWS_REGION_US_EAST_1) + bucket_name_us = "bucket_test_us" + s3_client_us_east_1.create_bucket( + Bucket=bucket_name_us, ObjectOwnership="BucketOwnerEnforced" + ) + public_write_policy = '{"Version": "2012-10-17","Id": "PutObjPolicy","Statement": [{"Sid": "PublicWritePolicy","Effect": "Allow","Principal": "*","Action": "s3:PutObject","Resource": "arn:aws:s3:::bucket_test_us/*"}]}' + s3_client_us_east_1.put_bucket_policy( + Bucket=bucket_name_us, + Policy=public_write_policy, + ) + + 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, + ), mock.patch( + "prowler.providers.aws.services.s3.s3_bucket_policy_public_write_access.s3_bucket_policy_public_write_access_fixer.s3_client", + new=S3(aws_provider), + ): + # Test Fixer + from prowler.providers.aws.services.s3.s3_bucket_policy_public_write_access.s3_bucket_policy_public_write_access_fixer import ( + fixer, + ) + + assert not fixer("bucket_name_non_existing", AWS_REGION_US_EAST_1)