2020-08-27 09:11:47 +00:00
|
|
|
import json
|
2023-08-07 16:48:48 +00:00
|
|
|
import re
|
2020-08-27 09:11:47 +00:00
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
import boto3
|
2020-08-27 09:11:47 +00:00
|
|
|
|
2024-01-07 12:03:33 +00:00
|
|
|
from moto import mock_aws
|
2020-08-27 09:11:47 +00:00
|
|
|
|
|
|
|
|
2024-01-07 12:03:33 +00:00
|
|
|
@mock_aws
|
2020-08-27 09:11:47 +00:00
|
|
|
def test_s3_bucket_cloudformation_basic():
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client = boto3.client("s3", region_name="us-east-1")
|
|
|
|
cf_client = boto3.client("cloudformation", region_name="us-east-1")
|
2020-08-27 09:11:47 +00:00
|
|
|
|
|
|
|
template = {
|
|
|
|
"AWSTemplateFormatVersion": "2010-09-09",
|
2022-03-10 14:39:59 +00:00
|
|
|
"Resources": {"testInstance": {"Type": "AWS::S3::Bucket", "Properties": {}}},
|
2020-08-27 09:11:47 +00:00
|
|
|
"Outputs": {"Bucket": {"Value": {"Ref": "testInstance"}}},
|
|
|
|
}
|
|
|
|
template_json = json.dumps(template)
|
2023-08-07 16:48:48 +00:00
|
|
|
cf_client.create_stack(StackName="test_stack", TemplateBody=template_json)
|
|
|
|
stack_description = cf_client.describe_stacks(StackName="test_stack")["Stacks"][0]
|
2020-08-27 09:11:47 +00:00
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.head_bucket(Bucket=stack_description["Outputs"][0]["OutputValue"])
|
2020-08-27 09:11:47 +00:00
|
|
|
|
|
|
|
|
2024-01-07 12:03:33 +00:00
|
|
|
@mock_aws
|
2020-08-27 09:11:47 +00:00
|
|
|
def test_s3_bucket_cloudformation_with_properties():
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client = boto3.client("s3", region_name="us-east-1")
|
|
|
|
cf_client = boto3.client("cloudformation", region_name="us-east-1")
|
2020-08-27 09:11:47 +00:00
|
|
|
|
|
|
|
bucket_name = "MyBucket"
|
|
|
|
template = {
|
|
|
|
"AWSTemplateFormatVersion": "2010-09-09",
|
|
|
|
"Resources": {
|
|
|
|
"testInstance": {
|
|
|
|
"Type": "AWS::S3::Bucket",
|
|
|
|
"Properties": {
|
|
|
|
"BucketName": bucket_name,
|
|
|
|
"BucketEncryption": {
|
|
|
|
"ServerSideEncryptionConfiguration": [
|
|
|
|
{
|
|
|
|
"ServerSideEncryptionByDefault": {
|
|
|
|
"SSEAlgorithm": "AES256"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"Outputs": {"Bucket": {"Value": {"Ref": "testInstance"}}},
|
|
|
|
}
|
|
|
|
template_json = json.dumps(template)
|
2023-08-07 16:48:48 +00:00
|
|
|
cf_client.create_stack(StackName="test_stack", TemplateBody=template_json)
|
|
|
|
cf_client.describe_stacks(StackName="test_stack")
|
|
|
|
s3_client.head_bucket(Bucket=bucket_name)
|
|
|
|
|
|
|
|
encryption = s3_client.get_bucket_encryption(Bucket=bucket_name)
|
|
|
|
assert (
|
|
|
|
encryption["ServerSideEncryptionConfiguration"]["Rules"][0][
|
|
|
|
"ApplyServerSideEncryptionByDefault"
|
|
|
|
]["SSEAlgorithm"]
|
|
|
|
== "AES256"
|
|
|
|
)
|
2020-08-27 09:11:47 +00:00
|
|
|
|
|
|
|
|
2024-01-07 12:03:33 +00:00
|
|
|
@mock_aws
|
2020-08-27 09:11:47 +00:00
|
|
|
def test_s3_bucket_cloudformation_update_no_interruption():
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client = boto3.client("s3", region_name="us-east-1")
|
|
|
|
cf_client = boto3.client("cloudformation", region_name="us-east-1")
|
2020-08-27 09:11:47 +00:00
|
|
|
|
|
|
|
template = {
|
|
|
|
"AWSTemplateFormatVersion": "2010-09-09",
|
|
|
|
"Resources": {"testInstance": {"Type": "AWS::S3::Bucket"}},
|
|
|
|
"Outputs": {"Bucket": {"Value": {"Ref": "testInstance"}}},
|
|
|
|
}
|
|
|
|
template_json = json.dumps(template)
|
2023-08-07 16:48:48 +00:00
|
|
|
cf_client.create_stack(StackName="test_stack", TemplateBody=template_json)
|
|
|
|
stack_description = cf_client.describe_stacks(StackName="test_stack")["Stacks"][0]
|
|
|
|
s3_client.head_bucket(Bucket=stack_description["Outputs"][0]["OutputValue"])
|
2020-08-27 09:11:47 +00:00
|
|
|
|
|
|
|
template = {
|
|
|
|
"AWSTemplateFormatVersion": "2010-09-09",
|
|
|
|
"Resources": {
|
|
|
|
"testInstance": {
|
|
|
|
"Type": "AWS::S3::Bucket",
|
|
|
|
"Properties": {
|
|
|
|
"BucketEncryption": {
|
|
|
|
"ServerSideEncryptionConfiguration": [
|
|
|
|
{
|
|
|
|
"ServerSideEncryptionByDefault": {
|
|
|
|
"SSEAlgorithm": "AES256"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"Outputs": {"Bucket": {"Value": {"Ref": "testInstance"}}},
|
|
|
|
}
|
|
|
|
template_json = json.dumps(template)
|
2023-08-07 16:48:48 +00:00
|
|
|
cf_client.update_stack(StackName="test_stack", TemplateBody=template_json)
|
|
|
|
encryption = s3_client.get_bucket_encryption(
|
2020-08-27 09:11:47 +00:00
|
|
|
Bucket=stack_description["Outputs"][0]["OutputValue"]
|
|
|
|
)
|
2023-08-07 16:48:48 +00:00
|
|
|
assert (
|
|
|
|
encryption["ServerSideEncryptionConfiguration"]["Rules"][0][
|
|
|
|
"ApplyServerSideEncryptionByDefault"
|
|
|
|
]["SSEAlgorithm"]
|
|
|
|
== "AES256"
|
|
|
|
)
|
2020-08-27 09:11:47 +00:00
|
|
|
|
|
|
|
|
2024-01-07 12:03:33 +00:00
|
|
|
@mock_aws
|
2020-08-27 09:11:47 +00:00
|
|
|
def test_s3_bucket_cloudformation_update_replacement():
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client = boto3.client("s3", region_name="us-east-1")
|
|
|
|
cf_client = boto3.client("cloudformation", region_name="us-east-1")
|
2020-08-27 09:11:47 +00:00
|
|
|
|
|
|
|
template = {
|
|
|
|
"AWSTemplateFormatVersion": "2010-09-09",
|
|
|
|
"Resources": {"testInstance": {"Type": "AWS::S3::Bucket"}},
|
|
|
|
"Outputs": {"Bucket": {"Value": {"Ref": "testInstance"}}},
|
|
|
|
}
|
|
|
|
template_json = json.dumps(template)
|
2023-08-07 16:48:48 +00:00
|
|
|
cf_client.create_stack(StackName="test_stack", TemplateBody=template_json)
|
|
|
|
stack_description = cf_client.describe_stacks(StackName="test_stack")["Stacks"][0]
|
|
|
|
s3_client.head_bucket(Bucket=stack_description["Outputs"][0]["OutputValue"])
|
2020-08-27 09:11:47 +00:00
|
|
|
|
|
|
|
template = {
|
|
|
|
"AWSTemplateFormatVersion": "2010-09-09",
|
|
|
|
"Resources": {
|
|
|
|
"testInstance": {
|
|
|
|
"Type": "AWS::S3::Bucket",
|
|
|
|
"Properties": {"BucketName": "MyNewBucketName"},
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"Outputs": {"Bucket": {"Value": {"Ref": "testInstance"}}},
|
|
|
|
}
|
|
|
|
template_json = json.dumps(template)
|
2023-08-07 16:48:48 +00:00
|
|
|
cf_client.update_stack(StackName="test_stack", TemplateBody=template_json)
|
|
|
|
stack_description = cf_client.describe_stacks(StackName="test_stack")["Stacks"][0]
|
|
|
|
s3_client.head_bucket(Bucket=stack_description["Outputs"][0]["OutputValue"])
|
2020-10-16 10:29:26 +00:00
|
|
|
|
|
|
|
|
2024-01-07 12:03:33 +00:00
|
|
|
@mock_aws
|
2020-10-16 10:29:26 +00:00
|
|
|
def test_s3_bucket_cloudformation_outputs():
|
2020-10-27 16:04:32 +00:00
|
|
|
region_name = "us-east-1"
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client = boto3.client("s3", region_name=region_name)
|
|
|
|
cf_client = boto3.resource("cloudformation", region_name=region_name)
|
2020-10-16 10:29:26 +00:00
|
|
|
stack_name = "test-stack"
|
|
|
|
bucket_name = "test-bucket"
|
|
|
|
template = {
|
|
|
|
"AWSTemplateFormatVersion": "2010-09-09",
|
|
|
|
"Resources": {
|
|
|
|
"TestBucket": {
|
|
|
|
"Type": "AWS::S3::Bucket",
|
|
|
|
"Properties": {"BucketName": bucket_name},
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"Outputs": {
|
|
|
|
"BucketARN": {
|
|
|
|
"Value": {"Fn::GetAtt": ["TestBucket", "Arn"]},
|
|
|
|
"Export": {"Name": {"Fn::Sub": "${AWS::StackName}:BucketARN"}},
|
|
|
|
},
|
2020-10-27 16:04:32 +00:00
|
|
|
"BucketDomainName": {
|
|
|
|
"Value": {"Fn::GetAtt": ["TestBucket", "DomainName"]},
|
|
|
|
"Export": {"Name": {"Fn::Sub": "${AWS::StackName}:BucketDomainName"}},
|
|
|
|
},
|
|
|
|
"BucketDualStackDomainName": {
|
|
|
|
"Value": {"Fn::GetAtt": ["TestBucket", "DualStackDomainName"]},
|
|
|
|
"Export": {
|
|
|
|
"Name": {"Fn::Sub": "${AWS::StackName}:BucketDualStackDomainName"}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"BucketRegionalDomainName": {
|
|
|
|
"Value": {"Fn::GetAtt": ["TestBucket", "RegionalDomainName"]},
|
|
|
|
"Export": {
|
|
|
|
"Name": {"Fn::Sub": "${AWS::StackName}:BucketRegionalDomainName"}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"BucketWebsiteURL": {
|
|
|
|
"Value": {"Fn::GetAtt": ["TestBucket", "WebsiteURL"]},
|
|
|
|
"Export": {"Name": {"Fn::Sub": "${AWS::StackName}:BucketWebsiteURL"}},
|
|
|
|
},
|
2020-10-16 10:29:26 +00:00
|
|
|
"BucketName": {
|
|
|
|
"Value": {"Ref": "TestBucket"},
|
|
|
|
"Export": {"Name": {"Fn::Sub": "${AWS::StackName}:BucketName"}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2023-08-07 16:48:48 +00:00
|
|
|
cf_client.create_stack(StackName=stack_name, TemplateBody=json.dumps(template))
|
|
|
|
outputs_list = cf_client.Stack(stack_name).outputs
|
2020-10-16 10:29:26 +00:00
|
|
|
output = {item["OutputKey"]: item["OutputValue"] for item in outputs_list}
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.head_bucket(Bucket=output["BucketName"])
|
|
|
|
assert re.match(f"arn:aws:s3.+{bucket_name}", output["BucketARN"])
|
|
|
|
assert output["BucketDomainName"] == f"{bucket_name}.s3.amazonaws.com"
|
|
|
|
assert output["BucketDualStackDomainName"] == (
|
2022-11-17 22:41:08 +00:00
|
|
|
f"{bucket_name}.s3.dualstack.{region_name}.amazonaws.com"
|
2020-10-27 16:04:32 +00:00
|
|
|
)
|
2023-08-07 16:48:48 +00:00
|
|
|
assert output["BucketRegionalDomainName"] == (
|
2022-11-17 22:41:08 +00:00
|
|
|
f"{bucket_name}.s3.{region_name}.amazonaws.com"
|
2020-10-27 16:04:32 +00:00
|
|
|
)
|
2023-08-07 16:48:48 +00:00
|
|
|
assert output["BucketWebsiteURL"] == (
|
2022-11-17 22:41:08 +00:00
|
|
|
f"http://{bucket_name}.s3-website.{region_name}.amazonaws.com"
|
2020-10-27 16:04:32 +00:00
|
|
|
)
|
2023-08-07 16:48:48 +00:00
|
|
|
assert output["BucketName"] == bucket_name
|