Skip to content

Commit

Permalink
feat: add s3 website alias record (#27)
Browse files Browse the repository at this point in the history
  • Loading branch information
raykrishardi committed Dec 13, 2023
1 parent 1b92964 commit 5b0cd73
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 1 deletion.
24 changes: 24 additions & 0 deletions s3.cfndsl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,30 @@
website_configuration['ErrorDocument'] = website['error_document']
website_configuration['IndexDocument'] = website['index_document']

if website.has_key?('alias')
dns_format = website['alias']['dns_format']
subdomain = website['alias']['subdomain']
fqdn = subdomain + "." + dns_format + "."
region = website['alias']['region']

# Reference: https://docs.aws.amazon.com/general/latest/gr/s3.html#s3_website_region_endpoints
s3RegionMapping = {
"ap-southeast-2" => {
"hosted_zone_id" => "Z1WCIGYICN2BYD"
}
}

Route53_RecordSet("#{safe_bucket_name}S3AliasRecord") do
HostedZoneName FnSub("#{dns_format}.")
Name FnSub(fqdn)
Type 'A'
AliasTarget ({
DNSName: "s3-website-#{region}.amazonaws.com.",
HostedZoneId: s3RegionMapping[region]['hosted_zone_id']
})
end
end

if website.has_key?('routing_rules')
routing_rules = []
website['routing_rules'].each do |rule|
Expand Down
85 changes: 85 additions & 0 deletions spec/website_alias_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
require 'yaml'

describe 'compiled component s3' do

context 'cftest' do
it 'compiles test' do
expect(system("cfhighlander cftest #{@validate} --tests tests/website_alias.test.yaml")).to be_truthy
end
end

let(:template) { YAML.load_file("#{File.dirname(__FILE__)}/../out/tests/website_alias/s3.compiled.yaml") }

context "Resource" do


context "NormalbucketS3AliasRecord" do
let(:resource) { template["Resources"]["NormalbucketS3AliasRecord"] }

it "is of type AWS::Route53::RecordSet" do
expect(resource["Type"]).to eq("AWS::Route53::RecordSet")
end

it "to have property HostedZoneName" do
expect(resource["Properties"]["HostedZoneName"]).to eq({"Fn::Sub"=>"example.com."})
end

it "to have property Name" do
expect(resource["Properties"]["Name"]).to eq({"Fn::Sub"=>"mybucket.example.com."})
end

it "to have property Type" do
expect(resource["Properties"]["Type"]).to eq("A")
end

it "to have property AliasTarget" do
expect(resource["Properties"]["AliasTarget"]).to eq({"DNSName"=>"s3-website-ap-southeast-2.amazonaws.com.", "HostedZoneId"=>"Z1WCIGYICN2BYD"})
end

end

context "Normalbucket" do
let(:resource) { template["Resources"]["Normalbucket"] }

it "is of type AWS::S3::Bucket" do
expect(resource["Type"]).to eq("AWS::S3::Bucket")
end

it "to have property BucketName" do
expect(resource["Properties"]["BucketName"]).to eq({"Fn::Sub"=>"normal-bucket"})
end

it "to have property Tags" do
expect(resource["Properties"]["Tags"]).to eq([{"Key"=>"Name", "Value"=>{"Fn::Sub"=>"${EnvironmentName}-normal-bucket"}}, {"Key"=>"Environment", "Value"=>{"Ref"=>"EnvironmentName"}}, {"Key"=>"EnvironmentType", "Value"=>{"Ref"=>"EnvironmentType"}}])
end

it "to have property PublicAccessBlockConfiguration" do
expect(resource["Properties"]["PublicAccessBlockConfiguration"]).to eq({"BlockPublicAcls"=>false, "BlockPublicPolicy"=>false, "IgnorePublicAcls"=>true, "RestrictPublicBuckets"=>false})
end

it "to have property WebsiteConfiguration" do
expect(resource["Properties"]["WebsiteConfiguration"]).to eq({"ErrorDocument"=>"error.html", "IndexDocument"=>"index.html", "RoutingRules"=>[{"RedirectRule"=>{"HostName"=>"test1", "HttpRedirectCode"=>"301", "Protocol"=>"http", "ReplaceKeyWith"=>"test1"}, "RoutingRuleCondition"=>{"HttpErrorCodeReturnedEquals"=>"400", "KeyPrefixEquals"=>"test1"}}, {"RedirectRule"=>{"ReplaceKeyPrefixWith"=>"documents/"}, "RoutingRuleCondition"=>{"KeyPrefixEquals"=>"docs/"}}]})
end

end

context "NormalbucketPolicy" do
let(:resource) { template["Resources"]["NormalbucketPolicy"] }

it "is of type AWS::S3::BucketPolicy" do
expect(resource["Type"]).to eq("AWS::S3::BucketPolicy")
end

it "to have property Bucket" do
expect(resource["Properties"]["Bucket"]).to eq({"Ref"=>"Normalbucket"})
end

it "to have property PolicyDocument" do
expect(resource["Properties"]["PolicyDocument"]).to eq({"Statement"=>[{"Sid"=>"s3-website", "Effect"=>"Allow", "Principal"=>"*", "Resource"=>[{"Fn::Join"=>["", ["arn:aws:s3:::", {"Ref"=>"Normalbucket"}]]}, {"Fn::Join"=>["", ["arn:aws:s3:::", {"Ref"=>"Normalbucket"}, "/*"]]}], "Action"=>["s3:GetObject"]}]})
end

end

end

end
21 changes: 21 additions & 0 deletions spec/website_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,33 @@
expect(resource["Properties"]["Tags"]).to eq([{"Key"=>"Name", "Value"=>{"Fn::Sub"=>"${EnvironmentName}-normal-bucket"}}, {"Key"=>"Environment", "Value"=>{"Ref"=>"EnvironmentName"}}, {"Key"=>"EnvironmentType", "Value"=>{"Ref"=>"EnvironmentType"}}])
end

it "to have property PublicAccessBlockConfiguration" do
expect(resource["Properties"]["PublicAccessBlockConfiguration"]).to eq({"BlockPublicAcls"=>false, "BlockPublicPolicy"=>false, "IgnorePublicAcls"=>true, "RestrictPublicBuckets"=>false})
end

it "to have property WebsiteConfiguration" do
expect(resource["Properties"]["WebsiteConfiguration"]).to eq({"ErrorDocument"=>"error.html", "IndexDocument"=>"index.html", "RoutingRules"=>[{"RedirectRule"=>{"HostName"=>"test1", "HttpRedirectCode"=>"301", "Protocol"=>"http", "ReplaceKeyWith"=>"test1"}, "RoutingRuleCondition"=>{"HttpErrorCodeReturnedEquals"=>"400", "KeyPrefixEquals"=>"test1"}}, {"RedirectRule"=>{"ReplaceKeyPrefixWith"=>"documents/"}, "RoutingRuleCondition"=>{"KeyPrefixEquals"=>"docs/"}}]})
end

end

context "NormalbucketPolicy" do
let(:resource) { template["Resources"]["NormalbucketPolicy"] }

it "is of type AWS::S3::BucketPolicy" do
expect(resource["Type"]).to eq("AWS::S3::BucketPolicy")
end

it "to have property Bucket" do
expect(resource["Properties"]["Bucket"]).to eq({"Ref"=>"Normalbucket"})
end

it "to have property PolicyDocument" do
expect(resource["Properties"]["PolicyDocument"]).to eq({"Statement"=>[{"Sid"=>"s3-website", "Effect"=>"Allow", "Principal"=>"*", "Resource"=>[{"Fn::Join"=>["", ["arn:aws:s3:::", {"Ref"=>"Normalbucket"}]]}, {"Fn::Join"=>["", ["arn:aws:s3:::", {"Ref"=>"Normalbucket"}, "/*"]]}], "Action"=>["s3:GetObject"]}]})
end

end

end

end
12 changes: 11 additions & 1 deletion tests/website.test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,14 @@ buckets:
- redirect_rule:
replace_key_prefix_with: "documents/"
routing_rule_condition:
key_prefix_equals: "docs/"
key_prefix_equals: "docs/"
public_access_block_configuration:
BlockPublicAcls: false
BlockPublicPolicy: false
IgnorePublicAcls: true
RestrictPublicBuckets: false
bucket-policy:
s3-website:
actions:
- s3:GetObject
principal: "*"
40 changes: 40 additions & 0 deletions tests/website_alias.test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
test_metadata:
type: config
name: website_alias
description: set the description for your test

# Insert your tests here
buckets:
normal-bucket:
type: default
website:
redirect_requests: false
error_document: error.html
index_document: index.html
alias:
dns_format: example.com
subdomain: mybucket
region: ap-southeast-2
routing_rules:
- redirect_rule:
hostname: "test1"
http_redirect_code: "301"
protocol: "http"
replace_key_with: "test1"
routing_rule_condition:
http_error_code_returned_equals: "400"
key_prefix_equals: "test1"
- redirect_rule:
replace_key_prefix_with: "documents/"
routing_rule_condition:
key_prefix_equals: "docs/"
public_access_block_configuration:
BlockPublicAcls: false
BlockPublicPolicy: false
IgnorePublicAcls: true
RestrictPublicBuckets: false
bucket-policy:
s3-website:
actions:
- s3:GetObject
principal: "*"

0 comments on commit 5b0cd73

Please sign in to comment.