Example #1
0
    def _create_cloudfront_distribution(self):
        """Create a cloudfront distribution with a public bucket as the origin"""
        origin_source = cloudfront.CustomOriginConfig(
            domain_name=self.bucket.bucket_website_domain_name,
            origin_protocol_policy=cloudfront.OriginProtocolPolicy.HTTP_ONLY,
            origin_headers={"Referer": self.__origin_referer_header},
        )

        self.distribution = cloudfront.CloudFrontWebDistribution(
            self,
            "cloudfront_distribution",
            alias_configuration=cloudfront.AliasConfiguration(
                acm_cert_ref=self.certificate.certificate_arn,
                names=[self._site_domain_name],
                ssl_method=cloudfront.SSLMethod.SNI,
                security_policy=cloudfront.SecurityPolicyProtocol.
                TLS_V1_2_2019,
            ),
            origin_configs=[
                cloudfront.SourceConfiguration(
                    custom_origin_source=origin_source,
                    behaviors=[
                        cloudfront.Behavior(is_default_behavior=True, )
                    ],
                )
            ],
            viewer_protocol_policy=cloudfront.ViewerProtocolPolicy.
            REDIRECT_TO_HTTPS,
            price_class=cloudfront.PriceClass.PRICE_CLASS_ALL,
        )
Example #2
0
    def __init__(self, scope: core.Construct, id: str, bucket_name: str,
                 cf_id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # The code that defines your stack goes here
        bucket = s3.Bucket(self,
                           id=id,
                           bucket_name=bucket_name,
                           access_control=s3.BucketAccessControl.PUBLIC_READ,
                           website_index_document="index.html")
        bucket.grant_public_access()
        cert = acm.Certificate(self,
                               "Cert",
                               domain_name=bucket_name,
                               validation=acm.CertificateValidation.from_dns())

        cf.CloudFrontWebDistribution(
            self,
            id=cf_id,
            price_class=cf.PriceClass.PRICE_CLASS_200,
            origin_configs=[
                cf.SourceConfiguration(
                    behaviors=[cf.Behavior(is_default_behavior=True)],
                    s3_origin_source=cf.S3OriginConfig(
                        s3_bucket_source=bucket))
            ],
            alias_configuration=cf.AliasConfiguration(
                names=[bucket_name], acm_cert_ref=cert.certificate_arn))
Example #3
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        self.bucket = s3.Bucket(
            self,
            "bucket",
            website_index_document=f"{stack_vars.root_html}",
            bucket_name=f"{stack_vars.bucket_name}")
        self.bucket.grant_public_access()
        names = [f"{stack_vars.bucket_name}", f"www.{stack_vars.bucket_name}"],

        cf.CloudFrontWebDistribution(
            self,
            "cloudwebdistribution",
            price_class=cf.PriceClass.PRICE_CLASS_ALL,
            default_root_object=f"{stack_vars.root_html}",
            alias_configuration=cf.AliasConfiguration(
                ssl_method=cf.SSLMethod.SNI,
                acm_cert_ref=stack_vars.cert_arn,
                names=[
                    f"{stack_vars.bucket_name}",
                    f"www.{stack_vars.bucket_name}"
                ],
                security_policy=cf.SecurityPolicyProtocol.TLS_V1_2_2018),
            origin_configs=[
                cf.SourceConfiguration(
                    behaviors=[cf.Behavior(is_default_behavior=True)],
                    s3_origin_source=cf.S3OriginConfig(
                        s3_bucket_source=self.bucket))
            ])
Example #4
0
    def __init__(self, scope: core.Construct, id: str, s3bucket,acmcert, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        prj_name = self.node.try_get_context("project_name")
        env_name = self.node.try_get_context("env")

        bucketName = s3.Bucket.from_bucket_name(self,'s3bucket',s3bucket)

        self.cdn_id = cdn.CloudFrontWebDistribution(self,'webhosting-cdn',
            origin_configs=[cdn.SourceConfiguration(
                behaviors=[
                    cdn.Behavior(is_default_behavior=True)
                ],
                origin_path="/build",
                s3_origin_source=cdn.S3OriginConfig(
                    s3_bucket_source=bucketName,
                    origin_access_identity=cdn.OriginAccessIdentity(self,'webhosting-origin')
                )

            )],
            error_configurations=[cdn.CfnDistribution.CustomErrorResponseProperty(
                error_code=400,
                response_code=200,
                response_page_path="/"

            ),
                cdn.CfnDistribution.CustomErrorResponseProperty(
                    error_code=403,
                    response_code=200,
                    response_page_path="/"
                ),
                cdn.CfnDistribution.CustomErrorResponseProperty(
                    error_code=404,
                    response_code=200,
                    response_page_path="/"
                )
            ],
            alias_configuration=cdn.AliasConfiguration(
                acm_cert_ref=acmcert.certificate_arn,
                names=['app.cloudevangelist.ca']
            )
            
        )

        ssm.StringParameter(self,'cdn-dist-id',
            parameter_name='/'+env_name+'/app-distribution-id',
            string_value=self.cdn_id.distribution_id
        )

        ssm.StringParameter(self,'cdn-url',
            parameter_name='/'+env_name+'/app-cdn-url',
            string_value='https://'+self.cdn_id.domain_name
        )
    def __init__(self, scope: core.Construct, id: str, domain: DomainInfo,
                 **kwargs) -> None:
        super().__init__(scope, id, **kwargs)
        if domain.stage == 'prod':
            self.final_domain = domain.domain_name
        else:
            self.final_domain = f'{domain.stage}.{domain.domain_name}'
        self.domain = domain

        # Create the static site website bucket
        bucket = s3.Bucket(self,
                           "sitebucket",
                           bucket_name=self.final_domain,
                           public_read_access=True,
                           website_index_document="index.html")
        core.CfnOutput(self, 'site_bucket_name', value=bucket.bucket_name)
        core.CfnOutput(self,
                       'site_bucket_website',
                       value=bucket.bucket_website_url)

        #create Cloudfront distribution return dist ID
        alias_configuration = cf.AliasConfiguration(
            acm_cert_ref=self.domain.cert_arn,
            names=[self.final_domain],
        )
        source_configuration = cf.SourceConfiguration(
            s3_origin_source=cf.S3OriginConfig(s3_bucket_source=bucket, ),
            behaviors=[cf.Behavior(is_default_behavior=True)])
        dist = cf.CloudFrontWebDistribution(
            self,
            'staticsitecf',
            alias_configuration=alias_configuration,
            origin_configs=[source_configuration],
        )
        core.CfnOutput(self,
                       'static_site_cf_dist_id',
                       value=dist.distribution_id)
        core.CfnOutput(self, 'static_site_cf_domain', value=dist.domain_name)

        #route53 logic
        if self.domain.stage == 'prod':
            zone = route53.HostedZone.from_hosted_zone_attributes(
                self,
                id="HostedZoneID",
                hosted_zone_id=self.domain.hosted_zone_id,
                zone_name=self.domain.domain_name)
            route53.ARecord(self,
                            'SiteAliasRecord',
                            record_name=self.final_domain,
                            target=route53.AddressRecordTarget.from_alias(
                                targets.CloudFrontTarget(dist)),
                            zone=zone)
Example #6
0
    def __init__(self, parent: core.Construct, name: str,
                 props: StaticSiteProps) -> None:
        super().__init__(parent, name)

        site_domain = props.site_sub_domain + '.' + props.domain_name

        # Content bucket
        site_bucket = s3.Bucket(self,
                                "SiteBucket",
                                bucket_name=site_domain,
                                website_index_document="index.html",
                                website_error_document="error.html",
                                public_read_access=True,
                                removal_policy=core.RemovalPolicy.DESTROY)

        core.CfnOutput(self, 'Bucket', value=site_bucket.bucket_name)

        #cloudfront distribution that provies HTTPS
        distribution = cfront.CloudFrontWebDistribution(
            self,
            'SiteDistribution',
            origin_configs=[
                cfront.SourceConfiguration(
                    behaviors=[cfront.Behavior(is_default_behavior=True)],
                    s3_origin_source=cfront.S3OriginConfig(
                        s3_bucket_source=site_bucket))
            ],
            alias_configuration=cfront.AliasConfiguration(
                acm_cert_ref=props.certificate_arn,
                names=[site_domain],
                ssl_method=cfront.SSLMethod.SNI,
                security_policy=cfront.SecurityPolicyProtocol.TLS_V1_1_2016))

        core.CfnOutput(self,
                       'DistributionID',
                       value=distribution.distribution_id)

        # Route 53 alias record for the CloudFront distribution
        zone = route53.HostedZone.from_lookup(self,
                                              'MyHostedZone',
                                              domain_name=props.domain_name)

        # Add a A record to the hosted zone
        route53.ARecord(
            self,
            'SiteAliasRecord',
            zone=zone,
            record_name=site_domain,
            target=route53.AddressRecordTarget.from_alias(
                aws_route53_targets.CloudFrontTarget(distribution)))
    def create_cloudfront_distribution(self,
                                       cloudfront_alias=typing.Optional[dict]):
        r"""Creates the Cloudfront distribution required to access the SPA website

    The Cloudfront distribution will automatically forward requests to the s3 bucket /index.html
    file and serve that as the default for all HTTP URIs that don't exist so that the index file
    can be served for any dynamic path

    NOTE: If cloudfront_alias is defined, the default `security_policy` is
      aws_cloudfront.SecurityPolicyProtocol.TLS_V1_2_2018 which can be by defining `security_policy`
      in the dictionary if required

    Args:
      cloudfront_alias: Aliases your Cloudfront distribution should use and should
        include a dictionary containing array(`names`) and str(`acm_cert_ref`)
    """
        cloudfront_originaccesspolicy = cloudfront.OriginAccessIdentity(
            self,
            f"{self.__website_identifier}-originpolicy",
        )
        alias_configuration = None
        if cloudfront_alias is not None:
            if 'security_policy' not in cloudfront_alias:
                cloudfront_alias[
                    'security_policy'] = cloudfront.SecurityPolicyProtocol.TLS_V1_2_2018
            cloudfront_alias = cloudfront.AliasConfiguration(
                **cloudfront_alias)
        self.cloudfront_distro = cloudfront.CloudFrontWebDistribution(
            self,
            id=f"{self.__website_identifier}-cloudfront",
            price_class=cloudfront.PriceClass.PRICE_CLASS_ALL,
            alias_configuration=alias_configuration,
            origin_configs=[
                cloudfront.SourceConfiguration(
                    behaviors=[cloudfront.Behavior(is_default_behavior=True)],
                    s3_origin_source=cloudfront.S3OriginConfig(
                        s3_bucket_source=self.website_assets_bucket,
                        origin_access_identity=cloudfront_originaccesspolicy))
            ],
            error_configurations=[
                cloudfront.CfnDistribution.CustomErrorResponseProperty(
                    error_code=404,
                    error_caching_min_ttl=0,
                    response_code=200,
                    response_page_path="/index.html")
            ])
Example #8
0
    def __init__(self, scope: core.Construct, id: str, aliases: List[str],
                 certificate_arn: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        bucket = s3.Bucket(self, 'Storage')

        origin_identity = cloudfront.OriginAccessIdentity(self, 'Identity')

        bucket.grant_read(origin_identity.grant_principal)

        certificate = acm.Certificate.from_certificate_arn(
            self, 'Certificate', certificate_arn=certificate_arn)

        distribution = cloudfront.CloudFrontWebDistribution(
            self,
            'CDN',
            price_class=cloudfront.PriceClass.PRICE_CLASS_ALL,
            alias_configuration=cloudfront.AliasConfiguration(
                names=aliases,
                acm_cert_ref=certificate.certificate_arn,
                security_policy=cloudfront.SecurityPolicyProtocol.
                TLS_V1_2_2019,
            ),
            origin_configs=[
                cloudfront.SourceConfiguration(
                    s3_origin_source=cloudfront.S3OriginConfig(
                        s3_bucket_source=bucket,
                        origin_access_identity=origin_identity,
                    ),
                    behaviors=[
                        cloudfront.Behavior(
                            default_ttl=core.Duration.days(1),
                            min_ttl=core.Duration.days(1),
                            max_ttl=core.Duration.days(365),
                            is_default_behavior=True,
                        )
                    ])
            ])

        self.bucket = bucket
        self.distribution = distribution
Example #9
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # Message timeout; used by SQS and Lambda
        message_timeout = core.Duration.seconds(15)

        # SQS queue that the Raspberry Pi will write to
        queue = sqs.Queue(
            self,
            'Queue',
            visibility_timeout=message_timeout,
            receive_message_wait_time=core.Duration.seconds(20),
            retention_period=core.Duration.hours(1),
        )

        # DynamoDB table that the web app will read from
        icao_address = dynamodb.Attribute(
            name='IcaoAddress',
            type=dynamodb.AttributeType.STRING,
        )
        table = dynamodb.Table(
            self,
            'Table',
            partition_key=icao_address,
            billing_mode=dynamodb.BillingMode.PAY_PER_REQUEST,
            removal_policy=core.RemovalPolicy.DESTROY,
        )

        database = timestream.CfnDatabase(
            self,
            'Database',
            database_name='aircraft-database',
        )
        table2 = timestream.CfnTable(self,
                                     'Table2',
                                     database_name=database.ref,
                                     table_name='aircraft-table',
                                     retention_properties={
                                         'MemoryStoreRetentionPeriodInHours':
                                         1,
                                         'MagneticStoreRetentionPeriodInDays':
                                         1,
                                     })

        # IAM user for the Raspberry Pi
        user = iam.User(self, 'RaspberryPi')
        queue.grant_send_messages(user)
        access_key = iam.CfnAccessKey(
            self,
            'AccessKey',
            user_name=user.user_name,
        )

        # IAM role for Lambda function, so it can write to DynamoDB
        lambda_role = iam.Role(
            self,
            'LambdaRole',
            assumed_by=iam.ServicePrincipal('lambda.amazonaws.com'),
            managed_policies=[
                iam.ManagedPolicy.from_aws_managed_policy_name(
                    'service-role/AWSLambdaBasicExecutionRole'),
            ],
        )
        lambda_role.add_to_policy(
            iam.PolicyStatement(
                actions=[
                    'timestream:CancelQuery', 'timestream:DescribeEndpoints',
                    'timestream:DescribeTable', 'timestream:ListMeasures',
                    'timestream:Select', 'timestream:WriteRecords'
                ],
                resources=['*'],  # TODO: narrow down permissions
            ))
        table.grant_read_write_data(lambda_role)

        # Integration between SQS and Lambda
        event = lambda_event_sources.SqsEventSource(
            queue=queue,
            batch_size=10,
        )

        # Lambda function that processes messages from SQS queue and updates DynamoDB table
        import_function = lambda_.Function(
            self,
            'ImportFunction',
            description='Reads SQS messages and writes to DynamoDB',
            runtime=lambda_.Runtime.PYTHON_3_8,
            code=lambda_.Code.from_asset('lambda_import/'),
            timeout=message_timeout,
            handler='index.handler',
            role=lambda_role,
            events=[event],
            environment={
                'TABLE_NAME': table2.ref,
            },
        )

        # TODO: add custom log group
        # TODO: add metric filters for number of succesfull updates and failed updates

        # Lambda function that reads from DynamoDB and returns data to API Gateway
        api_function = lambda_.Function(
            self,
            'ApiFunction',
            description='Reads from DynamoDB and returns to API GW',
            runtime=lambda_.Runtime.PYTHON_3_8,
            code=lambda_.Code.from_asset('lambda_api/'),
            timeout=message_timeout,
            handler='index.handler',
            role=lambda_role,
            environment={
                'TABLE_NAME': table.table_name,
            },
        )

        # API Gateway for requesting aircraft data
        api = apigateway.RestApi(
            self,
            'Api',
            endpoint_types=[apigateway.EndpointType.REGIONAL],
            cloud_watch_role=False,
        )

        aircraft_resource = api.root.add_resource('aircraft')

        aircraft_resource.add_method(
            http_method='GET',
            integration=apigateway.LambdaIntegration(
                api_function,
                proxy=True,
            ),
        )

        # Static website
        bucket = s3.Bucket(self, 'StaticWebsite')

        s3_deployment.BucketDeployment(
            self,
            'Deployment',
            sources=[
                s3_deployment.Source.asset('html/'),
            ],
            destination_bucket=bucket,
        )

        # Permissions between CloudFront and S3
        origin_identity = cloudfront.OriginAccessIdentity(self, 'Identity')
        bucket.grant_read(origin_identity.grant_principal)

        # CloudFront distribution pointing to both S3 and API Gateway
        s3_origin = cloudfront.SourceConfiguration(
            s3_origin_source=cloudfront.S3OriginConfig(
                s3_bucket_source=bucket,
                origin_access_identity=origin_identity,
            ),
            behaviors=[
                cloudfront.Behavior(
                    default_ttl=core.Duration.days(0),
                    min_ttl=core.Duration.days(0),
                    max_ttl=core.Duration.days(31),
                    is_default_behavior=True,
                )
            ])

        api_origin = cloudfront.SourceConfiguration(
            origin_path='/{}'.format(api.deployment_stage.stage_name),
            custom_origin_source=cloudfront.CustomOriginConfig(
                domain_name='{}.execute-api.{}.{}'.format(
                    api.rest_api_id, self.region, self.url_suffix), ),
            behaviors=[
                cloudfront.Behavior(
                    default_ttl=core.Duration.seconds(0),
                    min_ttl=core.Duration.seconds(0),
                    max_ttl=core.Duration.seconds(0),
                    path_pattern='/aircraft/*',
                )
            ])

        domain_name = self.node.try_get_context('domain_name')

        # If domain name is specified, create a certificate and alias configuration for CloudFront
        if domain_name is None:
            alias_configuration = None
        else:
            subdomain = 'aircraft.{}'.format(domain_name)

            zone = route53.HostedZone.from_lookup(
                self,
                'Zone',
                domain_name=domain_name,
            )

            certificate = acm.DnsValidatedCertificate(
                self,
                'Certificate',
                domain_name=subdomain,
                hosted_zone=zone,
                region='us-east-1',
            )

            alias_configuration = cloudfront.AliasConfiguration(
                acm_cert_ref=certificate.certificate_arn,
                names=[subdomain],
            )

        distribution = cloudfront.CloudFrontWebDistribution(
            self,
            'CDN',
            price_class=cloudfront.PriceClass.PRICE_CLASS_ALL,
            alias_configuration=alias_configuration,
            origin_configs=[
                s3_origin,
                api_origin,
            ],
        )

        # If domain name is specified, create a DNS record for CloudFront
        if domain_name is not None:
            route53.ARecord(
                self,
                'DnsRecord',
                record_name=subdomain,
                target=route53.AddressRecordTarget.from_alias(
                    alias_target=route53_targets.CloudFrontTarget(
                        distribution)),
                zone=zone,
            )

        # Outputs that are needed on the Raspberry Pi
        core.CfnOutput(
            self,
            'QueueUrl',
            value=queue.queue_url,
        )
        core.CfnOutput(
            self,
            'AccessKeyId',
            value=access_key.ref,
        )
        core.CfnOutput(
            self,
            'SecretAccessKey',
            value=access_key.attr_secret_access_key,
        )
        core.CfnOutput(
            self,
            'Region',
            value=self.region,
        )
    def __init__(
        self,
        scope: core.Construct,
        id: str,
        **kwargs,
    ) -> None:
        super().__init__(scope, id, **kwargs)

        s3_domain_prefix = scope.static_site_bucket.bucket_name
        s3_domain_suffix = ".s3-website-us-east-1.amazonaws.com"
        s3_website_domain_name = s3_domain_prefix + s3_domain_suffix

        path_patterns = ["/api/*", "/admin/*", "/flower*"]

        self.distribution = cloudfront.CloudFrontWebDistribution(
            self,
            "CloudFrontDistribution",
            origin_configs=[
                cloudfront.SourceConfiguration(
                    custom_origin_source=cloudfront.CustomOriginConfig(
                        domain_name=scope.alb.load_balancer_dns_name,
                        origin_protocol_policy=MATCH_VIEWER,
                    ),
                    behaviors=[
                        cloudfront.Behavior(
                            allowed_methods=ALL_METHODS,
                            path_pattern=path_pattern,
                            forwarded_values={
                                "headers": ["*"],
                                "cookies": {
                                    "forward": "all"
                                },
                                "query_string": True,
                            },
                        ) for path_pattern in path_patterns
                    ],
                ),
                cloudfront.SourceConfiguration(
                    custom_origin_source=cloudfront.CustomOriginConfig(
                        domain_name=s3_website_domain_name,
                        origin_protocol_policy=HTTP_ONLY,
                    ),
                    behaviors=[
                        cloudfront.Behavior(
                            is_default_behavior=True,
                            cached_methods=GET_HEAD,
                        )
                    ],
                ),
                cloudfront.SourceConfiguration(
                    s3_origin_source=cloudfront.S3OriginConfig(
                        s3_bucket_source=scope.backend_assets_bucket),
                    behaviors=[
                        cloudfront.Behavior(
                            allowed_methods=ALL_METHODS,
                            forwarded_values={"query_string": True},
                            path_pattern=path_pattern,
                            min_ttl=core.Duration.seconds(0),
                            default_ttl=core.Duration.seconds(0),
                            max_ttl=core.Duration.seconds(0),
                        ) for path_pattern in ["/static/*", "/media/*"]
                    ],
                ),
            ],
            alias_configuration=cloudfront.AliasConfiguration(
                acm_cert_ref=scope.certificate.certificate_arn,
                names=[scope.full_domain_name],
            ),
        )

        route53.ARecord(
            self,
            "AliasRecord",
            target=route53.AddressRecordTarget.from_alias(
                targets.CloudFrontTarget(self.distribution)),
            zone=scope.hosted_zone,
            record_name=f"{scope.full_domain_name}.",
        )
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)
        # super().__init__(scope, id, context, outdir)

        print()
        # Common Stack Tags
        for k, v in constants.COMMON_TAGS.items():
            core.Tag.add(self, key=k, value=v)

        # Hosted Zone
        if constants.HOSTED_ZONE["id"]:
            hosted_zone = aws_route53.HostedZone.from_hosted_zone_attributes(
                self,
                "ImportedHostedZone",
                hosted_zone_id=constants.HOSTED_ZONE["id"],
                zone_name=constants.HOSTED_ZONE["name"])
        else:
            hosted_zone = aws_route53.HostedZone(
                self,
                "MainHostedZone",
                zone_name=constants.HOSTED_ZONE["name"],
                comment="Hosted Zone for {}".format(
                    constants.HOSTED_ZONE["name"]),
            )

        # ACM Certificate
        if constants.CERTIFICATE["arn"]:
            acm_certificate = aws_certificatemanager.Certificate.from_certificate_arn(
                self,
                "ImportedCertificate",
                certificate_arn=constants.CERTIFICATE["arn"])
        else:
            acm_certificate = aws_certificatemanager.DnsValidatedCertificate(
                self,
                "CloudFrontCertificate",
                hosted_zone=hosted_zone,
                region=constants.CERTIFICATE["region"],
                domain_name=constants.HOSTED_ZONE["domain"],
                subject_alternative_names=constants.CERTIFICATE["alt_domains"],
                validation_method=aws_certificatemanager.ValidationMethod.DNS)
            acm_certificate.node.add_dependency(hosted_zone)

        # Website Bucket
        website_bucket = aws_s3.Bucket(
            self,
            "WebsiteBucket",
            encryption=aws_s3.BucketEncryption.S3_MANAGED,
            removal_policy=core.RemovalPolicy.DESTROY)

        # Cloudfront Origin Access Identity (OAI)
        website_bucket_oai = aws_cloudfront.CfnCloudFrontOriginAccessIdentity(
            self,
            "CloudfrontOAI",
            cloud_front_origin_access_identity_config=aws_cloudfront.
            CfnCloudFrontOriginAccessIdentity.
            CloudFrontOriginAccessIdentityConfigProperty(
                comment="CloudFrontOAIFor{}".format(
                    constants.PROJECT_CODE.capitalize())))

        # Canonical User Principal of OAI
        oai_canonical_user_principal = aws_iam.CanonicalUserPrincipal(
            website_bucket_oai.attr_s3_canonical_user_id)

        # Website Bucket Policy
        website_bucket.add_to_resource_policy(
            aws_iam.PolicyStatement(
                actions=["s3:GetObject"],
                resources=[website_bucket.arn_for_objects("*")],
                principals=[oai_canonical_user_principal],
                effect=aws_iam.Effect.ALLOW))

        # Adopt Lambda Function
        lambda_function = aws_lambda.Function.from_function_arn(
            self,
            "UrlRewriteFunction",
            function_arn=constants.URL_REWRITE_FUNCTION_ARN)

        lambda_function_version_arn = aws_lambda.Version.from_version_arn(
            self,
            "LambdaFunctionArn",
            version_arn=constants.URL_REWRITE_FUNCTION_VERSION_ARN)

        # CloudFront Web Distribution
        cloudfront_distribution = aws_cloudfront.CloudFrontWebDistribution(
            self,
            "CloudFrontDistribution",
            comment="waqqas.tech",
            default_root_object="index.html",
            viewer_protocol_policy=aws_cloudfront.ViewerProtocolPolicy.
            REDIRECT_TO_HTTPS,
            alias_configuration=aws_cloudfront.AliasConfiguration(
                acm_cert_ref=acm_certificate.certificate_arn,
                security_policy=aws_cloudfront.SecurityPolicyProtocol.
                TLS_V1_2_2018,
                names=constants.CLOUDFRONT["alt_domains"]),
            origin_configs=[
                aws_cloudfront.SourceConfiguration(
                    s3_origin_source=aws_cloudfront.S3OriginConfig(
                        s3_bucket_source=website_bucket,
                        origin_access_identity_id=website_bucket_oai.ref),
                    behaviors=[
                        aws_cloudfront.Behavior(
                            allowed_methods=aws_cloudfront.
                            CloudFrontAllowedMethods.GET_HEAD_OPTIONS,
                            cached_methods=aws_cloudfront.
                            CloudFrontAllowedCachedMethods.GET_HEAD,
                            compress=True,
                            is_default_behavior=True,
                            path_pattern="*",
                            default_ttl=core.Duration.seconds(
                                amount=constants.CLOUDFRONT['default_ttl']),
                            lambda_function_associations=[
                                aws_cloudfront.LambdaFunctionAssociation(
                                    event_type=aws_cloudfront.
                                    LambdaEdgeEventType.ORIGIN_REQUEST,
                                    lambda_function=lambda_function_version_arn
                                )
                            ])
                    ])
            ])

        # CloudFront Route53 Record
        primary_dns_record = aws_route53.ARecord(
            self,
            "PrimaryDNSRecord",
            zone=hosted_zone,
            comment="{} CloudFront Dist Alias Record".format(
                constants.PROJECT_CODE),
            record_name="{}.".format(constants.HOSTED_ZONE["domain"]),
            target=aws_route53.RecordTarget.from_alias(
                aws_route53_targets.CloudFrontTarget(cloudfront_distribution)),
            ttl=core.Duration.seconds(
                amount=constants.CLOUDFRONT["default_ttl"]),
        )

        # Artifact Bucket
        artifact_bucket = aws_s3.Bucket(
            self,
            "ArtifactBucket",
            encryption=aws_s3.BucketEncryption.S3_MANAGED,
            removal_policy=core.RemovalPolicy.DESTROY)

        # CodeBuild
        codebuild_environment_variables = aws_codebuild.BuildEnvironmentVariable(
            value=website_bucket.bucket_name)
        codebuild_environment = aws_codebuild.BuildEnvironment(
            build_image=aws_codebuild.LinuxBuildImage.
            UBUNTU_14_04_PYTHON_3_7_1,
            compute_type=aws_codebuild.ComputeType.SMALL)
        codebuild_buildspec = aws_codebuild.BuildSpec.from_object(
            value=buildspec.BUILDSPEC)
        codebuild_project = aws_codebuild.PipelineProject(
            self,
            "CodeBuildProject",
            environment_variables={
                "BUCKET_NAME": codebuild_environment_variables
            },
            environment=codebuild_environment,
            build_spec=codebuild_buildspec,
            description="CodeBuild Project for {} Content".format(
                constants.PROJECT_CODE),
            timeout=core.Duration.seconds(amount=300))
        # TODO: Lock down permissions for buckets
        codebuild_project.add_to_role_policy(
            aws_iam.PolicyStatement(actions=["s3:*"],
                                    effect=aws_iam.Effect.ALLOW,
                                    resources=[
                                        website_bucket.arn_for_objects("*"),
                                        artifact_bucket.arn_for_objects("*"),
                                        website_bucket.bucket_arn,
                                        artifact_bucket.bucket_arn,
                                    ]))
        # Codepipeline
        codepipeline = aws_codepipeline.Pipeline(
            self,
            "CodePipelineWebsiteContent",
            artifact_bucket=artifact_bucket,
            stages=[
                aws_codepipeline.StageProps(
                    stage_name="Source",
                    actions=[
                        aws_codepipeline_actions.GitHubSourceAction(
                            oauth_token=core.SecretValue(
                                value=constants.GITHUB_OAUTH_TOKEN),
                            output=aws_codepipeline.Artifact(
                                artifact_name="source"),
                            owner=constants.GITHUB_USER_NAME,
                            repo=constants.GITHUB_REPO_NAME,
                            branch=constants.BRANCH_NAME,
                            action_name="GithubSource",
                            trigger=aws_codepipeline_actions.GitHubTrigger.
                            WEBHOOK)
                    ]),
                aws_codepipeline.StageProps(
                    stage_name="Build",
                    actions=[
                        aws_codepipeline_actions.CodeBuildAction(
                            input=aws_codepipeline.Artifact(
                                artifact_name="source"),
                            project=codebuild_project,
                            type=aws_codepipeline_actions.CodeBuildActionType.
                            BUILD,
                            action_name="HugoBuild")
                    ])
            ])
        # TODO: Lock down permissions for buckets
        codepipeline.add_to_role_policy(
            aws_iam.PolicyStatement(actions=["s3:*"],
                                    effect=aws_iam.Effect.ALLOW,
                                    resources=[
                                        website_bucket.arn_for_objects("*"),
                                        artifact_bucket.arn_for_objects("*"),
                                        website_bucket.bucket_arn,
                                        artifact_bucket.bucket_arn,
                                    ]))
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        website_bucket = s3.Bucket(
            self,
            'FrontendBucket',
            versioned=True,
            website_index_document='index.html',
            website_error_document='index.html',
            public_read_access=True,
        )

        distribution = cloudfront.CloudFrontWebDistribution(
            self,
            'Distribution',
            alias_configuration=cloudfront.AliasConfiguration(
                acm_cert_ref=self.CERTIFICATE_ARN,
                names=[self.DOMAIN_NAME],
            ),
            origin_configs=[
                cloudfront.SourceConfiguration(
                    s3_origin_source=cloudfront.S3OriginConfig(
                        s3_bucket_source=website_bucket),
                    behaviors=[
                        cloudfront.Behavior(is_default_behavior=True,
                                            compress=True)
                    ],
                )
            ],
            error_configurations=[
                cloudfront.CfnDistribution.CustomErrorResponseProperty(
                    error_code=403,
                    error_caching_min_ttl=300,
                    response_code=200,
                    response_page_path='/index.html',
                ),
                cloudfront.CfnDistribution.CustomErrorResponseProperty(
                    error_code=404,
                    error_caching_min_ttl=300,
                    response_code=200,
                    response_page_path='/index.html',
                ),
            ],
        )

        s3deploy.BucketDeployment(
            self,
            'DeployWithInvalidation',
            sources=[s3deploy.Source.asset('../frontend/dist/')],
            destination_bucket=website_bucket,
            distribution=distribution,
            distribution_paths=['/*'],
        )

        # Django staticfiles
        s3.Bucket(
            self,
            'StaticAssetsBucket',
            public_read_access=True,
        )

        # non-www to www redirection
        redirect_bucket = s3.Bucket(
            self,
            'RedirectedBucket',
            bucket_name=self.ROOT_DOMAIN_NAME,
            website_redirect={
                'host_name': 'https://www.{{cookiecutter.domain_name}}'
            },
            public_read_access=True,
        )
        cloudfront.CloudFrontWebDistribution(
            self,
            'RedirectDistribution',
            alias_configuration=cloudfront.AliasConfiguration(
                acm_cert_ref=self.CERTIFICATE_ARN,
                names=[self.ROOT_DOMAIN_NAME],
            ),
            origin_configs=[
                cloudfront.SourceConfiguration(
                    s3_origin_source=cloudfront.S3OriginConfig(
                        s3_bucket_source=redirect_bucket),
                    behaviors=[cloudfront.Behavior(is_default_behavior=True)],
                )
            ],
        )
Example #13
0
    def __init__(self, scope: core.Construct, id: str, **kwargs):
        super().__init__(scope, id, **kwargs)

        # note assumption zone is named after domain
        hosted_zone = route53.HostedZone.from_hosted_zone_attributes(
            self,
            "HostedZone",
            hosted_zone_id=startuptoolbag_config.hosted_zone_id,
            zone_name=startuptoolbag_config.website_domain_name)

        # SSL/TLS Certificate
        # https://github.com/aws/aws-cdk/pull/8552
        # Experimental vs 'Certificate' (which requires validation in the console)
        tls_cert = certificatemanager.DnsValidatedCertificate(
            self,
            "SiteCertificate",
            hosted_zone=hosted_zone,
            domain_name=f'*.{startuptoolbag_config.website_domain_name}',
            subject_alternative_names=[
                startuptoolbag_config.website_domain_name
            ],
            region='us-east-1',
        )

        # Import the bucket that was created outside the stack
        self.www_site_bucket = s3.Bucket.from_bucket_name(
            self, 'SiteBucket', core.Fn.import_value("WWWSITEBUCKETNAME"))

        # CloudFront distribution that provides HTTPS - for www
        www_alias_configuration = cloudfront.AliasConfiguration(
            acm_cert_ref=tls_cert.certificate_arn,
            names=[f'www.{startuptoolbag_config.website_domain_name}'],
            ssl_method=cloudfront.SSLMethod.SNI,
            security_policy=cloudfront.SecurityPolicyProtocol.TLS_V1_1_2016)

        www_source_configuration = cloudfront.SourceConfiguration(
            s3_origin_source=cloudfront.S3OriginConfig(
                s3_bucket_source=self.www_site_bucket),
            behaviors=[cloudfront.Behavior(is_default_behavior=True)])

        www_distribution = cloudfront.CloudFrontWebDistribution(
            self,
            'SiteDistribution',
            alias_configuration=www_alias_configuration,
            origin_configs=[www_source_configuration])

        route53.ARecord(
            self,
            'CloudFrontARecord',
            zone=hosted_zone,
            record_name=
            f'www.{startuptoolbag_config.website_domain_name}',  #site domain
            target=aws_route53.RecordTarget.from_alias(
                aws_route53_targets.CloudFrontTarget(www_distribution)))

        # NAKED site bucket which redirects to naked to www
        redirect = aws_route53_patterns.HttpsRedirect(
            self,
            'NakedRedirect',
            record_names=[startuptoolbag_config.website_domain_name],
            target_domain=f'www.{startuptoolbag_config.website_domain_name}',
            zone=hosted_zone,
            certificate=tls_cert)

        # Create the API Gateway
        self.rest_api = aws_apigateway.RestApi(self,
                                               'RestApiGateway',
                                               deploy=False)
        api_domain_name = f'api.{startuptoolbag_config.website_domain_name}'
        domain = self.rest_api.add_domain_name('APIDomain',
                                               certificate=tls_cert,
                                               domain_name=api_domain_name)

        route53.ARecord(
            self,
            'APIGWAliasRecord',
            zone=hosted_zone,
            record_name=api_domain_name,  #site domain
            target=aws_route53.RecordTarget.from_alias(
                aws_route53_targets.ApiGatewayDomain(domain)))
    def __init__(self, scope: core.Construct, id: str,
                 props: StaticSiteProps) -> None:
        super().__init__(scope, id)

        fqdn = props.fqdn
        certificate_arn = props.certificate_arn
        error_configuration = props.error_configuration

        if len(error_configuration) == 0:
            error_codes = None
        else:
            error_codes = []
            for error_config in error_configuration:
                error_codes.append(
                    cloudfront.CfnDistribution.CustomErrorResponseProperty(
                        error_code=error_config["error_code"],
                        error_caching_min_ttl=error_config[
                            "error_caching_min_ttl"],
                        response_code=error_config["response_code"],
                        response_page_path=error_config["response_page_path"],
                    ))

        # Content Bucket
        site_bucket = s3.Bucket(
            self,
            "SiteBucket",
            bucket_name=fqdn + "-static-site",
            website_index_document="index.html",
            website_error_document="index.html",
            block_public_access=s3.BlockPublicAccess(block_public_policy=True),
            removal_policy=core.RemovalPolicy.DESTROY,
        )
        self.bucket_name = fqdn + "-static-site"
        self.bucket_resource = site_bucket
        origin_access_identity = cloudfront.CfnCloudFrontOriginAccessIdentity(
            self,
            "OriginIdentity",
            cloud_front_origin_access_identity_config={
                "comment": "Allow CloudFront to access web site"
            },
        )
        # Create IAM policy for S3 Canonical User
        policy_statement = iam.PolicyStatement()
        policy_statement.add_actions("s3:GetBucket*")
        policy_statement.add_actions("s3:GetObject*")
        policy_statement.add_actions("s3:List**")
        policy_statement.add_resources(site_bucket.bucket_arn)
        policy_statement.add_resources(f"{site_bucket.bucket_arn}/*")
        policy_statement.add_canonical_user_principal(
            origin_access_identity.attr_s3_canonical_user_id)
        site_bucket.add_to_resource_policy(policy_statement)
        core.CfnOutput(self, "Bucket", value=site_bucket.bucket_name)

        # CloudFront distribution with or without certificate
        source_configuration = cloudfront.SourceConfiguration(
            s3_origin_source=cloudfront.S3OriginConfig(
                s3_bucket_source=site_bucket,
                origin_access_identity_id=origin_access_identity.ref,
            ),
            behaviors=[cloudfront.Behavior(is_default_behavior=True)],
        )
        # Use ACM Certificate if provided, otherwise no-SSL
        if certificate_arn:
            # CloudFront distribution that provides HTTPS
            alias_configuration = cloudfront.AliasConfiguration(
                acm_cert_ref=certificate_arn,
                names=[fqdn],
                ssl_method=cloudfront.SSLMethod.SNI,
                security_policy=cloudfront.SecurityPolicyProtocol.
                TLS_V1_1_2016,
            )
            distribution = cloudfront.CloudFrontWebDistribution(
                self,
                "SiteDistribution",
                alias_configuration=alias_configuration,
                error_configurations=error_codes,
                origin_configs=[source_configuration],
                viewer_protocol_policy=cloudfront.ViewerProtocolPolicy.
                REDIRECT_TO_HTTPS,
            )
        else:
            distribution = cloudfront.CloudFrontWebDistribution(
                self,
                "SiteDistribution",
                origin_configs=[source_configuration],
                error_configurations=error_codes,
            )
        core.CfnOutput(
            self,
            "DistributionId",
            value=distribution.distribution_id,
            export_name=props.output_name,
        )

        # Route53 alias record for the CloudFront Distribution
        zone = route53.HostedZone.from_hosted_zone_attributes(
            self,
            id="HostedZoneID",
            hosted_zone_id=props.hosted_zone_id,
            zone_name=props.fqdn,
        )

        route53.ARecord(
            self,
            "SiteAliasRecord",
            record_name=fqdn,
            target=route53.AddressRecordTarget.from_alias(
                targets.CloudFrontTarget(distribution)),
            zone=zone,
        )
Example #15
0
    def web(self):
        zone = route53.HostedZone.from_hosted_zone_attributes(
            self,
            'hosted_zone',
            hosted_zone_id=HOSTED_ZONE_ID,
            zone_name=self.zone)
        cert = cert_manager.DnsValidatedCertificate(
            self,
            'domain_cert',
            domain_name=self.zone,
            subject_alternative_names=[
                self.web_domain
            ],
            hosted_zone=zone,
            validation_method=cert_manager.ValidationMethod.DNS)
        # cert = cert_manager.Certificate.from_certificate_arn(self, 'certificateDomainForAll',
        #                                                      "arn:aws:acm:us-east-1:134764946504:certificate/f74613d7-8cc5-4de1-a2ed-467d5321839d")
        site_bucket = s3.Bucket(self, 'site_bucket',
                                bucket_name=self.web_domain,
                                website_index_document='index.html',
                                website_error_document='404.html',
                                public_read_access=True)
        core.CfnOutput(self, 'bucket_name', value=site_bucket.bucket_name)
        source_behavior = cloudfront.Behavior(
            is_default_behavior=True,
            cached_methods=cloudfront.CloudFrontAllowedCachedMethods.GET_HEAD_OPTIONS,
            allowed_methods=cloudfront.CloudFrontAllowedMethods.GET_HEAD_OPTIONS,
            compress=True)
        s3_origin_source = cloudfront.S3OriginConfig(s3_bucket_source=site_bucket)
        origin_source_config = cloudfront.SourceConfiguration(
            s3_origin_source=s3_origin_source,
            behaviors=[source_behavior])
        alias_configuration = cloudfront.AliasConfiguration(
            acm_cert_ref=cert.certificate_arn,
            names=[self.zone],
            ssl_method=cloudfront.SSLMethod.SNI,
            security_policy=cloudfront.SecurityPolicyProtocol.TLS_V1_2_2019)

        distribution = cloudfront.CloudFrontWebDistribution(
            self, 'cf-web-distro',
            alias_configuration=alias_configuration,
            origin_configs=[origin_source_config],
            error_configurations=[
                cloudfront.CfnDistribution.CustomErrorResponseProperty(
                    error_code=404,
                    response_code=404,
                    response_page_path='/404.html'
                ),
                cloudfront.CfnDistribution.CustomErrorResponseProperty(
                    error_code=403,
                    response_code=404,
                    response_page_path='/404.html',
                )
            ],
            http_version=cloudfront.HttpVersion.HTTP2,
            viewer_protocol_policy=cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS
        )

        core.CfnOutput(self, 'Distribution ID', value=distribution.distribution_id)
        core.CfnOutput(self, 'Distribution domain name', value=distribution.domain_name)
        core.CfnOutput(self, 'SiteBucketWebsiteDomain', value=site_bucket.bucket_website_domain_name)
        # noinspection PyTypeChecker
        target_alias = route53.RecordTarget.from_alias(targets.CloudFrontTarget(distribution))
        route53.ARecord(self, 'arecord-web',
                        record_name=self.zone,
                        target=target_alias,
                        zone=zone,
                        ttl=core.Duration.minutes(60))
        s3_deployment.BucketDeployment(self, "deploy-with-invalidation",
                                       sources=[
                                           s3_deployment.Source.asset('./../website')
                                       ],
                                       destination_bucket=site_bucket,
                                       distribution=distribution,
                                       content_language='en-US',
                                       distribution_paths=['/*'])
Example #16
0
    def __init__(self, scope: core.Construct, id: str, sub_domain: str, domain: str, **kwargs) -> None:
        """
        StaticSiteStack creates the CloudFormation Stack that creates the resources necessary to host a static web site from an S3 Bucket with a CloudFormation CDN and a custom domain name.  

        arguments:
        sub_domain -- sub domain name used for the dashboard url, acg-covid-challenge
        domain -- custom domain name owned by user, e.g. my-domain.com
        """

        super().__init__(scope, id, **kwargs)

        # In the GitHub Actions Workflow, the Certificate is created using the CertificateStack and its arn is set as an environment variable
        self.certificate_arn = self.node.try_get_context("certificate_arn")

        bucket = s3.Bucket(self,
                           f"{sub_domain}-bucket",
                           website_index_document="index.html",
                           removal_policy=core.RemovalPolicy.DESTROY,
                           block_public_access=s3.BlockPublicAccess.BLOCK_ALL
                           )

        core.CfnOutput(self, "sitebucketname",
                       value=bucket.bucket_name)

        oai = cf.OriginAccessIdentity(
            self,
            f"OriginIdentity-{sub_domain}",
        )

        alias_configuration = cf.AliasConfiguration(
            acm_cert_ref=self.certificate_arn,
            names=[f"{sub_domain}.{domain}"],
            ssl_method=cf.SSLMethod.SNI,
            security_policy=cf.SecurityPolicyProtocol.TLS_V1_1_2016
        )

        source_config = cf.SourceConfiguration(
            s3_origin_source=cf.S3OriginConfig(
                s3_bucket_source=bucket,
                origin_access_identity=oai
            ),
            behaviors=[cf.Behavior(is_default_behavior=True)]
        )

        cf_dist = cf.CloudFrontWebDistribution(
            self,
            f"{sub_domain}-static-site-distribution",
            alias_configuration=alias_configuration,
            origin_configs=[source_config],
            viewer_protocol_policy=cf.ViewerProtocolPolicy.REDIRECT_TO_HTTPS
        )

        core.CfnOutput(self, "distid", value=cf_dist.distribution_id)

        # Route53 alias record for the CloudFront Distribution
        hosted_zone = route53.HostedZone.from_lookup(
            self, f"{sub_domain}-hosted-zone-id", domain_name=domain)

        route53.ARecord(
            self,
            f'{sub_domain}-alias-record',
            record_name=f"{sub_domain}.{domain}",
            target=route53.AddressRecordTarget.from_alias(
                targets.CloudFrontTarget(cf_dist)),
            zone=hosted_zone
        )
Example #17
0
    def __init__(self, scope: core.Construct, id: str,
                 props: StaticSiteProps) -> None:
        super().__init__(scope, id)

        site_domain: str = "{sub_domain}.{domain_name}".format(
            sub_domain=props.site_sub_domain, domain_name=props.domain_name)

        # Content Bucket
        site_bucket = s3.Bucket(
            self,
            "SiteBucket",
            bucket_name=site_domain,
            website_index_document="index.html",
            website_error_document="error.html",
            public_read_access=True,
        )
        core.CfnOutput(self, "Bucket", value=site_bucket.bucket_name)

        # Pre-existing ACM Certificate, with ARN stored in an SSM Parameter
        certificate_arn: str = ssm.StringParameter.from_string_parameter_attributes(
            self,
            "MYCertArnString",
            parameter_name="CertificateArn-{}".format(props.domain_name),
        ).string_value

        # CloudFront distribution that provides HTTPS
        alias_configuration = cloudfront.AliasConfiguration(
            acm_cert_ref=certificate_arn,
            names=[site_domain],
            ssl_method=cloudfront.SSLMethod.SNI,
            security_policy=cloudfront.SecurityPolicyProtocol.TLS_V1_1_2016,
        )

        source_configuration = cloudfront.SourceConfiguration(
            s3_origin_source=cloudfront.S3OriginConfig(
                s3_bucket_source=site_bucket),
            behaviors=[cloudfront.Behavior(is_default_behavior=True)],
        )

        distribution = cloudfront.CloudFrontWebDistribution(
            self,
            "SiteDistribution",
            alias_configuration=alias_configuration,
            origin_configs=[source_configuration],
        )
        core.CfnOutput(self,
                       "DistributionId",
                       value=distribution.distribution_id)

        # Route53 alias record for the CloudFront Distribution
        zone = route53.HostedZone.from_hosted_zone_attributes(
            self,
            id="HostedZoneID",
            hosted_zone_id=props.hosted_zone_id,
            zone_name=props.domain_name,
        )

        route53.ARecord(
            self,
            "SiteAliasRecord",
            record_name=site_domain,
            target=route53.AddressRecordTarget.from_alias(
                targets.CloudFrontTarget(distribution)),
            zone=zone,
        )
Example #18
0
    def __init__(self, scope: core.Construct, id: str, api: apigateway.RestApi,
                 **kwargs) -> None:
        super().__init__(scope, id, **kwargs)
        stack = core.Stack.of(self)

        bucket = s3.Bucket(self, 'Storage')

        s3_deployment.BucketDeployment(
            self,
            'Deployment',
            sources=[
                s3_deployment.Source.asset('./src/html'),
            ],
            destination_bucket=bucket,
        )

        origin_identity = cloudfront.OriginAccessIdentity(self, 'Identity')

        bucket.grant_read(origin_identity.grant_principal)

        s3_origin = cloudfront.SourceConfiguration(
            s3_origin_source=cloudfront.S3OriginConfig(
                s3_bucket_source=bucket,
                origin_access_identity=origin_identity,
            ),
            behaviors=[
                cloudfront.Behavior(
                    default_ttl=core.Duration.days(1),
                    min_ttl=core.Duration.days(1),
                    max_ttl=core.Duration.days(31),
                    is_default_behavior=True,
                )
            ])

        api_origin = cloudfront.SourceConfiguration(
            origin_path='/{}'.format(api.deployment_stage.stage_name),
            custom_origin_source=cloudfront.CustomOriginConfig(
                domain_name='{}.execute-api.{}.{}'.format(
                    api.rest_api_id, stack.region, stack.url_suffix), ),
            behaviors=[
                cloudfront.Behavior(default_ttl=core.Duration.seconds(0),
                                    min_ttl=core.Duration.seconds(0),
                                    max_ttl=core.Duration.seconds(0),
                                    path_pattern='/stock/*',
                                    forwarded_values={
                                        'query_string': True,
                                        'query_string_cache_keys':
                                        ['start', 'end']
                                    })
            ])

        domain_name = 'demo.training'
        subdomain = 'finance.{}'.format(domain_name)

        zone = route53.HostedZone.from_lookup(
            self,
            'Zone',
            domain_name=domain_name,
        )

        certificate = acm.DnsValidatedCertificate(
            self,
            'Certificate',
            domain_name=subdomain,
            hosted_zone=zone,
            region='us-east-1',
        )

        distribution = cloudfront.CloudFrontWebDistribution(
            self,
            'CDN',
            price_class=cloudfront.PriceClass.PRICE_CLASS_ALL,
            origin_configs=[
                s3_origin,
                api_origin,
            ],
            alias_configuration=cloudfront.AliasConfiguration(
                acm_cert_ref=certificate.certificate_arn,
                names=[subdomain],
            ))

        route53.ARecord(
            self,
            'DnsRecord',
            record_name=subdomain,
            target=route53.AddressRecordTarget.from_alias(
                alias_target=route53_targets.CloudFrontTarget(distribution)),
            zone=zone,
        )
Example #19
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # store
        dynamodb_table = dynamodb.Table(
            self,
            'dynamodb_table',
            table_name=f'{PROJECT}_{STAGE}',
            partition_key=dynamodb.Attribute(
                name='date', type=dynamodb.AttributeType.STRING),
            billing_mode=dynamodb.BillingMode.PAY_PER_REQUEST,
            point_in_time_recovery=False,
            removal_policy=core.RemovalPolicy.DESTROY,
            server_side_encryption=True,
        )

        # public api
        public_api = appsync.CfnGraphQLApi(
            self,
            'public_api',
            name=f'{PROJECT}_{STAGE}',
            authentication_type='API_KEY',
        )

        now = time.localtime()
        epoch = time.mktime(now)
        public_api_key = appsync.CfnApiKey(
            self,
            'public_api_key',
            api_id=public_api.attr_api_id,
            expires=epoch + core.Duration.days(90).to_seconds(),
        )

        with open('schema.gql', mode='r') as f:
            graphql_schema = f.read()

            appsync.CfnGraphQLSchema(self,
                                     'public_api_schema',
                                     api_id=public_api.attr_api_id,
                                     definition=graphql_schema)

        public_api_role = iam.Role(
            self,
            'public_api_role',
            assumed_by=iam.ServicePrincipal('appsync.amazonaws.com'),
            managed_policies=[
                iam.ManagedPolicy.from_aws_managed_policy_name(
                    'AmazonDynamoDBFullAccess')
            ],
        )

        public_api_datasource = appsync.CfnDataSource(
            self,
            'public_api_datasource',
            api_id=public_api.attr_api_id,
            name=f'{PROJECT}_{STAGE}_dynamodb',
            type='AMAZON_DYNAMODB',
            dynamo_db_config={
                'awsRegion': 'us-east-1',
                'tableName': dynamodb_table.table_name,
            },
            service_role_arn=public_api_role.role_arn,
        )

        with open('mapping_templates/get_holiday.json', mode='r') as f:
            get_holiday_json = f.read()

            appsync.CfnResolver(
                self,
                'public_api_resolver_get_holiday',
                api_id=public_api.attr_api_id,
                type_name='Query',
                field_name='getHoliday',
                data_source_name=public_api_datasource.attr_name,
                kind='UNIT',
                request_mapping_template=get_holiday_json,
                response_mapping_template='$util.toJson($context.result)',
            )

        with open('mapping_templates/list_holidays.json', mode='r') as f:
            list_holidays_json = f.read()

            appsync.CfnResolver(
                self,
                'public_api_resolver_list_holidays',
                api_id=public_api.attr_api_id,
                type_name='Query',
                field_name='listHolidays',
                data_source_name=public_api_datasource.attr_name,
                kind='UNIT',
                request_mapping_template=list_holidays_json,
                response_mapping_template='$util.toJson($context.result)',
            )

        # lambda source code upload to s3
        lambda_assets = s3_assets.Asset(self,
                                        'lambda_assets',
                                        path='./function/.artifact/')

        # update function
        func_api = lambda_.Function(
            self,
            f'{PROJECT}-{STAGE}-func',
            function_name=f'{PROJECT}-{STAGE}-func',
            code=lambda_.Code.from_bucket(bucket=lambda_assets.bucket,
                                          key=lambda_assets.s3_object_key),
            handler='app.handler',
            runtime=lambda_.Runtime.PYTHON_3_7,
            timeout=core.Duration.seconds(120),
            log_retention=logs.RetentionDays.SIX_MONTHS,
            memory_size=128,
            tracing=lambda_.Tracing.ACTIVE,
        )
        func_api.add_environment('TABLE_NAME', dynamodb_table.table_name)
        func_api.add_environment('CSV_URL', CSV_URL)
        func_api.add_to_role_policy(
            iam.PolicyStatement(
                actions=[
                    'dynamodb:Get*',
                    'dynamodb:Put*',
                    'dynamodb:Batch*',
                ],
                resources=[dynamodb_table.table_arn],
            ))

        # schedule execute
        events.Rule(
            self,
            f'{PROJECT}-{STAGE}-schedule',
            enabled=True,
            schedule=events.Schedule.rate(core.Duration.days(10)),
            targets=[events_targets.LambdaFunction(func_api)],
        )

        # lambda@edge
        func_lambdaedge = lambda_.Function(
            self,
            f'{PROJECT}-{STAGE}-func-lambdaedge',
            function_name=f'{PROJECT}-{STAGE}-func-lambdaedge',
            code=lambda_.Code.from_inline(
                open('./function/src/lambdaedge.py').read().replace(
                    '__X_API_KEY__', public_api_key.attr_api_key)),
            handler='index.handler',
            runtime=lambda_.Runtime.PYTHON_3_7,
            timeout=core.Duration.seconds(30),
            memory_size=128,
            role=iam.Role(
                self,
                f'{PROJECT}-{STAGE}-func-lambdaedge-role',
                assumed_by=iam.CompositePrincipal(
                    iam.ServicePrincipal('edgelambda.amazonaws.com'),
                    iam.ServicePrincipal('lambda.amazonaws.com'),
                ),
                managed_policies=[
                    iam.ManagedPolicy.from_aws_managed_policy_name(
                        'service-role/AWSLambdaBasicExecutionRole'),
                ],
            ),
        )
        lambdaedge_version = func_lambdaedge.add_version(
            hashlib.sha256(
                open('./function/src/lambdaedge.py').read().replace(
                    '__X_API_KEY__',
                    public_api_key.attr_api_key).encode()).hexdigest())

        # ACM
        certificates = acm.Certificate(
            self,
            'certificates',
            domain_name=DOMAIN,
            validation_method=acm.ValidationMethod.DNS,
        )

        # CDN
        cdn = cloudfront.CloudFrontWebDistribution(
            self,
            f'{PROJECT}-{STAGE}-cloudfront',
            origin_configs=[
                cloudfront.SourceConfiguration(
                    behaviors=[
                        # default behavior
                        cloudfront.Behavior(
                            allowed_methods=cloudfront.
                            CloudFrontAllowedMethods.ALL,
                            default_ttl=core.Duration.seconds(0),
                            max_ttl=core.Duration.seconds(0),
                            min_ttl=core.Duration.seconds(0),
                            is_default_behavior=True,
                            lambda_function_associations=[
                                cloudfront.LambdaFunctionAssociation(
                                    event_type=cloudfront.LambdaEdgeEventType.
                                    ORIGIN_REQUEST,
                                    lambda_function=lambdaedge_version,
                                ),
                            ])
                    ],
                    custom_origin_source=cloudfront.CustomOriginConfig(
                        domain_name=core.Fn.select(
                            2, core.Fn.split('/',
                                             public_api.attr_graph_ql_url)), ),
                )
            ],
            alias_configuration=cloudfront.AliasConfiguration(
                acm_cert_ref=certificates.certificate_arn,
                names=[DOMAIN],
                security_policy=cloudfront.SecurityPolicyProtocol.
                TLS_V1_2_2018,
            ),
            price_class=cloudfront.PriceClass.PRICE_CLASS_ALL,
        )
        core.CfnOutput(
            self,
            'cloudfront-domain',
            value=cdn.domain_name,
        )
Example #20
0
    def __init__(self, scope: core.Construct, id: str,
                 props: StaticSiteProps) -> None:
        super().__init__(scope, id)

        fqdn = props.fqdn
        certificate_arn = props.certificate_arn
        error_configuration = props.error_configuration

        if len(error_configuration) == 0:
            error_codes = None
        else:
            error_codes = []
            for error_config in error_configuration:
                error_codes.append(
                    cloudfront.CfnDistribution.CustomErrorResponseProperty(
                        error_code=error_config["error_code"],
                        error_caching_min_ttl=error_config[
                            "error_caching_min_ttl"],
                        response_code=error_config["response_code"],
                        response_page_path=error_config["response_page_path"],
                    ))

        # Content Bucket
        site_bucket = s3.Bucket(
            self,
            "SiteBucket",
            bucket_name=fqdn + "-static-site",
            website_index_document="index.html",
            website_error_document="index.html",
            block_public_access=s3.BlockPublicAccess(block_public_policy=True),
            removal_policy=core.RemovalPolicy.DESTROY,
        )
        self.bucket_name = fqdn + "-static-site"
        self.bucket_resource = site_bucket

        # Uses new method for OAI (still breaking changes) - https://github.com/aws/aws-cdk/pull/4491
        origin_access_identity = cloudfront.OriginAccessIdentity(
            self, "OriginIdentity")
        # Add CloudFront Origin Access Identity to the bucket
        site_bucket.grant_read(origin_access_identity)

        core.CfnOutput(self, "Bucket", value=site_bucket.bucket_name)

        # CloudFront distribution with or without certificate
        source_configuration = cloudfront.SourceConfiguration(
            s3_origin_source=cloudfront.S3OriginConfig(
                s3_bucket_source=site_bucket,
                origin_access_identity=origin_access_identity,
            ),
            behaviors=[cloudfront.Behavior(is_default_behavior=True)],
        )
        # Use ACM Certificate if provided, otherwise no-SSL
        if certificate_arn:
            # CloudFront distribution that provides HTTPS
            alias_configuration = cloudfront.AliasConfiguration(
                acm_cert_ref=certificate_arn,
                names=[fqdn],
                ssl_method=cloudfront.SSLMethod.SNI,
                security_policy=cloudfront.SecurityPolicyProtocol.
                TLS_V1_1_2016,
            )
            distribution = cloudfront.CloudFrontWebDistribution(
                self,
                "SiteDistribution",
                alias_configuration=alias_configuration,
                error_configurations=error_codes,
                origin_configs=[source_configuration],
                viewer_protocol_policy=cloudfront.ViewerProtocolPolicy.
                REDIRECT_TO_HTTPS,
            )
        else:
            distribution = cloudfront.CloudFrontWebDistribution(
                self,
                "SiteDistribution",
                origin_configs=[source_configuration],
                error_configurations=error_codes,
            )
        core.CfnOutput(
            self,
            "DistributionId",
            value=distribution.distribution_id,
            export_name=props.output_name,
        )

        # Route53 alias record for the CloudFront Distribution
        zone = route53.HostedZone.from_hosted_zone_attributes(
            self,
            id="HostedZoneID",
            hosted_zone_id=props.hosted_zone_id,
            zone_name=props.fqdn,
        )

        route53.ARecord(
            self,
            "SiteAliasRecord",
            record_name=fqdn,
            target=route53.RecordTarget.from_alias(
                alias_target=targets.CloudFrontTarget(distribution)),
            zone=zone,
        )
Example #21
0
    def __init__(
        self,
        scope: core.Construct,
        id: str,
        certificate_arn: str,
        hosted_zone_id,
        domain_name,
        **kwargs
    ) -> None:
        super().__init__(scope, id, **kwargs)

        hosted_zone = route53.HostedZone.from_hosted_zone_attributes(
            self, "HostedZone", hosted_zone_id=hosted_zone_id, zone_name=domain_name
        )

        # since the bucket has already been created from previous deployments
        # we build the bucket object from attributes here rather than creating a
        # new bucket.
        # This change is required since we had to re-create this entire stack 
        # after the bucket had been originally created.
        site_bucket = s3.Bucket.from_bucket_attributes(
            self,
            "SiteBucket",
            bucket_name=domain_name
        )

        oai = cloudfront.OriginAccessIdentity(self, "OriginAccessIdentity")

        distribution = cloudfront.CloudFrontWebDistribution(
            self,
            "SiteDistribution",
            alias_configuration=cloudfront.AliasConfiguration(
                acm_cert_ref=certificate_arn, names=[domain_name],
            ),
            origin_configs=[
                cloudfront.SourceConfiguration(
                    s3_origin_source=cloudfront.S3OriginConfig(
                        s3_bucket_source=site_bucket, origin_access_identity=oai
                    ),
                    behaviors=[cloudfront.Behavior(is_default_behavior=True)],
                ),
            ],
        )

        # noinspection PyTypeChecker
        route53.ARecord(
            self,
            "SiteAliasRecord",
            record_name=domain_name,
            target=route53.AddressRecordTarget.from_alias(
                route53_targets.CloudFrontTarget(distribution)
            ),
            zone=hosted_zone,
        )

        s3_deployment.BucketDeployment(
            self,
            "DeployWithInvalidation",
            sources=[s3_deployment.Source.asset("assets/elm/dst")],
            destination_bucket=site_bucket,
            distribution=distribution,
            distribution_paths=["/*"],
        )
Example #22
0
    def __init__(self, scope: core.Construct, id: str, props, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # Validated require props.
        required_props_keys = ['CfOriginDomainName', 'Asg', 'HostedZoneName', 'WebsiteDns']
        for k in required_props_keys:
            if k not in props or not props[k]:
                raise ValueError("Required prop %s is not present" % k)

        # Create a custom resource that returns the IP of the host behind the autoscaling group
        asg = props['Asg']
        asg_ip_handler = lambda_.Function(
            self, 'GhostIpHandler',
            runtime=lambda_.Runtime.PYTHON_3_6,
            code=lambda_.Code.asset('lambda'),
            handler='ghost_ip.handler',
        )

        asg_ip_handler.add_to_role_policy(
            statement=iam.PolicyStatement(
                actions=['autoscaling:DescribeAutoScalingGroups', 'ec2:DescribeInstances'],
                resources=['*', '*'],
            )
        )

        asg_ip_provider = cr.Provider(
            self, 'GhostIpProvider',
            on_event_handler=asg_ip_handler,
        )

        asg_ip_resource = cfn.CustomResource(
            self, 'GhostIpResource',
            provider=asg_ip_provider,
            properties={
                'AsgName': asg.auto_scaling_group_name,
                'ts': time.time(), # this makes sure the function is invoked for every CFN update
            }
        )

        # Create R53 HZ and cf origin domain
        if 'ExistingHostedZoneId' in props and props['ExistingHostedZoneId']:
            hz = route53.HostedZone.from_hosted_zone_attributes(
                self, 'HostedZone', 
                zone_name=props['HostedZoneName'],
                hosted_zone_id=props['ExistingHostedZoneId'],
            )
        else:
            hz = route53.HostedZone(
                self, 'HostedZone',
                zone_name=props['HostedZoneName']
            )

        origin_rrset = route53.ARecord(
            self, 'OriginRecord',
            target=route53.RecordTarget.from_ip_addresses(asg_ip_resource.get_att_string('GhostIp')),
            record_name=props['CfOriginDomainName'],
            zone=hz,
        )

        # Create a CF distro
        acm_cert = acm.DnsValidatedCertificate(
            self, 'GhostAcmCert',
            hosted_zone=hz,
            domain_name=props['WebsiteDns'],
            region='us-east-1',
        )

        cf_distro = cf.CloudFrontWebDistribution(
            self, 'CfDistro',
            origin_configs=[cf.SourceConfiguration(
                custom_origin_source=cf.CustomOriginConfig(
                    domain_name=props['CfOriginDomainName'],
                    origin_protocol_policy=cf.OriginProtocolPolicy.HTTP_ONLY,
                ),
                behaviors=[cf.Behavior(is_default_behavior=True)],
            )],
            alias_configuration=cf.AliasConfiguration(
                names=[props['WebsiteDns']],
                acm_cert_ref=acm_cert.certificate_arn,
            ),
            default_root_object='',
        )

        # Create the top level website DNS pointing to the CF distro
        ghost_rrset = route53.CnameRecord(
            self, 'GhostDns',
            domain_name=cf_distro.domain_name,
            zone=hz,
            record_name=props['WebsiteDns'],
        )
Example #23
0
class TsWwwStack(core.Stack):

    def __init__(self, scope: core.Construct, id: str,domain_name:str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # Materialize existing AWS Hosted DNS Zone
        dns_zone = r53_.HostedZone.from_lookup(self,"dns_zone",domain_name = domain_name)
        
        # Compose site name for AWS Certificate
        site_fqdn = "www." + dns_zone.zone_name

        # Create a DNS Certificate
        certificate = cm_.DnsValidatedCertificate (self,"certificate",
                                                         domain_name=site_fqdn,
                                                         hosted_zone=dns_zone,
                                                         region="us-east-1")

        # Define Bucket to store Site Contents
        ts_www_bucket = s3_.Bucket(self,"truesys-static-website",
                                        bucket_name = site_fqdn,
                                        website_index_document = "index.html",
                                        website_error_document = "404/index.html",
                                        public_read_access = True
                                        )

        #Cria lambda function para fazr URL Rewriting de default document
        url_rewrite_lambda = _lambda.Function(self,'URLRewriteLambdaEdge',
                                                   handler='url_rewrite_handler.handler',
                                                   runtime=_lambda.Runtime.PYTHON_3_7,
                                                   code=_lambda.Code.asset('lambda_edge'),
        )
        
        
        // A numbered version to give to cloudfront
       const myOriginRequestHandlerVersion = new lambda.Version(this, "OriginRequestHandlerVersion", {
               lambda: myOriginRequestHandler,
});
        
        
        lea = clf_.AlambdaFunctionAssociation(event_type = cfl_AlambdaEdgeEventType.ORIGIN_REQUEST, myOriginRequestHandlerVersion)
        
        #Define Cloud Front distribution
        s3_origin_config = clf_.S3OriginConfig(s3_bucket_source = ts_www_bucket)
        behaviour = clf_.Behavior(is_default_behavior=True, 
                                  lambda_function_associations = [lea])
        source_config = clf_.SourceConfiguration(s3_origin_source=s3_origin_config,
                                                 behaviors = [behaviour])
        clf_alias_config = clf_.AliasConfiguration(acm_cert_ref = certificate.certificate_arn,
                                                  names=[site_fqdn], 
                                                  ssl_method = clf_.SSLMethod.SNI,
                                                  security_policy = clf_.SecurityPolicyProtocol.TLS_V1_1_2016)
        cf_distribution = clf_.CloudFrontWebDistribution(self,"TsDistribution",
                                                           origin_configs=[source_config],
                                                           alias_configuration=clf_alias_config,
                                                           price_class = clf_.PriceClass.PRICE_CLASS_ALL
                                                     )
                                                     
        #Define Route 53 Alias aka endereco do site
        cloud_front_target = r53tgs_.CloudFrontTarget(distribution = cf_distribution) 
        r53_target = r53_.RecordTarget.from_alias(alias_target = cloud_front_target)
        r53_.ARecord(self,"EnderecoDosite",record_name = site_fqdn,
                                           target = r53_target,
                                           zone = dns_zone)
        
        
        #Faz deploy do conteudo do site para o S3 e invalida distribution
        site_assets = s3deploy_.Source.asset("./true-systems-static-site/public")
        s3deploy_.BucketDeployment(self,"truesys-website-content-deployment",
                                        sources = [site_assets],
                                        destination_bucket=ts_www_bucket,
                                        distribution=cf_distribution,
                                        distribution_paths = [ "/*"])

        core.CfnOutput(self,"Site",value = site_fqdn)                                
    def __init__(self, scope: core.Construct, id: str, environment: str,
                 domain: str, **kwargs) -> None:
        """
        StaticSiteStack creates the CloudFormation Stack that creates the resources necessary to host a static web site from an S3 Bucket with a CloudFormation CDN and a custom domain name.  Three separate stacks are created based on the environment variable ('dev', 'stg', 'prod')

        arguments:
        environment -- Deployment Environment, e.g. one of ('dev', 'stg', 'prod')
        domain -- custom domain name owned by user, e.g. my-domain.com
        """

        super().__init__(scope, id, **kwargs)

        # In the GitHub Actions Workflow, the Certificate is created using the CertificateStack and its arn is set as an environment variable
        self.certificate_arn = self.node.try_get_context("certificate_arn")

        bucket = s3.Bucket(self,
                           f"{environment}bucket",
                           website_index_document="index.html",
                           removal_policy=core.RemovalPolicy.DESTROY,
                           block_public_access=s3.BlockPublicAccess.BLOCK_ALL)

        core.CfnOutput(self, "sitebucketname", value=bucket.bucket_name)

        oai = cf.OriginAccessIdentity(
            self,
            f"OriginIdentity-{environment}-{domain}",
        )

        alias_configuration = cf.AliasConfiguration(
            acm_cert_ref=self.certificate_arn,
            names=[f"{environment}.{domain}"],
            ssl_method=cf.SSLMethod.SNI,
            security_policy=cf.SecurityPolicyProtocol.TLS_V1_1_2016)

        # Config dictionary for CloudFront distributions, no caching takes place in dev
        # The assumption is that it will be changed frequently and those changes will be tested
        # To use alternative sub-domains, change the keys of this dictionary to match the sub-domains used in certificate_stack.py
        cf_behavior_dict = {
            "dev":
            cf.Behavior(is_default_behavior=True,
                        min_ttl=core.Duration.seconds(0),
                        max_ttl=core.Duration.seconds(0),
                        default_ttl=core.Duration.seconds(0)),
            "stg":
            cf.Behavior(is_default_behavior=True),
            "prod":
            cf.Behavior(is_default_behavior=True)
        }

        source_config = cf.SourceConfiguration(
            s3_origin_source=cf.S3OriginConfig(s3_bucket_source=bucket,
                                               origin_access_identity=oai),
            behaviors=[cf_behavior_dict[environment]])

        cf_dist = cf.CloudFrontWebDistribution(
            self,
            f"{environment}-static-site-distribution",
            alias_configuration=alias_configuration,
            origin_configs=[source_config],
            viewer_protocol_policy=cf.ViewerProtocolPolicy.REDIRECT_TO_HTTPS)

        core.CfnOutput(self, "distid", value=cf_dist.distribution_id)

        # Route53 alias record for the CloudFront Distribution
        hosted_zone = route53.HostedZone.from_lookup(
            self, "static-site-hosted-zone-id", domain_name=domain)

        route53.ARecord(self,
                        'static-site-alias-record',
                        record_name=f"{environment}.{domain}",
                        target=route53.AddressRecordTarget.from_alias(
                            targets.CloudFrontTarget(cf_dist)),
                        zone=hosted_zone)
Example #25
0
def add_static_site(stack: CDKMasterStack, domain: str, bucket_name: str, prefix: str = ""):

    # Construct code goes here
    core.CfnOutput(stack, f"{prefix}Site", value=f"https://{domain}")

    # Content bucket
    kix.info("Bucket Name: " + bucket_name)
    site_bucket = aws_s3.Bucket(
        stack, f"{prefix}SiteBucket",
        bucket_name=bucket_name,
        website_index_document="index.html",
        website_error_document="index.html",
        public_read_access=True,
        removal_policy=core.RemovalPolicy.DESTROY)
    core.CfnOutput(stack, f"{prefix}BucketArn", value=site_bucket.bucket_arn)

    # Certificate
    kix.info("Creating Certificate")
    cert = aws_certificatemanager.DnsValidatedCertificate(
        stack, f"{prefix}ValidatedCert",
        domain_name=domain,
        hosted_zone=stack.zone)
    core.CfnOutput(stack, f"{prefix}CertificateArn", value=cert.certificate_arn)

    kix.info("Creating Distribution")
    distribution = aws_cloudfront.CloudFrontWebDistribution(
        stack, f"{prefix}SiteDistribution",
        alias_configuration=aws_cloudfront.AliasConfiguration(
            acm_cert_ref=cert.certificate_arn,
            names=[domain],
            ssl_method=aws_cloudfront.SSLMethod.SNI,
            security_policy=aws_cloudfront.SecurityPolicyProtocol.TLS_V1_1_2016,
        ),
        origin_configs=[
            aws_cloudfront.SourceConfiguration(
                s3_origin_source=aws_cloudfront.S3OriginConfig(s3_bucket_source=site_bucket),
                behaviors=[aws_cloudfront.Behavior(is_default_behavior=True)]
            )],
        error_configurations=[
            aws_cloudfront.CfnDistribution.CustomErrorResponseProperty(
                error_code=403,
                response_code=200,
                response_page_path="/index.html"
            ),
            aws_cloudfront.CfnDistribution.CustomErrorResponseProperty(
                error_code=404,
                response_code=200,
                response_page_path="/index.html"
            )
        ]
    )
    core.CfnOutput(stack, f"{prefix}DistributionId", value=distribution.distribution_id)
    a_record_target = aws_route53.AddressRecordTarget.from_alias(aws_route53_targets.CloudFrontTarget(distribution))

    # Route 53 alias record for the CloudFront distribution
    kix.info("Routing A-Record Alias")
    aws_route53.ARecord(
        stack, f"{prefix}SiteAliasRecord",
        zone=stack.zone,
        target=a_record_target,
        record_name=domain)
Example #26
0
    def __init__(self,
                 scope: core.Construct,
                 id: str,
                 s3bucket,
                 acmcert,
                 hostedzone,
                 alb=elbv2.ApplicationLoadBalancer,
                 **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        prj_name = self.node.try_get_context("project_name")
        env_name = self.node.try_get_context("env")
        domain_name = self.node.try_get_context("domain_name")

        bucketName = s3.Bucket.from_bucket_name(self, 's3bucket', s3bucket)

        path_patterns = ["/static/*", "/templates/*"]

        self.cdn_id = cdn.CloudFrontWebDistribution(
            self,
            'webhosting-cdn',
            origin_configs=[
                cdn.SourceConfiguration(
                    #   origin_path="/",
                    s3_origin_source=cdn.S3OriginConfig(
                        s3_bucket_source=bucketName,
                        origin_access_identity=cdn.OriginAccessIdentity(
                            self, 'webhosting-origin')),
                    behaviors=[
                        cdn.Behavior(
                            path_pattern=path_pattern,
                            allowed_methods=cdn.CloudFrontAllowedMethods.ALL,
                            cached_methods=cdn.CloudFrontAllowedCachedMethods.
                            GET_HEAD,
                        ) for path_pattern in path_patterns
                    ],
                ),
                cdn.SourceConfiguration(
                    custom_origin_source=cdn.CustomOriginConfig(
                        domain_name=alb.load_balancer_dns_name,
                        origin_protocol_policy=cdn.OriginProtocolPolicy.
                        MATCH_VIEWER),
                    behaviors=[
                        cdn.Behavior(
                            is_default_behavior=True,
                            allowed_methods=cdn.CloudFrontAllowedMethods.ALL,
                            forwarded_values={
                                "query_string": True,
                                "cookies": {
                                    "forward": "all"
                                },
                                "headers": ['*']
                            },
                        )
                    ])
            ],
            error_configurations=[
                cdn.CfnDistribution.CustomErrorResponseProperty(
                    error_code=400, response_code=200, response_page_path="/"),
                cdn.CfnDistribution.CustomErrorResponseProperty(
                    error_code=403, response_code=200, response_page_path="/"),
                cdn.CfnDistribution.CustomErrorResponseProperty(
                    error_code=404, response_code=200, response_page_path="/")
            ],
            alias_configuration=cdn.AliasConfiguration(
                acm_cert_ref=acmcert.certificate_arn,
                names=[env_name + '.' + domain_name]))

        r53.ARecord(
            self,
            'dev-record',
            zone=hostedzone,
            target=r53.RecordTarget.from_alias(
                alias_target=r53targets.CloudFrontTarget(self.cdn_id)),
            #target=r53.RecordTarget.from_alias(alias_target="d1w8o2vctuxdpo.cloudfront.net"),
            record_name='dev')

        ssm.StringParameter(self,
                            'cdn-dist-id',
                            parameter_name='/' + env_name +
                            '/app-distribution-id',
                            string_value=self.cdn_id.distribution_id)

        ssm.StringParameter(self,
                            'cdn-url',
                            parameter_name='/' + env_name + '/app-cdn-url',
                            string_value='https://' + self.cdn_id.domain_name)