示例#1
0
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        self.Enabled = 'True'
        DefaultCacheBehavior = CFDefaultCacheBehavior(
            'CloudFrontCacheBehaviors0', key=cfg.CloudFrontCacheBehaviors[0])
        self.DefaultCacheBehavior = DefaultCacheBehavior
        self.HttpVersion = get_endvalue('CloudFrontHttpVersion')
        self.Logging = If(
            'CloudFrontLogging',
            clf.Logging(
                Bucket=Sub(f'{cfg.BucketLogs}.s3.amazonaws.com'),
                Prefix=Sub('${EnvRole}.${AWS::StackName}/'),
            ), Ref('AWS::NoValue'))
        self.PriceClass = 'PriceClass_100'
        self.ViewerCertificate = clf.ViewerCertificate()
        self.ViewerCertificate.AcmCertificateArn = If(
            'CloudFrontAcmCertificate', get_endvalue('GlobalCertificateArn'),
            Ref('AWS::NoValue'))
        self.ViewerCertificate.CloudFrontDefaultCertificate = If(
            'CloudFrontAcmCertificate', Ref('AWS::NoValue'), 'True')
        self.ViewerCertificate.SslSupportMethod = If(
            'CloudFrontAcmCertificate', 'sni-only', Ref('AWS::NoValue'))
        self.ViewerCertificate.MinimumProtocolVersion = If(
            'CloudFrontAcmCertificate',
            get_endvalue('CloudFrontMinimumProtocolVersion'),
            Ref('AWS::NoValue'))
        self.WebACLId = get_endvalue('CloudFrontWebACLId', condition=True)
示例#2
0
 def add_logging_bucket(self):
     # type: () -> Union[cloudfront.Logging, NoValue]
     """Add Logging Bucket."""
     if self.cf_logging_enabled:
         return cloudfront.Logging(Bucket=Join(
             '.',
             [self.get_variables()['LogBucketName'], 's3.amazonaws.com']))
     return NoValue
示例#3
0
    def test_logging(self):

        logging = cloudfront.Logging(
            Bucket='mytestbucket',
            IncludeCookies=True,
            Prefix='myprefix',
        )

        d = logging.to_dict()
        self.assertEquals(d['IncludeCookies'], True)
示例#4
0
文件: trop.py 项目: swipswaps/builder
def render_cloudfront(context, template, origin_hostname):
    if not context['cloudfront']['origins']:
        ensure(
            context['full_hostname'],
            "A public hostname is required to be pointed at by the Cloudfront CDN"
        )

    allowed_cnames = context['cloudfront']['subdomains'] + context[
        'cloudfront']['subdomains-without-dns']

    def _cookies(cookies):
        if cookies:
            return cloudfront.Cookies(Forward='whitelist',
                                      WhitelistedNames=cookies)
        return cloudfront.Cookies(Forward='none')

    if context['cloudfront']['origins']:
        origins = [
            cloudfront.Origin(DomainName=o['hostname'],
                              Id=o_id,
                              CustomOriginConfig=cloudfront.CustomOrigin(
                                  HTTPSPort=443,
                                  OriginProtocolPolicy='https-only'))
            for o_id, o in context['cloudfront']['origins'].items()
        ]
        origin = origins[0].Id
    else:
        origin = CLOUDFRONT_TITLE + 'Origin'
        origins = [
            cloudfront.Origin(DomainName=origin_hostname,
                              Id=origin,
                              CustomOriginConfig=cloudfront.CustomOrigin(
                                  HTTPSPort=443,
                                  OriginProtocolPolicy='https-only'))
        ]
    props = {
        'Aliases':
        allowed_cnames,
        'CacheBehaviors': [],
        'DefaultCacheBehavior':
        cloudfront.DefaultCacheBehavior(
            AllowedMethods=[
                'DELETE', 'GET', 'HEAD', 'OPTIONS', 'PATCH', 'POST', 'PUT'
            ],
            CachedMethods=['GET', 'HEAD'],
            Compress=context['cloudfront']['compress'],
            DefaultTTL=context['cloudfront']['default-ttl'],
            TargetOriginId=origin,
            ForwardedValues=cloudfront.ForwardedValues(
                Cookies=_cookies(context['cloudfront']['cookies']),
                Headers=context['cloudfront']
                ['headers'],  # 'whitelisted' headers
                QueryString=True),
            ViewerProtocolPolicy='redirect-to-https',
        ),
        'Enabled':
        True,
        'HttpVersion':
        'http2',
        'Origins':
        origins,
        'ViewerCertificate':
        cloudfront.ViewerCertificate(
            IamCertificateId=context['cloudfront']['certificate_id'],
            SslSupportMethod='sni-only')
    }

    def _cache_behavior(origin_id, pattern, headers=None, cookies=None):
        return cloudfront.CacheBehavior(
            TargetOriginId=origin_id,
            DefaultTTL=context['cloudfront']['default-ttl'],
            ForwardedValues=cloudfront.ForwardedValues(
                Cookies=_cookies(cookies),
                QueryString=False,
                Headers=headers if headers else []),
            PathPattern=pattern,
            ViewerProtocolPolicy='allow-all',
        )

    if context['cloudfront']['errors']:
        props['Origins'].append(
            cloudfront.Origin(
                DomainName=context['cloudfront']['errors']['domain'],
                # TODO: constant
                Id=CLOUDFRONT_ERROR_ORIGIN_ID,
                # no advantage in using cloudfront.S3Origin for public buckets
                CustomOriginConfig=cloudfront.CustomOrigin(
                    HTTPSPort=443,
                    OriginProtocolPolicy='https-only'
                    if context['cloudfront']['errors']['protocol'] == 'https'
                    else 'http-only')))
        props['CacheBehaviors'].append(
            _cache_behavior(
                CLOUDFRONT_ERROR_ORIGIN_ID,
                context['cloudfront']['errors']['pattern'],
            ))
        props['CustomErrorResponses'] = [
            cloudfront.CustomErrorResponse(ErrorCode=code,
                                           ResponseCode=code,
                                           ResponsePagePath=page)
            for code, page in context['cloudfront']['errors']['codes'].items()
        ]

    if context['cloudfront']['logging']:
        props['Logging'] = cloudfront.Logging(
            Bucket="%s.s3.amazonaws.com" %
            context['cloudfront']['logging']['bucket'],
            Prefix="%s/" % context['stackname'])

    if context['cloudfront']['origins']:
        props['CacheBehaviors'].extend([
            _cache_behavior(o_id,
                            o['pattern'],
                            headers=o['headers'],
                            cookies=o['cookies'])
            for o_id, o in context['cloudfront']['origins'].items()
            if o['pattern']
        ])

    template.add_resource(
        cloudfront.Distribution(
            CLOUDFRONT_TITLE,
            DistributionConfig=cloudfront.DistributionConfig(**props)))

    for dns in external_dns_cloudfront(context):
        template.add_resource(dns)
示例#5
0
 def add_logging_bucket(self) -> Union[cloudfront.Logging, Ref]:
     """Add Logging Bucket."""
     if self.cf_logging_enabled:
         return cloudfront.Logging(Bucket=Join(
             ".", [self.variables["LogBucketName"], "s3.amazonaws.com"]))
     return NoValue
示例#6
0
    def create_template(self):
        """Create template (main function called by Stacker)."""
        template = self.template
        variables = self.get_variables()
        template.set_version('2010-09-09')
        template.set_description('Static Website - Bucket and Distribution')

        # Conditions
        template.add_condition(
            'AcmCertSpecified',
            And(Not(Equals(variables['AcmCertificateArn'].ref, '')),
                Not(Equals(variables['AcmCertificateArn'].ref, 'undefined')))
        )
        template.add_condition(
            'AliasesSpecified',
            And(Not(Equals(Select(0, variables['Aliases'].ref), '')),
                Not(Equals(Select(0, variables['Aliases'].ref), 'undefined')))
        )
        template.add_condition(
            'CFLoggingEnabled',
            And(Not(Equals(variables['LogBucketName'].ref, '')),
                Not(Equals(variables['LogBucketName'].ref, 'undefined')))
        )
        template.add_condition(
            'DirectoryIndexSpecified',
            And(Not(Equals(variables['RewriteDirectoryIndex'].ref, '')),
                Not(Equals(variables['RewriteDirectoryIndex'].ref, 'undefined')))  # noqa
        )
        template.add_condition(
            'WAFNameSpecified',
            And(Not(Equals(variables['WAFWebACL'].ref, '')),
                Not(Equals(variables['WAFWebACL'].ref, 'undefined')))
        )

        # Resources
        oai = template.add_resource(
            cloudfront.CloudFrontOriginAccessIdentity(
                'OAI',
                CloudFrontOriginAccessIdentityConfig=cloudfront.CloudFrontOriginAccessIdentityConfig(  # noqa pylint: disable=line-too-long
                    Comment='CF access to website'
                )
            )
        )

        bucket = template.add_resource(
            s3.Bucket(
                'Bucket',
                AccessControl=s3.Private,
                LifecycleConfiguration=s3.LifecycleConfiguration(
                    Rules=[
                        s3.LifecycleRule(
                            NoncurrentVersionExpirationInDays=90,
                            Status='Enabled'
                        )
                    ]
                ),
                VersioningConfiguration=s3.VersioningConfiguration(
                    Status='Enabled'
                ),
                WebsiteConfiguration=s3.WebsiteConfiguration(
                    IndexDocument='index.html',
                    ErrorDocument='error.html'
                )
            )
        )
        template.add_output(Output(
            'BucketName',
            Description='Name of website bucket',
            Value=bucket.ref()
        ))

        allowcfaccess = template.add_resource(
            s3.BucketPolicy(
                'AllowCFAccess',
                Bucket=bucket.ref(),
                PolicyDocument=PolicyDocument(
                    Version='2012-10-17',
                    Statement=[
                        Statement(
                            Action=[awacs.s3.GetObject],
                            Effect=Allow,
                            Principal=Principal(
                                'CanonicalUser',
                                oai.get_att('S3CanonicalUserId')
                            ),
                            Resource=[
                                Join('', [bucket.get_att('Arn'),
                                          '/*'])
                            ]
                        )
                    ]
                )
            )
        )

        cfdirectoryindexrewriterole = template.add_resource(
            iam.Role(
                'CFDirectoryIndexRewriteRole',
                Condition='DirectoryIndexSpecified',
                AssumeRolePolicyDocument=PolicyDocument(
                    Version='2012-10-17',
                    Statement=[
                        Statement(
                            Effect=Allow,
                            Action=[awacs.sts.AssumeRole],
                            Principal=Principal('Service',
                                                ['lambda.amazonaws.com',
                                                 'edgelambda.amazonaws.com'])
                        )
                    ]
                ),
                ManagedPolicyArns=[
                    IAM_ARN_PREFIX + 'AWSLambdaBasicExecutionRole'
                ]
            )
        )

        cfdirectoryindexrewrite = template.add_resource(
            awslambda.Function(
                'CFDirectoryIndexRewrite',
                Condition='DirectoryIndexSpecified',
                Code=awslambda.Code(
                    ZipFile=Join(
                        '',
                        ["'use strict';\n",
                         "exports.handler = (event, context, callback) => {\n",
                         "\n",
                         "    // Extract the request from the CloudFront event that is sent to Lambda@Edge\n",  # noqa pylint: disable=line-too-long
                         "    var request = event.Records[0].cf.request;\n",
                         "    // Extract the URI from the request\n",
                         "    var olduri = request.uri;\n",
                         "    // Match any '/' that occurs at the end of a URI. Replace it with a default index\n",  # noqa pylint: disable=line-too-long
                         "    var newuri = olduri.replace(/\\/$/, '\\/",
                         variables['RewriteDirectoryIndex'].ref,
                         "');\n",  # noqa
                         "    // Log the URI as received by CloudFront and the new URI to be used to fetch from origin\n",  # noqa pylint: disable=line-too-long
                         "    console.log(\"Old URI: \" + olduri);\n",
                         "    console.log(\"New URI: \" + newuri);\n",
                         "    // Replace the received URI with the URI that includes the index page\n",  # noqa pylint: disable=line-too-long
                         "    request.uri = newuri;\n",
                         "    // Return to CloudFront\n",
                         "    return callback(null, request);\n",
                         "\n",
                         "};\n"]
                    )
                ),
                Description='Rewrites CF directory HTTP requests to default page',  # noqa
                Handler='index.handler',
                Role=cfdirectoryindexrewriterole.get_att('Arn'),
                Runtime='nodejs8.10'
            )
        )

        # Generating a unique resource name here for the Lambda version, so it
        # updates automatically if the lambda code changes
        code_hash = hashlib.md5(
            str(cfdirectoryindexrewrite.properties['Code'].properties['ZipFile'].to_dict()).encode()  # noqa pylint: disable=line-too-long
        ).hexdigest()

        cfdirectoryindexrewritever = template.add_resource(
            awslambda.Version(
                'CFDirectoryIndexRewriteVer' + code_hash,
                Condition='DirectoryIndexSpecified',
                FunctionName=cfdirectoryindexrewrite.ref()
            )
        )

        # If custom associations defined, use them
        if variables['lambda_function_associations']:
            lambda_function_associations = [
                cloudfront.LambdaFunctionAssociation(
                    EventType=x['type'],
                    LambdaFunctionARN=x['arn']
                ) for x in variables['lambda_function_associations']
            ]
        else:  # otherwise fallback to pure CFN condition
            lambda_function_associations = If(
                'DirectoryIndexSpecified',
                [cloudfront.LambdaFunctionAssociation(
                    EventType='origin-request',
                    LambdaFunctionARN=cfdirectoryindexrewritever.ref()
                )],
                NoValue
            )

        cfdistribution = template.add_resource(
            get_cf_distribution_class()(
                'CFDistribution',
                DependsOn=allowcfaccess.title,
                DistributionConfig=get_cf_distro_conf_class()(
                    Aliases=If(
                        'AliasesSpecified',
                        variables['Aliases'].ref,
                        NoValue
                    ),
                    Origins=[
                        get_cf_origin_class()(
                            DomainName=Join(
                                '.',
                                [bucket.ref(),
                                 's3.amazonaws.com']),
                            S3OriginConfig=get_s3_origin_conf_class()(
                                OriginAccessIdentity=Join(
                                    '',
                                    ['origin-access-identity/cloudfront/',
                                     oai.ref()])
                            ),
                            Id='S3Origin'
                        )
                    ],
                    DefaultCacheBehavior=cloudfront.DefaultCacheBehavior(
                        AllowedMethods=['GET', 'HEAD'],
                        Compress=False,
                        DefaultTTL='86400',
                        ForwardedValues=cloudfront.ForwardedValues(
                            Cookies=cloudfront.Cookies(Forward='none'),
                            QueryString=False,
                        ),
                        LambdaFunctionAssociations=lambda_function_associations,  # noqa
                        TargetOriginId='S3Origin',
                        ViewerProtocolPolicy='redirect-to-https'
                    ),
                    DefaultRootObject='index.html',
                    Logging=If(
                        'CFLoggingEnabled',
                        cloudfront.Logging(
                            Bucket=Join('.',
                                        [variables['LogBucketName'].ref,
                                         's3.amazonaws.com'])
                        ),
                        NoValue
                    ),
                    PriceClass=variables['PriceClass'].ref,
                    Enabled=True,
                    WebACLId=If(
                        'WAFNameSpecified',
                        variables['WAFWebACL'].ref,
                        NoValue
                    ),
                    ViewerCertificate=If(
                        'AcmCertSpecified',
                        cloudfront.ViewerCertificate(
                            AcmCertificateArn=variables['AcmCertificateArn'].ref,  # noqa
                            SslSupportMethod='sni-only'
                        ),
                        NoValue
                    )
                )
            )
        )
        template.add_output(Output(
            'CFDistributionId',
            Description='CloudFront distribution ID',
            Value=cfdistribution.ref()
        ))
        template.add_output(
            Output(
                'CFDistributionDomainName',
                Description='CloudFront distribution domain name',
                Value=cfdistribution.get_att('DomainName')
            )
        )
    def cloudfront_distribution(self):
        if self.vars["AcmCertificateARN"]:
            viewer_certificate = cf.ViewerCertificate(
                SslSupportMethod="sni-only",
                MinimumProtocolVersion="TLSv1",
                AcmCertificateArn=self.vars["AcmCertificateARN"],
            )
            url_prefix = 'https://'
        else:
            viewer_certificate = NoValue
            url_prefix = 'http://'

        t = self.template
        self.SiteCFDistribution = t.add_resource(
            cf.Distribution(
                "SiteCFDistribution",
                DistributionConfig=cf.DistributionConfig(
                    Comment="S3 Distribution",
                    Logging=cf.Logging(
                        Prefix=self.vars["FQDNPublic"] + "/cloudfront_logs/",
                        Bucket=self.vars["LogBucket"] + ".s3.amazonaws.com",
                        IncludeCookies="false"),
                    WebACLId=self.vars["WebACLId"],
                    Origins=[
                        cf.Origin(
                            S3OriginConfig=cf.S3Origin(OriginAccessIdentity=(
                                "origin-access-identity/cloudfront/" +
                                self.vars["OriginAccessIdentity"]), ),
                            Id="myS3Origin",
                            DomainName=GetAtt(self.SiteBucket, "DomainName"),
                            OriginPath=self.vars["OriginPath"],
                        )
                    ],
                    DefaultRootObject=self.vars["DefaultRootObject"],
                    PriceClass="PriceClass_100",
                    Enabled="true",
                    DefaultCacheBehavior=cf.DefaultCacheBehavior(
                        ViewerProtocolPolicy="redirect-to-https",
                        ForwardedValues=cf.ForwardedValues(
                            Cookies=cf.Cookies(Forward="none"),
                            QueryString="true"),
                        TargetOriginId="myS3Origin",
                        DefaultTTL=self.vars["DefaultTTL"],
                    ),
                    Aliases=[self.vars["FQDNPublic"]],
                    ViewerCertificate=viewer_certificate,
                ),
            ))

        CloudFrontDistribution = t.add_output(
            Output(
                "CloudFrontDistribution",
                Description="Cloudfront distribution domainname in AWS",
                Value=GetAtt(self.SiteCFDistribution, "DomainName"),
            ))
        WebsiteURL = t.add_output(
            Output(
                "WebsiteURL",
                Description="Public URL of cloudfront hosted website",
                Value=url_prefix + self.vars["FQDNPublic"],
            ))
示例#8
0
    def create_template(self):
        """Create template (main function called by Stacker)."""
        template = self.template
        variables = self.get_variables()
        template.add_version('2010-09-09')
        template.add_description('Static Website - Bucket and Distribution')

        # Conditions
        template.add_condition(
            'AcmCertSpecified',
            And(Not(Equals(variables['AcmCertificateArn'].ref, '')),
                Not(Equals(variables['AcmCertificateArn'].ref, 'undefined'))))
        template.add_condition(
            'AliasesSpecified',
            And(Not(Equals(Select(0, variables['Aliases'].ref), '')),
                Not(Equals(Select(0, variables['Aliases'].ref), 'undefined'))))
        template.add_condition(
            'CFLoggingEnabled',
            And(Not(Equals(variables['LogBucketName'].ref, '')),
                Not(Equals(variables['LogBucketName'].ref, 'undefined'))))
        template.add_condition(
            'WAFNameSpecified',
            And(Not(Equals(variables['WAFWebACL'].ref, '')),
                Not(Equals(variables['WAFWebACL'].ref, 'undefined'))))

        # Resources
        oai = template.add_resource(
            cloudfront.CloudFrontOriginAccessIdentity(
                'OAI',
                CloudFrontOriginAccessIdentityConfig=cloudfront.
                CloudFrontOriginAccessIdentityConfig(  # noqa pylint: disable=line-too-long
                    Comment='CF access to website')))

        bucket = template.add_resource(
            s3.Bucket(
                'Bucket',
                AccessControl=s3.Private,
                LifecycleConfiguration=s3.LifecycleConfiguration(Rules=[
                    s3.LifecycleRule(NoncurrentVersionExpirationInDays=90,
                                     Status='Enabled')
                ]),
                VersioningConfiguration=s3.VersioningConfiguration(
                    Status='Enabled'),
                WebsiteConfiguration=s3.WebsiteConfiguration(
                    IndexDocument='index.html', ErrorDocument='error.html')))
        template.add_output(
            Output('BucketName',
                   Description='Name of website bucket',
                   Value=bucket.ref()))

        allowcfaccess = template.add_resource(
            s3.BucketPolicy(
                'AllowCFAccess',
                Bucket=bucket.ref(),
                PolicyDocument=Policy(
                    Version='2012-10-17',
                    Statement=[
                        Statement(
                            Action=[awacs.s3.GetObject],
                            Effect=Allow,
                            Principal=Principal(
                                'CanonicalUser',
                                oai.get_att('S3CanonicalUserId')),
                            Resource=[Join('', [bucket.get_att('Arn'), '/*'])])
                    ])))

        cfdistribution = template.add_resource(
            cloudfront.Distribution(
                'CFDistribution',
                DependsOn=allowcfaccess.title,
                DistributionConfig=cloudfront.DistributionConfig(
                    Aliases=If('AliasesSpecified', variables['Aliases'].ref,
                               NoValue),
                    Origins=[
                        cloudfront.Origin(
                            DomainName=Join(
                                '.', [bucket.ref(), 's3.amazonaws.com']),
                            S3OriginConfig=cloudfront.S3Origin(
                                OriginAccessIdentity=Join(
                                    '', [
                                        'origin-access-identity/cloudfront/',
                                        oai.ref()
                                    ])),
                            Id='S3Origin')
                    ],
                    DefaultCacheBehavior=cloudfront.DefaultCacheBehavior(
                        AllowedMethods=['GET', 'HEAD'],
                        Compress=False,
                        DefaultTTL='86400',
                        ForwardedValues=cloudfront.ForwardedValues(
                            Cookies=cloudfront.Cookies(Forward='none'),
                            QueryString=False,
                        ),
                        TargetOriginId='S3Origin',
                        ViewerProtocolPolicy='redirect-to-https'),
                    DefaultRootObject='index.html',
                    Logging=If(
                        'CFLoggingEnabled',
                        cloudfront.Logging(Bucket=Join('.', [
                            variables['LogBucketName'].ref, 's3.amazonaws.com'
                        ])), NoValue),
                    PriceClass=variables['PriceClass'].ref,
                    Enabled=True,
                    WebACLId=If('WAFNameSpecified', variables['WAFWebACL'].ref,
                                NoValue),
                    ViewerCertificate=If(
                        'AcmCertSpecified',
                        cloudfront.ViewerCertificate(
                            AcmCertificateArn=variables['AcmCertificateArn'].
                            ref,  # noqa
                            SslSupportMethod='sni-only'),
                        NoValue))))
        template.add_output(
            Output('CFDistributionId',
                   Description='CloudFront distribution ID',
                   Value=cfdistribution.ref()))
        template.add_output(
            Output('CFDistributionDomainName',
                   Description='CloudFront distribution domain name',
                   Value=cfdistribution.get_att('DomainName')))