diff --git a/cloudfront.cfndsl.rb b/cloudfront.cfndsl.rb index 7452051..072a2b5 100644 --- a/cloudfront.cfndsl.rb +++ b/cloudfront.cfndsl.rb @@ -18,7 +18,7 @@ export = external_parameters.fetch(:export_name, external_parameters[:component_name]) - Condition('WebACLEnabled', FnNot(FnEquals(Ref('WebACL'), ''))) + Condition('WebACLEnabled', FnNot(FnEquals(Ref('WebACL'), ''))) # WebACL issue part, works well without this condition Condition('OverrideAliases', FnNot(FnEquals(Ref('OverrideAliases'), ''))) tags = [] @@ -27,15 +27,14 @@ distribution_config = {} if (comment.to_s.start_with?('{"Fn::')) - distribution_config[:Comment] = comment + distribution_config[:Comment] = comment else distribution_config[:Comment] = FnSub(comment) end distribution_config[:Origins] = [] - - origins.each do |id,config| - origin={ + origins.each do |id, config| + origin = { Id: id, DomainName: Ref("#{id}OriginDomainName") } @@ -44,6 +43,7 @@ case config['source'] when 'vpc' if config.has_key?("arn") + config['default-caching-policy-id'] = '83da9c7e-98b4-4e11-a168-04f0df8e2c65' vpc_origin_config = {} vpc_origin_config[:HTTPPort] = config.has_key?('http_port') ? config["http_port"] : 80 vpc_origin_config[:HTTPSPort] = config.has_key?('https_port') ? config["https_port"] : 443 @@ -61,13 +61,14 @@ origin[:VpcOriginConfig][:VpcOriginId] = Ref("#{id}VPCOrigin") end when 'loadbalancer', 'apigateway' + config['default-caching-policy-id'] = '83da9c7e-98b4-4e11-a168-04f0df8e2c65' origin[:CustomOriginConfig] = { HTTPPort: '80', HTTPSPort: '443' } origin[:CustomOriginConfig][:OriginKeepaliveTimeout] = config["keep_alive_timeout"] if config.has_key?('keep_alive_timeout') origin[:CustomOriginConfig][:OriginReadTimeout] = config["read_timeout"] if config.has_key?('read_timeout') origin[:CustomOriginConfig][:OriginSSLProtocols] = config['ssl_policy'] if config.has_key?('ssl_policy') origin[:CustomOriginConfig][:OriginProtocolPolicy] = config['protocol_policy'] when 's3' - + config['default-caching-policy-id'] = '658327ea-f89d-4fab-a63d-7e88639e58f6' use_access_identity = external_parameters.fetch(:use_access_identity, false) if (use_access_identity == true) CloudFront_CloudFrontOriginAccessIdentity("#{id}OriginAccessIdentity") { @@ -76,7 +77,6 @@ }) } origin[:S3OriginConfig] = { OriginAccessIdentity: FnSub("origin-access-identity/cloudfront/${#{id}OriginAccessIdentity}") } - Output("#{id}OriginAccessIdentity") do Value(FnGetAtt("#{id}OriginAccessIdentity", 'S3CanonicalUserId')) end @@ -96,11 +96,8 @@ Value Ref("#{id}OriginAccessControl") end end - end - distribution_config[:Origins] << origin - end default_root_object = external_parameters.fetch(:default_root_object, nil) @@ -111,7 +108,7 @@ distribution_config[:Enabled] = external_parameters[:enabled] distribution_config[:IPV6Enabled] = ipv6 unless ipv6.nil? distribution_config[:PriceClass] = Ref('PriceClass') - distribution_config[:WebACLId] = FnIf('WebACLEnabled', Ref('WebACL'), Ref('AWS::NoValue')) + distribution_config[:WebACLId] = FnIf('WebACLEnabled', Ref('WebACL'), Ref('AWS::NoValue')) # WebACL issue part distribution_config[:CustomErrorResponses] = custom_error_responses unless custom_error_responses.nil? logs = external_parameters.fetch(:logs, {}) @@ -145,111 +142,190 @@ distribution_config[:ViewerCertificate][:MinimumProtocolVersion] = ssl.has_key?('minimum_protocol_version') ? ssl['minimum_protocol_version'] : "TLSv1.2_2018" - # Cache policies - cache_policies = external_parameters.fetch(:cache_policies, {}) - cache_policies.each do |policy, policy_config| - cache_policy_config = {} - cache_policy_config[:Comment] = policy_config['Comment'] if policy_config.has_key?('Comment') - cache_policy_config[:DefaultTTL] = policy_config.has_key?('DefaultTTL') ? policy_config['DefaultTTL'] : Ref('DefaultTTL') - cache_policy_config[:MaxTTL] = policy_config.has_key?('MaxTTL') ? policy_config['MaxTTL'] : Ref('MaxTTL') - cache_policy_config[:MinTTL] = policy_config.has_key?('MinTTL') ? policy_config['MinTTL'] : Ref('MinTTL') - cache_policy_config[:Name] = policy_config.has_key?('Name') ? policy_config['Name'] : "#{component_name}-#{policy}" - cache_policy_config[:ParametersInCacheKeyAndForwardedToOrigin] = {} - cache_policy_config[:ParametersInCacheKeyAndForwardedToOrigin][:CookiesConfig] = {} - cache_policy_config[:ParametersInCacheKeyAndForwardedToOrigin][:CookiesConfig][:CookieBehavior] = policy_config.has_key?('CookieBehavior') ? policy_config['CookieBehavior'] : "none" - cache_policy_config[:ParametersInCacheKeyAndForwardedToOrigin][:CookiesConfig][:Cookies] = policy_config['Cookies'] if policy_config.has_key?('Cookies') - cache_policy_config[:ParametersInCacheKeyAndForwardedToOrigin][:EnableAcceptEncodingBrotli] = policy_config.has_key?('EnableAcceptEncodingBrotli') ? policy_config['EnableAcceptEncodingBrotli'] : false - cache_policy_config[:ParametersInCacheKeyAndForwardedToOrigin][:EnableAcceptEncodingGzip] = policy_config.has_key?('EnableAcceptEncodingGzip') ? policy_config['EnableAcceptEncodingGzip'] : true - cache_policy_config[:ParametersInCacheKeyAndForwardedToOrigin][:HeadersConfig] = {} - cache_policy_config[:ParametersInCacheKeyAndForwardedToOrigin][:HeadersConfig][:HeaderBehavior] = policy_config.has_key?('HeaderBehavior') ? policy_config['HeaderBehavior'] : 'none' - cache_policy_config[:ParametersInCacheKeyAndForwardedToOrigin][:HeadersConfig][:Headers] = policy_config['Headers'] if policy_config.has_key?('Headers') - cache_policy_config[:ParametersInCacheKeyAndForwardedToOrigin][:QueryStringsConfig] = {} - cache_policy_config[:ParametersInCacheKeyAndForwardedToOrigin][:QueryStringsConfig][:QueryStringBehavior] = policy_config.has_key?('QueryStringBehavior') ? policy_config['QueryStringBehavior'] : 'none' - cache_policy_config[:ParametersInCacheKeyAndForwardedToOrigin][:QueryStringsConfig][:QueryStrings] = policy_config['QueryStrings'] if policy_config.has_key?('QueryStrings') - policy_safe = policy.gsub(/[-_.]/,"") - CloudFront_CachePolicy("#{policy_safe}CloudFrontCachePolicy") { - CachePolicyConfig cache_policy_config - } - end + # Cache policies + cache_policies = external_parameters.fetch(:cache_policies, {}) + cache_policies.each do |policy, policy_config| + cache_policy_config = {} + cache_policy_config[:Comment] = policy_config['Comment'] if policy_config.has_key?('Comment') + cache_policy_config[:DefaultTTL] = policy_config.has_key?('DefaultTTL') ? policy_config['DefaultTTL'] : Ref('DefaultTTL') + cache_policy_config[:MaxTTL] = policy_config.has_key?('MaxTTL') ? policy_config['MaxTTL'] : Ref('MaxTTL') + cache_policy_config[:MinTTL] = policy_config.has_key?('MinTTL') ? policy_config['MinTTL'] : Ref('MinTTL') + cache_policy_config[:Name] = policy_config.has_key?('Name') ? policy_config['Name'] : FnJoin('-', [Ref('EnvironmentName'), "#{component_name}-#{policy}"]) + cache_policy_config[:ParametersInCacheKeyAndForwardedToOrigin] = {} + cache_policy_config[:ParametersInCacheKeyAndForwardedToOrigin][:CookiesConfig] = {} + cache_policy_config[:ParametersInCacheKeyAndForwardedToOrigin][:CookiesConfig][:CookieBehavior] = policy_config.has_key?('CookieBehavior') ? policy_config['CookieBehavior'] : "none" + cache_policy_config[:ParametersInCacheKeyAndForwardedToOrigin][:CookiesConfig][:Cookies] = policy_config['Cookies'] if policy_config.has_key?('Cookies') + cache_policy_config[:ParametersInCacheKeyAndForwardedToOrigin][:EnableAcceptEncodingBrotli] = policy_config.has_key?('EnableAcceptEncodingBrotli') ? policy_config['EnableAcceptEncodingBrotli'] : false + cache_policy_config[:ParametersInCacheKeyAndForwardedToOrigin][:EnableAcceptEncodingGzip] = policy_config.has_key?('EnableAcceptEncodingGzip') ? policy_config['EnableAcceptEncodingGzip'] : true + cache_policy_config[:ParametersInCacheKeyAndForwardedToOrigin][:HeadersConfig] = {} + cache_policy_config[:ParametersInCacheKeyAndForwardedToOrigin][:HeadersConfig][:HeaderBehavior] = policy_config.has_key?('HeaderBehavior') ? policy_config['HeaderBehavior'] : 'none' + cache_policy_config[:ParametersInCacheKeyAndForwardedToOrigin][:HeadersConfig][:Headers] = policy_config['Headers'] if policy_config.has_key?('Headers') + cache_policy_config[:ParametersInCacheKeyAndForwardedToOrigin][:QueryStringsConfig] = {} + cache_policy_config[:ParametersInCacheKeyAndForwardedToOrigin][:QueryStringsConfig][:QueryStringBehavior] = policy_config.has_key?('QueryStringBehavior') ? policy_config['QueryStringBehavior'] : 'none' + cache_policy_config[:ParametersInCacheKeyAndForwardedToOrigin][:QueryStringsConfig][:QueryStrings] = policy_config['QueryStrings'] if policy_config.has_key?('QueryStrings') + policy_safe = policy.gsub(/[-_.]/,"") + CloudFront_CachePolicy("#{policy_safe}CloudFrontCachePolicy") { + CachePolicyConfig cache_policy_config + } + end - # Origin request policies - origin_request_policies = external_parameters.fetch(:origin_request_policies, {}) - origin_request_policies.each do |request_policy, policy_config| - request_policy_config = {} - request_policy_config[:Comment] = policy_config['Comment'] if policy_config.has_key?('Comment') - request_policy_config[:Name] = policy_config.has_key?('Name') ? policy_config['Name'] : "#{component_name}-#{request_policy}" - request_policy_config[:CookiesConfig] = {} - request_policy_config[:CookiesConfig][:CookieBehavior] = policy_config.has_key?('CookieBehavior') ? policy_config['CookieBehavior'] : "none" - request_policy_config[:CookiesConfig][:Cookies] = policy_config['Cookies'] if policy_config.has_key?('Cookies') - request_policy_config[:HeadersConfig] = {} - request_policy_config[:HeadersConfig][:HeaderBehavior] = policy_config.has_key?('HeaderBehavior') ? policy_config['HeaderBehavior'] : 'none' - request_policy_config[:HeadersConfig][:Headers] = policy_config['Headers'] if policy_config.has_key?('Headers') - request_policy_config[:QueryStringsConfig] = {} - request_policy_config[:QueryStringsConfig][:QueryStringBehavior] = policy_config.has_key?('QueryStringBehavior') ? policy_config['QueryStringBehavior'] : 'none' - request_policy_config[:QueryStringsConfig][:QueryStrings] = policy_config['QueryStrings'] if policy_config.has_key?('QueryStrings') - request_policy_safe = request_policy.gsub(/[-_.]/,"") - CloudFront_OriginRequestPolicy("#{request_policy_safe}CloudFrontOriginRequestPolicy") { - OriginRequestPolicyConfig request_policy_config - } - end + # Origin request policies + origin_request_policies = external_parameters.fetch(:origin_request_policies, {}) + origin_request_policies.each do |request_policy, policy_config| + request_policy_config = {} + request_policy_config[:Comment] = policy_config['Comment'] if policy_config.has_key?('Comment') + request_policy_config[:Name] = policy_config.has_key?('Name') ? policy_config['Name'] : FnJoin('-', [Ref('EnvironmentName'), "#{component_name}-#{request_policy}"]) + request_policy_config[:CookiesConfig] = {} + request_policy_config[:CookiesConfig][:CookieBehavior] = policy_config.has_key?('CookieBehavior') ? policy_config['CookieBehavior'] : "none" + request_policy_config[:CookiesConfig][:Cookies] = policy_config['Cookies'] if policy_config.has_key?('Cookies') + request_policy_config[:HeadersConfig] = {} + request_policy_config[:HeadersConfig][:HeaderBehavior] = policy_config.has_key?('HeaderBehavior') ? policy_config['HeaderBehavior'] : 'none' + request_policy_config[:HeadersConfig][:Headers] = policy_config['Headers'] if policy_config.has_key?('Headers') + request_policy_config[:QueryStringsConfig] = {} + request_policy_config[:QueryStringsConfig][:QueryStringBehavior] = policy_config.has_key?('QueryStringBehavior') ? policy_config['QueryStringBehavior'] : 'none' + request_policy_config[:QueryStringsConfig][:QueryStrings] = policy_config['QueryStrings'] if policy_config.has_key?('QueryStrings') + request_policy_safe = request_policy.gsub(/[-_.]/,"") + CloudFront_OriginRequestPolicy("#{request_policy_safe}CloudFrontOriginRequestPolicy") { + OriginRequestPolicyConfig request_policy_config + } + end - # Functions - functions = external_parameters.fetch(:functions, {}) - functions.each do |func, fconfig| - func_safe = func.gsub(/[-_.]/,"") - func_conf = {} - func_conf['Comment'] = fconfig.has_key?('Comment') ? fconfig['Comment'] : FnJoin(" ", ["The", func, "CloudFrontFunction"]) - func_conf['Runtime'] = fconfig.has_key?('Runtime') ? fconfig['Runtime'] : "cloudfront-js-2.0" - func_conf['KeyValueStoreAssociations'] = fconfig['KeyValueStoreAssociations'] if fconfig.has_key?('KeyValueStoreAssociations') - CloudFront_Function("#{func_safe}CloudFrontFunction") do - AutoPublish fconfig.has_key?('AutoPublish') ? fconfig['AutoPublish'] : true - FunctionCode fconfig['code'] - Name fconfig.has_key?('Name') ? fconfig['Name'] : func_safe - FunctionConfig func_conf - end + # Response headers policies + response_headers_policies = external_parameters.fetch(:response_headers_policies, {}) + response_headers_policies.each do |response_policy, policy_config| + response_headers_policy_config = {} + response_headers_policy_config[:Comment] = policy_config['Comment'] if policy_config.has_key?('Comment') + response_headers_policy_config[:CorsConfig] = policy_config['CorsConfig'] if policy_config.has_key?('CorsConfig') + response_headers_policy_config[:CustomHeadersConfig] = {} if policy_config.has_key?('CustomHeadersConfig') + response_headers_policy_config[:CustomHeadersConfig]['Items'] = policy_config['CustomHeadersConfig'] if policy_config.has_key?('CustomHeadersConfig') + response_headers_policy_config[:Name] = policy_config.has_key?('Name') ? policy_config['Name'] : FnJoin('-', [Ref('EnvironmentName'), "#{component_name}-#{response_policy}"]) + response_headers_policy_config[:RemoveHeadersConfig] = {} if policy_config.has_key?('RemoveHeadersConfig') + response_headers_policy_config[:RemoveHeadersConfig]['Items'] = policy_config['RemoveHeadersConfig'] if policy_config.has_key?('RemoveHeadersConfig') + response_headers_policy_config[:SecurityHeadersConfig] = policy_config['SecurityHeadersConfig'] if policy_config.has_key?('SecurityHeadersConfig') + response_headers_policy_config[:ServerTimingHeadersConfig] = policy_config['ServerTimingHeadersConfig'] if policy_config.has_key?('ServerTimingHeadersConfig') + response_policy_safe = response_policy.gsub(/[-_.]/,"") + CloudFront_ResponseHeadersPolicy("#{response_policy_safe}CloudFrontResponseHeadersPolicy") { + ResponseHeadersPolicyConfig response_headers_policy_config + } + end + + # Functions + functions = external_parameters.fetch(:functions, {}) + functions.each do |func, fconfig| + func_safe = func.gsub(/[-_.]/,"") + func_conf = {} + func_conf['Comment'] = fconfig.has_key?('Comment') ? fconfig['Comment'] : FnJoin(" ", ["The", func, "CloudFrontFunction"]) + func_conf['Runtime'] = fconfig.has_key?('Runtime') ? fconfig['Runtime'] : "cloudfront-js-2.0" + func_conf['KeyValueStoreAssociations'] = fconfig['KeyValueStoreAssociations'] if fconfig.has_key?('KeyValueStoreAssociations') + CloudFront_Function("#{func_safe}CloudFrontFunction") do + AutoPublish fconfig.has_key?('AutoPublish') ? fconfig['AutoPublish'] : true + FunctionCode FunctionCode ((fconfig['code'] if fconfig.has_key?('code')) || (fconfig['FunctionCode'] if fconfig.has_key?('FunctionCode'))) + Name fconfig.has_key?('Name') ? fconfig['Name'] : func + FunctionConfig func_conf end + end - # Cache behaviours - behaviours = external_parameters.fetch(:behaviours, {}) - behaviours.each do |behaviour, config| - if behaviour == 'default' - if (config.has_key?('CachePolicyId')) + # Cache behaviours + behaviours = external_parameters.fetch(:behaviours, {}) + behaviours.each do |behaviour, config| + if behaviour == 'default' + # What if origin does not exists? - perform check + if (config.has_key?('TargetOriginId') and (!config['TargetOriginId'].nil?) and (origins.keys.include? config['TargetOriginId'])) + # What if the caching policy not defined? - perform check + if (config.has_key?('CachePolicyId') and (!config['CachePolicyId'].nil?) and (cache_policies.keys.include? config['CachePolicyId'])) config.delete('ForwardedValues') policy_safe = config['CachePolicyId'].gsub(/[-_.]/,"") config['CachePolicyId'] = { "Ref" => "#{policy_safe}CloudFrontCachePolicy" } + else + config['CachePolicyId'] = origins[config['TargetOriginId']]['default-caching-policy-id'] + if (config.has_key?('OriginRequestPolicyId') and (not config['OriginRequestPolicyId'].nil?)) + if (origin_request_policies.has_key?(config['OriginRequestPolicyId']) and (origin_request_policies[config['OriginRequestPolicyId']]['QueryStringBehavior'] != 'none')) + config['CachePolicyId'] = '4cc15a8a-d715-48a4-82b8-cc0b614638fe' # UseOriginCacheControlHeaders-QueryStrings + end + end + end + # What if the request policy not defined? - perform check + if (config.has_key?('OriginRequestPolicyId') and (!config['OriginRequestPolicyId'].nil?) and (origin_request_policies.keys.include? config['OriginRequestPolicyId'])) + request_policy_safe = config['OriginRequestPolicyId'].gsub(/[-_.]/,"") + config['OriginRequestPolicyId'] = { "Ref" => "#{request_policy_safe}CloudFrontOriginRequestPolicy" } + else + config.delete('OriginRequestPolicyId') end - request_policy_safe = config['OriginRequestPolicyId'].gsub(/[-_.]/,"") if config.has_key?('OriginRequestPolicyId') - config['OriginRequestPolicyId'] = { "Ref" => "#{request_policy_safe}CloudFrontOriginRequestPolicy" } if config.has_key?('OriginRequestPolicyId') - if config.has_key?('FunctionAssociation') - if config['FunctionAssociation'].has_key?('Function') - func_safe = config['FunctionAssociation']['Function'].gsub(/[-_.]/,"") - config['FunctionAssociation'].delete('Function') - config['FunctionAssociation']['EventType'] = 'viewer-request' if not config['FunctionAssociation'].has_key?('EventType') - config['FunctionAssociation']['FunctionARN'] = FnGetAtt("#{func_safe}CloudFrontFunction", "FunctionARN") + # What if the response headers policy not defined? - perform check + if (config.has_key?('ResponseHeadersPolicyId') and (!config['ResponseHeadersPolicyId'].nil?) and (response_headers_policies.keys.include? config['ResponseHeadersPolicyId'])) + response_policy_safe = config['ResponseHeadersPolicyId'].gsub(/[-_.]/,"") + config['ResponseHeadersPolicyId'] = { "Ref" => "#{response_policy_safe}CloudFrontResponseHeadersPolicy" } + else + config.delete('ResponseHeadersPolicyId') + end + if config.has_key?('FunctionAssociations') + config['FunctionAssociations'].uniq{ |k| k['EventType'] }.each do |assoc| + # What if function is not defined? - perform check + if (assoc.has_key?('Function') and (!assoc['Function'].nil?) and (functions.keys.include? assoc['Function'])) + func_safe = assoc['Function'].gsub(/[-_.]/,"") + assoc['EventType'] = 'viewer-request' if not assoc.has_key?('EventType') + assoc['FunctionARN'] = FnGetAtt("#{func_safe}CloudFrontFunction", "FunctionARN") + assoc.delete('Function') if assoc.has_key?('Function') + else + config['FunctionAssociations'].delete(assoc) + end end end distribution_config[:DefaultCacheBehavior] = config - else - config.each do |x| - if (x.has_key?('CachePolicyId')) + end + else + config.each do |x| + # What if origin does not exists? - perform check + if (x.has_key?('TargetOriginId') and (!x['TargetOriginId'].nil?) and (origins.keys.include? x['TargetOriginId'])) + # What if the caching policy not defined? - perform check + if (x.has_key?('CachePolicyId') and (!x['CachePolicyId'].nil?) and (cache_policies.keys.include? x['CachePolicyId'])) x.delete('ForwardedValues') policy_safe = x['CachePolicyId'].gsub(/[-_.]/,"") x['CachePolicyId'] = { "Ref" => "#{policy_safe}CloudFrontCachePolicy" } + else + x['CachePolicyId'] = origins[x['TargetOriginId']]['default-caching-policy-id'] + if (x.has_key?('OriginRequestPolicyId') and (not x['OriginRequestPolicyId'].nil?)) + if (origin_request_policies.has_key?(x['OriginRequestPolicyId']) and (origin_request_policies[x['OriginRequestPolicyId']]['QueryStringBehavior'] != 'none')) + x['CachePolicyId'] = '4cc15a8a-d715-48a4-82b8-cc0b614638fe' # UseOriginCacheControlHeaders-QueryStrings + end + end + end + # What if the request policy not defined? - perform check + if (x.has_key?('OriginRequestPolicyId') and (!x['OriginRequestPolicyId'].nil?) and (origin_request_policies.keys.include? x['OriginRequestPolicyId'])) + request_policy_safe = x['OriginRequestPolicyId'].gsub(/[-_.]/,"") + x['OriginRequestPolicyId'] = { "Ref" => "#{request_policy_safe}CloudFrontOriginRequestPolicy" } + else + x.delete('OriginRequestPolicyId') + end + # What if the response headers policy not defined? - perform check + if (x.has_key?('ResponseHeadersPolicyId') and (!x['ResponseHeadersPolicyId'].nil?) and (response_headers_policies.keys.include? x['ResponseHeadersPolicyId'])) + response_policy_safe = x['ResponseHeadersPolicyId'].gsub(/[-_.]/,"") + x['ResponseHeadersPolicyId'] = { "Ref" => "#{response_policy_safe}CloudFrontResponseHeadersPolicy" } + else + x.delete('ResponseHeadersPolicyId') end - request_policy_safe = x['OriginRequestPolicyId'].gsub(/[-_.]/,"") if x.has_key?('OriginRequestPolicyId') - x['OriginRequestPolicyId'] = { "Ref" => "#{request_policy_safe}CloudFrontOriginRequestPolicy" } if x.has_key?('OriginRequestPolicyId') - if x.has_key?('FunctionAssociation') - if x['FunctionAssociation'].has_key?('Function') - func_safe = x['FunctionAssociation']['Function'].gsub(/[-_.]/,"") - x['FunctionAssociation'].delete('Function') - x['FunctionAssociation']['EventType'] = 'viewer-request' if not x['FunctionAssociation'].has_key?('EventType') - x['FunctionAssociation']['FunctionARN'] = FnGetAtt("#{func_safe}CloudFrontFunction", "FunctionARN") + if x.has_key?('FunctionAssociations') + x['FunctionAssociations'].uniq{ |k| k['EventType'] }.each do |assoc| + # What if function is not defined? - perform check + if (assoc.has_key?('Function') and (!assoc['Function'].nil?) and (functions.keys.include? assoc['Function'])) + func_safe = assoc['Function'].gsub(/[-_.]/,"") + assoc['EventType'] = 'viewer-request' if not assoc.has_key?('EventType') + assoc['FunctionARN'] = FnGetAtt("#{func_safe}CloudFrontFunction", "FunctionARN") + assoc.delete('Function') if assoc.has_key?('Function') + else + x['FunctionAssociations'].delete(assoc) + end end end + else + config.delete(x) + end + if (config.length()>0) + distribution_config[:CacheBehaviors] = config end - distribution_config[:CacheBehaviors] = config end end + end # Aliases aliases_map = external_parameters.fetch(:aliases_map, {}) @@ -276,40 +352,44 @@ end end - CloudFront_Distribution(:Distribution) { - DependsOn dependencies_list - DistributionConfig distribution_config - Tags tags - } + if (distribution_config.has_key?(:DefaultCacheBehavior) and (!distribution_config[:DefaultCacheBehavior].nil?)) - dns_records = external_parameters.fetch(:dns_records, {}) - dns_records.each_with_index do |record, index| - if (dns_format.to_s.start_with?('{"Fn::')) - name = (['apex',''].include? record) ? FnJoin('', [dns_format]) : FnJoin('.', [record, dns_format]) - zone_name = FnJoin('', [dns_format, '.']) - else - name = (['apex',''].include? record) ? FnSub("#{dns_format}") : FnSub("#{record}.#{dns_format}") - zone_name = FnSub("#{dns_format}.") + CloudFront_Distribution(:Distribution) { + DependsOn dependencies_list + DistributionConfig distribution_config + Tags tags + } + + dns_records = external_parameters.fetch(:dns_records, {}) + dns_records.each_with_index do |record, index| + if (dns_format.to_s.start_with?('{"Fn::')) + name = (['apex',''].include? record) ? FnJoin('', [dns_format]) : FnJoin('.', [record, dns_format]) + zone_name = FnJoin('', [dns_format, '.']) + else + name = (['apex',''].include? record) ? FnSub("#{dns_format}") : FnSub("#{record}.#{dns_format}") + zone_name = FnSub("#{dns_format}.") + end + Route53_RecordSet("CloudfrontDns#{index}") do + HostedZoneName zone_name + Name name + Type 'A' + AliasTarget ({ + DNSName: FnGetAtt(:Distribution, :DomainName), + HostedZoneId: 'Z2FDTNDATAQYW2' + }) + end end - Route53_RecordSet("CloudfrontDns#{index}") do - HostedZoneName zone_name - Name name - Type 'A' - AliasTarget ({ - DNSName: FnGetAtt(:Distribution, :DomainName), - HostedZoneId: 'Z2FDTNDATAQYW2' - }) + + Output('DomainName') do + Value(FnGetAtt('Distribution', 'DomainName')) + Export FnJoin("-", [Ref("EnvironmentName"), export, "DomainName"]) end - end - Output('DomainName') do - Value(FnGetAtt('Distribution', 'DomainName')) - Export FnJoin("-", [Ref("EnvironmentName"), export, "DomainName"]) - end + Output('DistributionId') do + Value(FnGetAtt('Distribution', 'Id')) + Export FnJoin("-", [Ref("EnvironmentName"), export, "DistributionId"]) + end - Output('DistributionId') do - Value(FnGetAtt('Distribution', 'Id')) - Export FnJoin("-", [Ref("EnvironmentName"), export, "DistributionId"]) end end \ No newline at end of file diff --git a/cloudfront.config.yaml b/cloudfront.config.yaml index 9f67ddc..1d88a7a 100644 --- a/cloudfront.config.yaml +++ b/cloudfront.config.yaml @@ -1,14 +1,11 @@ - dns_format: ${EnvironmentName}.${DnsDomain} -# true | false enabled: true comment: ${EnvironmentName} distribution export_name: cloudfront -#default_root_object: index.html +# default_root_object: index.html -# http1.1 | http2 -http_version: http2 +http_version: http2 # http1.1|http2 # ipv6: false # custom_error_responses: @@ -23,20 +20,16 @@ http_version: http2 # source: loadbalancer # protocol_policy: https-only # custom_headers: - # - HeaderName: x-test-header - # HeaderValue: desiredvalue +# - HeaderName: x-test-header +# HeaderValue: desiredvalue ssl: - # acm | cloudfront | iam - type: cloudfront - # sni-only | vip - support_method: sni-only - # SSLv3 | TLSv1 | TLSv1_2016 | TLSv1.1_2016 | TLSv1.2_2018 - minimum_protocol_version: TLSv1.2_2018 + type: cloudfront # acm|cloudfront|iam + support_method: sni-only # sni-only|vip + minimum_protocol_version: TLSv1.2_2018 # SSLv3|TLSv1|TLSv1_2016|TLSv1.1_2016|TLSv1.2_2018 behaviours: default: - # GET, HEAD, OPTIONS, PUT, PATCH, POST, and DELETE AllowedMethods: - GET - HEAD @@ -46,8 +39,7 @@ behaviours: Cookies: Forward: none QueryString: true - # allow-all | redirect-to-https | https-only - ViewerProtocolPolicy: redirect-to-https + ViewerProtocolPolicy: redirect-to-https # allow-all|redirect-to-https|https-only # nondefaultcachebehaviours: # - # AllowedMethods: @@ -60,7 +52,6 @@ behaviours: # Cookies: # Forward: none # QueryString: false - # # allow-all | redirect-to-https | https-only # ViewerProtocolPolicy: redirect-to-https # PathPattern: /index.html diff --git a/tests/cache_policies.test.yaml b/tests/cache_policies.test.yaml index 060b7b6..3f98c31 100644 --- a/tests/cache_policies.test.yaml +++ b/tests/cache_policies.test.yaml @@ -3,11 +3,9 @@ test_metadata: name: cache policies description: Create custom cache policies - origins: myapploadbalancer: source: loadbalancer - # http-only | match-viewer | https-only protocol_policy: https-only ssl_protocols: - TLSv1.2 @@ -15,16 +13,16 @@ origins: cache_policies: full: Comment: Full Cache Policy - DefaultTTL: 86400 # Required - MaxTTL: 31536000 # Required - MinTTL: 0 # Required - Name: Full-Policy. # Required - CookieBehavior: none # none|whitelist|allExcept|all Required + DefaultTTL: 86400 + MaxTTL: 31536000 + MinTTL: 0 + Name: Full-Policy + CookieBehavior: whitelist Cookies: - someValue EnableAcceptEncodingBrotli: false - EnableAcceptEncodingGzip: true # Required - HeaderBehavior: none # none|whitelist Required + EnableAcceptEncodingGzip: true + HeaderBehavior: whitelist Headers: - Host - CloudFront-Viewer-Country @@ -33,6 +31,20 @@ cache_policies: - Host - CloudFront-Viewer-Country +response_headers_policies: + resp: + Comment: The response headers policy + SecurityHeadersConfig: + ContentTypeOptions: + Override: true + +origin_request_policies: + origin-default: + Comment: the origin request policy for here + CookieBehavior: none + HeaderBehavior: allViewer + QueryStringBehavior: all + behaviours: default: AllowedMethods: @@ -49,9 +61,9 @@ behaviours: Headers: - "CloudFront-Viewer-Country" Cookies: - Forward: all # none # Drift detected on STAGE and PROD as well + Forward: all QueryString: true - ViewerProtocolPolicy: redirect-to-https # allow-all|redirect-to-https|https-only + ViewerProtocolPolicy: redirect-to-https custom: - PathPattern: /api* @@ -61,4 +73,6 @@ behaviours: - OPTIONS Compress: true TargetOriginId: myapploadbalancer - CachePolicyId: minimal \ No newline at end of file + CachePolicyId: minimal + OriginRequestPolicyId: origin-default + ResponseHeadersPolicyId: resp \ No newline at end of file diff --git a/tests/functions.test.yaml b/tests/functions.test.yaml index 06712b3..4ad269a 100644 --- a/tests/functions.test.yaml +++ b/tests/functions.test.yaml @@ -3,12 +3,10 @@ test_metadata: name: functions description: Create cloudfront functions - origins: myapploadbalancer: source: loadbalancer - # http-only | match-viewer | https-only - protocol_policy: https-only + protocol_policy: https-only # http-only|match-viewer|https-only ssl_protocols: - TLSv1.2 @@ -23,13 +21,20 @@ functions: return request; } custom-viewer-request: - code: | + Name: + Fn::Join: + - '-' + - - Ref: EnvironmentName + - custom-viewer-request + #`FunctionCode` or `code` + FunctionCode: | async function handler(event) { const request = event.request; const uri = request.uri; if (uri.endsWith('/')) { request.uri += 'index.html'; } else if (!uri.includes('.')) { request.uri += '/index.html'; } return request; + } behaviours: default: @@ -42,14 +47,14 @@ behaviours: - POST - DELETE TargetOriginId: myapploadbalancer - FunctionAssociation: - EventType: viewer-request # viewer-request|viewer-response|origin-request|origin-response - Function: default-viewer-request + FunctionAssociations: + - EventType: viewer-request # viewer-request|viewer-response|origin-request|origin-response + Function: default-viewer-request ForwardedValues: Headers: - "CloudFront-Viewer-Country" Cookies: - Forward: all # none # Drift detected on STAGE and PROD as well + Forward: all QueryString: true ViewerProtocolPolicy: redirect-to-https # allow-all|redirect-to-https|https-only custom: @@ -61,5 +66,5 @@ behaviours: - OPTIONS Compress: true TargetOriginId: myapploadbalancer - FunctionAssociation: - Function: custom-viewer-request \ No newline at end of file + FunctionAssociations: + - Function: custom-viewer-request \ No newline at end of file diff --git a/tests/origin_polices.test.yaml b/tests/origin_polices.test.yaml index 467c5fd..898d52a 100644 --- a/tests/origin_polices.test.yaml +++ b/tests/origin_polices.test.yaml @@ -3,34 +3,29 @@ test_metadata: name: origin policies description: Create custom cache policies - origins: myapploadbalancer: source: loadbalancer - # http-only | match-viewer | https-only - protocol_policy: https-only + protocol_policy: https-only # http-only|match-viewer|https-only ssl_protocols: - TLSv1.2 origin_request_policies: origin-full: Comment: the origin request policy for here - CookieBehavior: none # none|whitelist|allExcept|all Required + CookieBehavior: whitelist # none|whitelist|allExcept|all Cookies: - someValue - HeaderBehavior: none # none|whitelist Required + HeaderBehavior: whitelist Headers: - Host - CloudFront-Viewer-Country - Name: Policy-for-here # Required - QueryStringBehavior: none # none|whitelist|all|allExcept Required - QueryStrings: - - someValue + Name: Policy-for-here + QueryStringBehavior: none origin-minimal: Headers: - Host - behaviours: default: AllowedMethods: @@ -47,7 +42,7 @@ behaviours: Headers: - "CloudFront-Viewer-Country" Cookies: - Forward: all # none # Drift detected on STAGE and PROD as well + Forward: all QueryString: true ViewerProtocolPolicy: redirect-to-https # allow-all|redirect-to-https|https-only custom: