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, )
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
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'))
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, ]))