Esempio n. 1
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        bucket = s3.Bucket(self, "Bucket", website_index_document="index.html")

        config = {"comment": "mythical-mysfits"}

        origin = cloudfront.CfnCloudFrontOriginAccessIdentity(
            self,
            "BucketOrigin",
            cloud_front_origin_access_identity_config=config)

        identity = iam.CanonicalUserPrincipal(
            canonical_user_id=origin.attr_s3_canonical_user_id)

        bucket.grant_read(identity)

        cloudfront_behaviour = cloudfront.Behavior(
            max_ttl=core.Duration.seconds(60),
            allowed_methods=cloudfront.CloudFrontAllowedMethods.
            GET_HEAD_OPTIONS,
            is_default_behavior=True)
        cloudfront_distribution = cloudfront.CloudFrontWebDistribution(
            self,
            "CloudFront",
            viewer_protocol_policy=cloudfront.ViewerProtocolPolicy.ALLOW_ALL,
            price_class=cloudfront.PriceClass.PRICE_CLASS_ALL,
            origin_configs=[
                cloudfront.SourceConfiguration(
                    behaviors=[cloudfront_behaviour],
                    origin_path="/web",
                    s3_origin_source=cloudfront.S3OriginConfig(
                        s3_bucket_source=bucket,
                        origin_access_identity_id=origin.ref),
                )
            ],
        )

        contentDir = os.path.realpath("../web/")
        source = deployment.Source.asset(contentDir)
        deployment.BucketDeployment(
            self,
            "DeployWebsite",
            sources=[source],
            destination_key_prefix="web/",
            destination_bucket=bucket,
            distribution=cloudfront_distribution,
            retain_on_delete=False,
        )

        core.CfnOutput(
            self,
            "CloudFrontURL",
            description="The CloudFront distribution URL",
            value="http://{}".format(cloudfront_distribution.domain_name),
        )
    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,
        )
Esempio n. 3
0
    def __init__(self, scope: core.Construct, construct_id: str,
                 ss_context: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # Access logging bucket for the S3 and Cloudfront

        ss = dict(self.node.try_get_context(ss_context))

        allowed_methods = AllowedMethods.ALLOW_GET_HEAD if ss[
            "cfront_allowed_methods"] == "ALLOW_GET_HEAD" else AllowedMethods.ALLOW_GET_HEAD_OPTIONS if ss[
                "cfront_allowed_methods"] == "ALLOW_GET_HEAD_OPTIONS" else AllowedMethods.ALLOW_ALL

        viewer_policy = ViewerProtocolPolicy.REDIRECT_TO_HTTPS if ss[
            "cfront_viewer_policy"] == "REDIRECT_TO_HTTPS" else ViewerProtocolPolicy.HTTPS_ONLY if ss[
                "cfront_viewer_policy"] == "HTTPS_ONLY" else ViewerProtocolPolicy.ALLOW_ALL

        price_class = PriceClass.PRICE_CLASS_ALL if ss[
            "cfront_price_class"] == "PRICE_CLASS_ALL" else PriceClass.PRICE_CLASS_200 if ss[
                "cfront_price_class"] == "PRICE_CLASS_200" else PriceClass.PRICE_CLASS_100

        # Creating the access logs bucket

        access_log_bucket = _s3.Bucket(
            self,
            ss["access_logs_bucket_name"],
            bucket_name=ss["access_logs_bucket_name"],
            encryption=_s3.BucketEncryption.KMS_MANAGED,
            removal_policy=core.RemovalPolicy.DESTROY,
            auto_delete_objects=True,
        )

        # S3 bucket for the static site

        source_bucket = _s3.Bucket(
            self,
            ss["static_site_bucket_name"],
            bucket_name=ss["static_site_bucket_name"],
            encryption=_s3.BucketEncryption.KMS_MANAGED,
            removal_policy=core.RemovalPolicy.DESTROY,
            auto_delete_objects=True,
            versioned=True,
            website_index_document=ss["website_index_document"],
            website_error_document=ss["website_index_document"])

        bucket_origins = _cfront_origins.S3Origin(source_bucket)

        # Cloudfront distribution with S3 as origin and logging enabled

        cfront_oai = _cfront.CfnCloudFrontOriginAccessIdentity(
            self,
            "accessOriginOAI",
            cloud_front_origin_access_identity_config={
                "comment": ss["cfront_origins_comment"]
            })

        cfront_dist = _cfront.Distribution(
            self,
            ss["cfront_distribution_name"],
            default_behavior={
                "origin": bucket_origins,
                "allowed_methods": allowed_methods,
                "viewer_protocol_policy": viewer_policy
            },
            enable_ipv6=True,
            minimum_protocol_version=SecurityPolicyProtocol.TLS_V1_2_2019,
            price_class=price_class,
            default_root_object=ss["cfront_root_object"],
            comment=ss["cfront_dist_comment"],
            log_bucket=access_log_bucket,
            log_includes_cookies=False,
            log_file_prefix=ss["cfront_log_file_prefix"],
            # web_acl_id=,
            # certificate=,
            geo_restriction=GeoRestriction.whitelist(ss["geo_whitelist"]),
        )

        # Bucket policy to restrict access to bucket - Use only cloudfront's Origin Access identity
        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(source_bucket.bucket_arn)
        policy_statement.add_resources(f"{source_bucket.bucket_arn}/*")
        policy_statement.add_canonical_user_principal(
            cfront_oai.attr_s3_canonical_user_id)
        source_bucket.add_to_resource_policy(policy_statement)

        # Outputs

        core.CfnOutput(self,
                       "CloudfrontDistribution",
                       value=(cfront_dist.distribution_domain_name))
        core.CfnOutput(self, "BucketArn", value=(source_bucket.bucket_arn))
        core.CfnOutput(self,
                       "LoggingBucketArn",
                       value=(access_log_bucket.bucket_arn))

        self.bucket = source_bucket
        self.access_logs_bucket = access_log_bucket
        self.cfront_dist = cfront_dist
Esempio n. 4
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # MyCfnId
        self.cfn_access_id = cdn.CfnCloudFrontOriginAccessIdentity(
            self,
            "cfn_access_id",
            cloud_front_origin_access_identity_config={
                'comment': 'access-id-s3-test'
            })
        # MyCfn
        self.cfn = cdn.CfnDistribution(
            self,
            "cfn",
            distribution_config={
                'aliases': ['mst-test.codefirefly.com'],
                'enabled':
                True,
                'defaultCacheBehavior': {
                    'forwardedValues': {
                        'queryString': False,
                        'cookies': {
                            'forward': 'none'
                        }
                    },
                    'allowed_methods': ['GET', 'HEAD'],
                    # 'lambdaFunctionAssociations': [{
                    #     'eventType': 'viewer-request',
                    #     'lambdaFunctionArn': checkConditionsFunctionVersion.function_arn
                    # }],
                    'targetOriginId': 'myS3Origin',
                    'viewerProtocolPolicy': 'allow-all',
                    'compress': True
                },
                'ipv6Enabled':
                False,
                # 'logging': {
                #     'bucket': self.node.try_get_context('distribution_log_bucket'),
                #     'prefix': "logs/"
                # },
                'origins': [{
                    'domainName': 'mst-test.s3.amazonaws.com',
                    'id': "myS3Origin",
                    's3OriginConfig': {
                        'originAccessIdentity':
                        'origin-access-identity/cloudfront/' +
                        self.cfn_access_id.ref
                    }
                }],
                'comment':
                'mst-test',
                # 'priceClass': 'PriceClass_All',
                'viewerCertificate': {
                    'acmCertificateArn':
                    'arn:aws:acm:us-east-1:456843195142:certificate/31c9c3b3-af3e-4155-9ad8-ebbf1186284e',
                    'sslSupportMethod': 'sni-only'
                }
            })
        # MyRoute53
        record = r53.CfnRecordSet(
            self,
            'route53',
            name='mst-test.codefirefly.com',
            hosted_zone_id='Z2787K6CO94PK7',
            # comment='public dns for myDistribution',
            type='A',
            alias_target=r53.CfnRecordSet.AliasTargetProperty(
                dns_name=self.cfn.attr_domain_name,
                hosted_zone_id='Z2FDTNDATAQYW2'))
Esempio n. 5
0
    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,
                                    ]))