feat(cloudfront): add new check cloudfront_distributions_s3_origin_non_existing_bucket (#4996)

Co-authored-by: Sergio <sergio@prowler.com>
This commit is contained in:
Hugo Pereira Brito
2024-09-23 18:43:03 +02:00
committed by GitHub
parent 14ed19e3a8
commit cca17b9378
19 changed files with 299 additions and 35 deletions
@@ -0,0 +1,34 @@
{
"Provider": "aws",
"CheckID": "cloudfront_distributions_s3_origin_non_existent_bucket",
"CheckTitle": "CloudFront distributions should not point to non-existent S3 origins.",
"CheckType": [
"Software and Configuration Checks/Industry and Regulatory Standards/NIST 800-53 Controls"
],
"ServiceName": "cloudfront",
"SubServiceName": "",
"ResourceIdTemplate": "arn:partition:cloudfront:region:account-id:distribution/resource-id",
"Severity": "high",
"ResourceType": "AwsCloudFrontDistribution",
"Description": "This control checks whether Amazon CloudFront distributions are pointing to non-existent Amazon S3 origins. The control fails if the origin is configured to point to a non-existent bucket.",
"Risk": "Pointing a CloudFront distribution to a non-existent S3 bucket can allow malicious actors to create the bucket and potentially serve unauthorized content through your distribution, leading to security and integrity issues.",
"RelatedUrl": "https://docs.aws.amazon.com/whitepapers/latest/secure-content-delivery-amazon-cloudfront/s3-origin-with-cloudfront.html",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/cloudfront-controls.html#cloudfront-12",
"Terraform": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/CloudFront/cloudfront-existing-s3-bucket.html"
},
"Recommendation": {
"Text": "Verify that all CloudFront distributions are configured to point to valid, existing S3 buckets. Update the origin settings as needed to ensure that your distributions are linked to appropriate and secure origins.",
"Url": "https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/HowToUpdateDistribution.html"
}
},
"Categories": [
"trustboundaries"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}
@@ -0,0 +1,32 @@
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.cloudfront.cloudfront_client import (
cloudfront_client,
)
from prowler.providers.aws.services.s3.s3_client import s3_client
class cloudfront_distributions_s3_origin_non_existent_bucket(Check):
def execute(self):
findings = []
for distribution in cloudfront_client.distributions.values():
report = Check_Report_AWS(self.metadata())
report.region = distribution.region
report.resource_arn = distribution.arn
report.resource_id = distribution.id
report.resource_tags = distribution.tags
report.status = "PASS"
report.status_extended = f"CloudFront Distribution {distribution.id} does not have non-existent S3 buckets as origins."
non_existent_buckets = []
for origin in distribution.origins:
bucket_name = origin.domain_name.split(".")[0]
if not s3_client._head_bucket(bucket_name):
non_existent_buckets.append(bucket_name)
if non_existent_buckets:
report.status = "FAIL"
report.status_extended = f"CloudFront Distribution {distribution.id} has non-existent S3 buckets as origins: {','.join(non_existent_buckets)}."
findings.append(report)
return findings
@@ -36,7 +36,6 @@ class CloudFront(AWSService):
origin_group.get("Members", {}).get("Quantity", 0) >= 2
for origin_group in origin_groups
)
default_certificate = item["ViewerCertificate"][
"CloudFrontDefaultCertificate"
]
@@ -442,6 +442,27 @@ class S3(AWSService):
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
def _head_bucket(self, bucket_name):
logger.info("S3 - Checking if bucket exists...")
try:
self.client.head_bucket(Bucket=bucket_name)
return True
except ClientError as error:
if error.response["Error"]["Message"] == "Not Found":
logger.warning(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return True
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
class S3Control(AWSService):
def __init__(self, provider):
@@ -31,7 +31,7 @@ class Test_cloudfront_distributions_custom_ssl_certificate:
def test_distribution_default_certificate(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -66,7 +66,7 @@ class Test_cloudfront_distributions_custom_ssl_certificate:
def test_distribution_custom_certificate(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -35,7 +35,7 @@ class Test_cloudfront_distributions_default_root_object:
def test_distribution_no_root_object(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -75,7 +75,7 @@ class Test_cloudfront_distributions_default_root_object:
cloudfront_client = mock.MagicMock
dro = "index.html"
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -35,7 +35,7 @@ class Test_cloudfront_distributions_field_level_encryption_enabled:
def test_one_distribution_field_level_encryption_enabled(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -75,7 +75,7 @@ class Test_cloudfront_distributions_field_level_encryption_enabled:
def test_one_distribution_field_level_encryption_disabled(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -34,7 +34,7 @@ class Test_cloudfront_distributions_geo_restrictions_enabled:
def test_one_distribution_geo_restriction_disabled(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -69,7 +69,7 @@ class Test_cloudfront_distributions_geo_restrictions_enabled:
def test_one_distribution_geo_restriction_enabled_whitelist(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -105,7 +105,7 @@ class Test_cloudfront_distributions_geo_restrictions_enabled:
def test_one_distribution_geo_restriction_enabled_blacklist(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -35,7 +35,7 @@ class Test_cloudfront_distributions_https_enabled:
def test_one_distribution_https_disabled(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -75,7 +75,7 @@ class Test_cloudfront_distributions_https_enabled:
def test_one_distribution_https_redirect(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -115,7 +115,7 @@ class Test_cloudfront_distributions_https_enabled:
def test_one_distribution_https_only(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -34,7 +34,7 @@ class Test_cloudfront_distributions_https_sni_enabled:
def test_distribution_no_certificate(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -60,7 +60,7 @@ class Test_cloudfront_distributions_https_sni_enabled:
def test_distribution_certificate_not_set_up(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -96,7 +96,7 @@ class Test_cloudfront_distributions_https_sni_enabled:
def test_distribution_valid_configuration(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -35,7 +35,7 @@ class Test_cloudfront_distributions_logging_enabled:
def test_one_distribution_logging_enabled(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -70,7 +70,7 @@ class Test_cloudfront_distributions_logging_enabled:
def test_one_distribution_logging_disabled_realtime_disabled(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -111,7 +111,7 @@ class Test_cloudfront_distributions_logging_enabled:
def test_one_distribution_logging_disabled_realtime_enabled(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -152,7 +152,7 @@ class Test_cloudfront_distributions_logging_enabled:
def test_one_distribution_logging_enabled_realtime_enabled(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -35,7 +35,7 @@ class Test_cloudfront_distributions_multiple_origin_failover_configured:
def test_no_origin_failover(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -75,7 +75,7 @@ class Test_cloudfront_distributions_multiple_origin_failover_configured:
def test_origin_failover(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -37,7 +37,7 @@ class Test_cloudfront_distributions_origin_traffic_encrypted:
cloudfront_client = mock.MagicMock
id = "origin1"
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -86,7 +86,7 @@ class Test_cloudfront_distributions_origin_traffic_encrypted:
cloudfront_client = mock.MagicMock
id = "origin1"
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -134,7 +134,7 @@ class Test_cloudfront_distributions_origin_traffic_encrypted:
cloudfront_client = mock.MagicMock
id = "origin1"
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -182,7 +182,7 @@ class Test_cloudfront_distributions_origin_traffic_encrypted:
def test_distribution_traffic_encrypted(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -34,7 +34,7 @@ class Test_cloudfront_distributions_s3_origin_access_control:
def test_no_s3_origin_distributions(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -66,7 +66,7 @@ class Test_cloudfront_distributions_s3_origin_access_control:
def test_distribution_using_origin_access_control(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -112,7 +112,7 @@ class Test_cloudfront_distributions_s3_origin_access_control:
cloudfront_client = mock.MagicMock
id = "EXAMPLE-OAC-ID"
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -0,0 +1,151 @@
from unittest import mock
from prowler.providers.aws.services.cloudfront.cloudfront_service import (
Distribution,
Origin,
)
from prowler.providers.aws.services.s3.s3_service import Bucket
from tests.providers.aws.utils import AWS_ACCOUNT_NUMBER, AWS_REGION_EU_WEST_1
DISTRIBUTION_ID = "E27LVI50CSW06W"
DISTRIBUTION_ARN = (
f"arn:aws:cloudfront::{AWS_ACCOUNT_NUMBER}:distribution/{DISTRIBUTION_ID}"
)
class Test_cloudfront_s3_origin_non_existent_bucket:
def test_no_distributions(self):
# Distributions
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {}
s3_client = mock.MagicMock
# Buckets
s3_client.buckets = {}
with mock.patch(
"prowler.providers.aws.services.s3.s3_service.S3", new=s3_client
), mock.patch(
"prowler.providers.aws.services.cloudfront.cloudfront_service.CloudFront",
new=cloudfront_client,
):
# Test Check
from prowler.providers.aws.services.cloudfront.cloudfront_distributions_s3_origin_non_existent_bucket.cloudfront_distributions_s3_origin_non_existent_bucket import (
cloudfront_distributions_s3_origin_non_existent_bucket,
)
check = cloudfront_distributions_s3_origin_non_existent_bucket()
result = check.execute()
assert len(result) == 0
@mock.patch(
"prowler.providers.aws.services.s3.s3_service.S3._head_bucket",
new=mock.MagicMock(return_value=False),
)
def test_distribution_nonexistent_origins(self):
# Distributions
domain = "nonexistent-bucket.s3.eu-west-1.amazonaws.com"
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=AWS_REGION_EU_WEST_1,
logging_enabled=True,
origins=[
Origin(
domain_name=domain,
id="S3-ORIGIN",
origin_protocol_policy="",
origin_ssl_protocols=[],
),
],
)
}
# Buckets
nonexistent_bucket = "nonexistent-bucket"
s3_client = mock.MagicMock
s3_client.buckets = {}
with mock.patch(
"prowler.providers.aws.services.s3.s3_service.S3", new=s3_client
), mock.patch(
"prowler.providers.aws.services.cloudfront.cloudfront_service.CloudFront",
new=cloudfront_client,
):
# Test Check
from prowler.providers.aws.services.cloudfront.cloudfront_distributions_s3_origin_non_existent_bucket.cloudfront_distributions_s3_origin_non_existent_bucket import (
cloudfront_distributions_s3_origin_non_existent_bucket,
)
check = cloudfront_distributions_s3_origin_non_existent_bucket()
result = check.execute()
assert len(result) == 1
assert result[0].region == AWS_REGION_EU_WEST_1
assert result[0].resource_arn == DISTRIBUTION_ARN
assert result[0].resource_id == DISTRIBUTION_ID
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"CloudFront Distribution {DISTRIBUTION_ID} has non-existent S3 buckets as origins: {nonexistent_bucket}."
)
@mock.patch(
"prowler.providers.aws.services.s3.s3_service.S3._head_bucket",
new=mock.MagicMock(return_value=True),
)
def test_distribution_no_nonexistent_origins(self):
# Distributions
domain = "existent-bucket.s3.eu-west-1.amazonaws.com"
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=AWS_REGION_EU_WEST_1,
logging_enabled=True,
origins=[
Origin(
domain_name=domain,
id="S3-ORIGIN",
origin_protocol_policy="",
origin_ssl_protocols=[],
),
],
)
}
# Buckets
bucket_name = "existent-bucket"
s3_client = mock.MagicMock
s3_client.audited_account = AWS_ACCOUNT_NUMBER
s3_client.buckets = {
f"arn:aws:s3:::{bucket_name}": Bucket(
name=bucket_name,
region=AWS_REGION_EU_WEST_1,
)
}
with mock.patch(
"prowler.providers.aws.services.s3.s3_service.S3", new=s3_client
), mock.patch(
"prowler.providers.aws.services.cloudfront.cloudfront_service.CloudFront",
new=cloudfront_client,
):
# Test Check
from prowler.providers.aws.services.cloudfront.cloudfront_distributions_s3_origin_non_existent_bucket.cloudfront_distributions_s3_origin_non_existent_bucket import (
cloudfront_distributions_s3_origin_non_existent_bucket,
)
check = cloudfront_distributions_s3_origin_non_existent_bucket()
result = check.execute()
assert len(result) == 1
assert result[0].region == AWS_REGION_EU_WEST_1
assert result[0].resource_arn == DISTRIBUTION_ARN
assert result[0].resource_id == DISTRIBUTION_ID
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"CloudFront Distribution {DISTRIBUTION_ID} does not have non-existent S3 buckets as origins."
)
@@ -34,7 +34,7 @@ class Test_cloudfront_distributions_using_deprecated_ssl_protocols:
def test_one_distribution_using_deprecated_ssl_protocols(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -76,7 +76,7 @@ class Test_cloudfront_distributions_using_deprecated_ssl_protocols:
def test_one_distribution_using_SSL_and_TLS(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -121,7 +121,7 @@ class Test_cloudfront_distributions_using_deprecated_ssl_protocols:
def test_one_distribution_using_SSL_and_bad_TLS(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -166,7 +166,7 @@ class Test_cloudfront_distributions_using_deprecated_ssl_protocols:
def test_one_distribution_not_using_deprecated_ssl_protocols(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -32,7 +32,7 @@ class Test_cloudfront_distributions_using_waf:
wef_acl_id = "TEST-WAF-ACL"
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -68,7 +68,7 @@ class Test_cloudfront_distributions_using_waf:
def test_one_distribution_no_waf(self):
cloudfront_client = mock.MagicMock
cloudfront_client.distributions = {
"DISTRIBUTION_ID": Distribution(
DISTRIBUTION_ID: Distribution(
arn=DISTRIBUTION_ARN,
id=DISTRIBUTION_ID,
region=REGION,
@@ -2,6 +2,7 @@ import json
from unittest.mock import patch
import botocore
import botocore.exceptions
from boto3 import client
from moto import mock_aws
@@ -478,6 +479,32 @@ class Test_S3_Service:
assert s3.buckets[bucket_arn].lifecycle[0].id == "test"
assert s3.buckets[bucket_arn].lifecycle[0].status == "Enabled"
# Test S3 Head Bucket
@mock_aws
@patch("botocore.client.BaseClient._make_api_call", new=mock_make_api_call)
def test_head_bucket(self):
# Generate S3 Client
s3_client = client("s3")
# Create S3 Bucket
bucket_name = "test-bucket"
bucket_arn = f"arn:aws:s3:::{bucket_name}"
s3_client.create_bucket(
Bucket=bucket_name,
ObjectOwnership="BucketOwnerEnforced",
ObjectLockEnabledForBucket=True,
)
# S3 client for this test class
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
s3 = S3(aws_provider)
assert len(s3.buckets) == 1
assert s3.buckets[bucket_arn].name == bucket_name
assert s3._head_bucket(
bucket_name=bucket_name,
)
assert s3.buckets[bucket_arn].region == AWS_REGION_US_EAST_1
# Test S3 List Access Points
@patch("botocore.client.BaseClient._make_api_call", new=mock_make_api_call)
@mock_aws