def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) # The code that defines your stack goes here bucket = _s3.Bucket( self, '_s3-site-bucket', website_index_document='index.html', public_read_access=True, removal_policy=core.RemovalPolicy.DESTROY ) deployment = _deployment.BucketDeployment( self, '_s3-asset', destination_bucket=bucket, sources=[_deployment.Source.asset('./static/')] ) cloudfrontorigin = _cloudfront_origins.S3Origin( bucket, ) cloudfront = _cloudfront.Distribution( self, 'cloudfront_dist', default_behavior=cloudfrontorigin ) core.CfnOutput(self, 'Cloudfront-DomainName', value=cloudfront.distribution_domain_name)
def setup_cloudfront(self): """Setup CloudFront / is pointing to S3 /api is pointing to Load Balancer Returns ------- aws_cloudfront.Distribution that redirecting traffic to ALB """ return cf.Distribution( self, 'CloudFront', default_behavior=cf.BehaviorOptions( origin=origins.S3Origin(self.web_bucket)), additional_behaviors={ '/api/*': cf.BehaviorOptions( origin=origins.LoadBalancerV2Origin( self.service.load_balancer, protocol_policy=cf.OriginProtocolPolicy.HTTP_ONLY, ), cache_policy=cf.CachePolicy.CACHING_DISABLED, allowed_methods=cf.AllowedMethods.ALLOW_ALL, ) })
def S3_FRONTENDDEPLOY(self): bucket = s3.Bucket( self, "FrontendBucket", removal_policy=core.RemovalPolicy.DESTROY, versioned=True, ) distribution = cloudfront.Distribution( self, "FrontendDistribution", # TODO: The domain and cert info should be env vars domain_names=["www.seanfischer.io"], certificate=certificates.Certificate.from_certificate_arn( self, "DomainCertificateEast1", "arn:aws:acm:us-east-1:261392311630:certificate/859dc9d1-7a5f-4474-bcad-bcba1607a5ed", ), default_root_object="index.html", default_behavior=cloudfront.BehaviorOptions( origin=origins.S3Origin(bucket, ), viewer_protocol_policy=cloudfront.ViewerProtocolPolicy. REDIRECT_TO_HTTPS, ), ) s3deploy.BucketDeployment( self, "FrontendS3Deployment", sources=[s3deploy.Source.asset("./src")], destination_bucket=bucket, distribution=distribution, ) return bucket
def __init__(self, app: core.App, cfn_name: str, stack_env): super().__init__(scope=app, id=f"{cfn_name}-{stack_env}") s3_bucket = s3.Bucket(scope=self, id=f"{cfn_name}-{stack_env}-bucket", website_index_document="index.html") # upload files in `./html` to the bucket defined above _ = s3_deploy.BucketDeployment( scope=self, id=f"{cfn_name}-{stack_env}-deployments", sources=[s3_deploy.Source.asset("./html")], destination_bucket=s3_bucket, destination_key_prefix=self.ORIGIN_PATH) # set S3 as origin s3_origin = origin.S3Origin(bucket=s3_bucket, origin_path=self.ORIGIN_PATH) # create CloudFront Distribution _ = cloud_front.Distribution( scope=self, id=f"{cfn_name}-{stack_env}", default_behavior=cloud_front.BehaviorOptions( # may warning here, for type mismatched. origin=s3_origin))
def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) # The code that defines your stack goes here bucket = s3.Bucket( self, 'cloudfronttestbucket', bucket_name="testcloudfrontbuckettoday", public_read_access=False, removal_policy=core.RemovalPolicy.DESTROY, ) s3identity = cloudfront.OriginAccessIdentity( self, 'accessidentity', comment="access-identity-") s3Origin = origins.S3Origin(bucket=bucket, origin_access_identity=s3identity) current_behavior = cloudfront.BehaviorOptions( origin=s3Origin, viewer_protocol_policy=cloudfront.ViewerProtocolPolicy. REDIRECT_TO_HTTPS) skull_distribution = cloudfront.Distribution( self, 'skulldistibution', default_behavior=current_behavior) bucket.grant_read(identity=s3identity.grant_principal)
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) lambda_edge = _lambda.Function( self, 'LambdaEdge', runtime=_lambda.Runtime.PYTHON_3_7, handler='index.handler', code=_lambda.Code.from_asset('lambda'), ) #create an S3 bucket used as origin for Cloudfront, not used but origin is a required field hosting_bucket = s3.Bucket(self, "MyHostingBucket") my_distribution = cloudfront.Distribution( self, "MyDistribution", default_behavior=cloudfront.BehaviorOptions( origin=origins.S3Origin(hosting_bucket), edge_lambdas=[ cloudfront.EdgeLambda( function_version=lambda_edge.current_version, event_type=cloudfront.LambdaEdgeEventType. ORIGIN_REQUEST) ]), comment='Dynamic content generation using Lambda@Edge') CfnOutput(self, "DomainName", value=my_distribution.domain_name, export_name='DomainName', description='CloudFront Domain Name')
def _create_cloudfront_distribution(self): """Create a cloudfront distribution with a private bucket as the origin""" self.distribution = cloudfront.Distribution( self, "cloudfront_distribution", default_behavior=cloudfront.BehaviorOptions( origin=origins.S3Origin(self.bucket), viewer_protocol_policy=cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, ), domain_names=[self._site_domain_name], certificate=self.certificate, default_root_object="index.html", )
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) s3_bucket_name = cdk.CfnParameter(self, 'S3BucketForStaticContents', type='String', description='s3 bucket that the site contents are deployed to' ) site_bucket = s3.Bucket.from_bucket_name(self, 'S3BucketForStaticSite', s3_bucket_name.value_as_string) cloudfrontOAI = cloudfront.OriginAccessIdentity(self, 'CloudFrontOAI', comment="Allows CloudFront to reach the bucket: {name}".format(name=s3_bucket_name.value_as_string) ); cloudfrontOAI.apply_removal_policy(cdk.RemovalPolicy.DESTROY) #XXX: Add policy document the existing s3 bucket #XXX: https://stackoverflow.com/questions/60087302/how-to-add-resource-policy-to-existing-s3-bucket-with-cdk-in-javascript site_bucket_policy_statement = aws_iam.PolicyStatement(**{ 'actions': ['s3:GetObject'], 'resources': [site_bucket.arn_for_objects('*')], 'principals': [aws_iam.CanonicalUserPrincipal(cloudfrontOAI.cloud_front_origin_access_identity_s3_canonical_user_id)] }) s3.CfnBucketPolicy(self, 'SiteBucketPolicy', bucket=site_bucket.bucket_name, policy_document=aws_iam.PolicyDocument(statements=[site_bucket_policy_statement]) ) distribution = cloudfront.Distribution(self, "myDist", default_behavior=cloudfront.BehaviorOptions( origin=cf_origins.S3Origin(bucket=site_bucket, origin_access_identity=cloudfrontOAI) ), error_responses=[ #XXX: If you have accessed root page of cloudfront url (i.e. https://your-domain.cloudfront.net/), #XXX: 403:Forbidden error might occur. In order to prevent this error, #XXX: configure 403:Forbidden error response page to be 'index.html' cloudfront.ErrorResponse(http_status=403, response_http_status=200, response_page_path='/index.html', ttl=cdk.Duration.seconds(10)), #XXX: Configure 404:NotFound error response page to be 'error.html' cloudfront.ErrorResponse(http_status=404, response_http_status=404, response_page_path='/error.html', ttl=cdk.Duration.seconds(10)) ] ) cdk.CfnOutput(self, 'StackName', value=self.stack_name, export_name='StackName') cdk.CfnOutput(self, 'SiteBucket', value=site_bucket.bucket_name, export_name='SiteBucket') cdk.CfnOutput(self, 'DistributionId', value=distribution.distribution_id, export_name='DistributionId') cdk.CfnOutput(self, 'DistributionDomainName', value=distribution.distribution_domain_name, export_name='DistributionDomainName') cdk.CfnOutput(self, 'CloudFrontOriginAccessId', value=cloudfrontOAI.cloud_front_origin_access_identity_s3_canonical_user_id, export_name='CloudFrontOAI')
def __create_cloud_front_www( self, origin_bucket_name: str, domain_name: str, alternative_domain_names: Optional[List[str]], ssl_certificate: aws_certificatemanager.Certificate, cache_policy: aws_cloudfront.CachePolicy, origin_access_identity: aws_cloudfront.OriginAccessIdentity, edge_lambda_viewer_request: aws_lambda.Version ) -> aws_cloudfront.Distribution: domain_names = alternative_domain_names if alternative_domain_names else [] domain_names.append(domain_name) domain_names = set(domain_names) return aws_cloudfront.Distribution( self, 'CloudFrontWWW', enabled=True, certificate=ssl_certificate, comment='CloudFront Distribution for your WWW static website', domain_names=list(domain_names), http_version=HttpVersion.HTTP2, price_class=PriceClass.PRICE_CLASS_100, default_behavior=BehaviorOptions( allowed_methods=AllowedMethods.ALLOW_GET_HEAD, cached_methods=CachedMethods.CACHE_GET_HEAD, cache_policy=cache_policy, viewer_protocol_policy=ViewerProtocolPolicy.REDIRECT_TO_HTTPS, origin=aws_cloudfront_origins.S3Origin( bucket=Bucket.from_bucket_name( self, "OriginProd", bucket_name=origin_bucket_name), origin_access_identity=origin_access_identity, origin_path='/src/prod'), edge_lambdas=[ EdgeLambda(event_type=LambdaEdgeEventType.VIEWER_REQUEST, include_body=False, function_version=edge_lambda_viewer_request) ]), error_responses=[ ErrorResponse(ttl=Duration.seconds(300), response_page_path='/404.html', http_status=403, response_http_status=404) ])
def __init__(self, scope: core.Construct, construct_id: str, s3_construct: S3Construct, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) self.distribution = aws_cloudfront.Distribution( self, "release_artifacts_cloudfront", default_behavior=aws_cloudfront.BehaviorOptions( origin=aws_cloudfront_origins.S3Origin(s3_construct.bucket), viewer_protocol_policy=aws_cloudfront.ViewerProtocolPolicy. HTTPS_ONLY, ), ) # We do not want someone to accidentally delete the # CloudFront distribution, since that would break # publicly-available distribution mechanisms. Set # the removal policy to RETAIN so that deleting # the `cloudformation` stack does not remove the # CloudFront resource. self.distribution.apply_removal_policy(core.RemovalPolicy.RETAIN)
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) #create the Cloudfront Function used to change the uri cf_function = cloudfront.Function( self, "Function", code=cloudfront.FunctionCode.from_file( file_path="cff/ab_testing.js")) #the S3 bucket where the html files will be hosted hosting_bucket = s3.Bucket(self, "MyHostingBucket") #copy the html files at deployment to the hosting bucket s3_deployment.BucketDeployment( self, "myDeployment", sources=[s3_deployment.Source.asset("website")], destination_bucket=hosting_bucket, ) #create a cloudfront distribution and associate the cloudfront Function to the Distribution my_distribution = cloudfront.Distribution( self, "MyDistribution", default_behavior=cloudfront.BehaviorOptions( origin=origins.S3Origin(hosting_bucket), function_associations=[ cloudfront.FunctionAssociation( function=cf_function, event_type=cloudfront.FunctionEventType.VIEWER_REQUEST) ])) CfnOutput(self, "DomainName", value=my_distribution.domain_name, export_name='DomainName', description='CloudFront Domain Name')
def __init__(self, app: core.App, id: str) -> None: super().__init__(app, id) with open("config.json") as f: self.config = json.load(f) assert ( "SECRET_KEY" in self.config), "Need random SECRET_KEY specified in config.json" assert ( "CERTIFICATE_ARN" in self.config), "Need CERTIFICATE_ARN specified in config.json" self.lambda_dir = "assets/lambda" os.makedirs(os.path.join(self.lambda_dir, "templates", "generated"), exist_ok=True) r = requests.get( "https://api.github.com/repos/sumpfork/dominiontabs/releases") changelog = r.json() changelog = [{ "url": ch["html_url"], "date": dt.datetime.strptime(ch["published_at"][:10], "%Y-%m-%d").date(), "name": ch["name"], "tag": ch["tag_name"], "description": ch["body"], } for ch in changelog] env = Environment(loader=FileSystemLoader("templates"), autoescape=select_autoescape(["html"])) t = env.get_template("changelog.html.j2") generated_template_path = os.path.join(self.lambda_dir, "templates", "generated") shutil.rmtree(generated_template_path) os.mkdir(generated_template_path) with open( os.path.join(generated_template_path, "changelog.html"), "w", ) as f: f.write(t.render(changelog=changelog)) static_website_bucket = s3.Bucket( self, "Dominion Divider Generator Site", ) cf_static_dist = cloudfront.Distribution( self, "StaticCloudfrontDist", default_behavior=cloudfront.BehaviorOptions( origin=cloudfront_origins.S3Origin(static_website_bucket)), ) s3_deployment.BucketDeployment( self, "Static Files Deployment", sources=[s3_deployment.Source.asset("./static")], destination_bucket=static_website_bucket, destination_key_prefix="static", ) flask_app = lambda_python.PythonFunction( self, "DominionDividersFlaskApp", entry=self.lambda_dir, index="lambda-handlers.py", handler="apig_wsgi_handler", environment={ "STATIC_WEB_URL": f"https://{cf_static_dist.domain_name}", "FLASK_SECRET_KEY": self.config["SECRET_KEY"], "GA_CONFIG": self.config.get("GA_CONFIG", ""), }, timeout=core.Duration.seconds(60), memory_size=512, runtime=lambda_.Runtime.PYTHON_3_8, ) api = apig.LambdaRestApi( self, "bgtools-api", handler=flask_app, binary_media_types=["*/*"], minimum_compression_size=10e4, deploy_options={ "method_options": { "/*/*": apig.MethodDeploymentOptions(throttling_rate_limit=10, throttling_burst_limit=20) } }, ) cloudfront.Distribution( self, "BGToolsCloudfrontDist", default_behavior=cloudfront.BehaviorOptions( origin=cloudfront_origins.HttpOrigin( core.Fn.select(2, core.Fn.split("/", api.url)), origin_path=core.Fn.join( "", ["/", core.Fn.select(3, core.Fn.split("/", api.url))]), ), origin_request_policy=cloudfront.OriginRequestPolicy( self, "OriginRequestPolicy", cookie_behavior=cloudfront.OriginRequestCookieBehavior.all( ), ), allowed_methods=cloudfront.AllowedMethods.ALLOW_ALL, ), domain_names=["domdiv.bgtools.net"], certificate=acm.Certificate.from_certificate_arn( self, "cert", self.config["CERTIFICATE_ARN"], ), ) dashboard = aws_cloudwatch.Dashboard( self, f"bgtools-dashboard", dashboard_name=f"bgtools-prod", start="-P1D", period_override=aws_cloudwatch.PeriodOverride.INHERIT, ) dashboard.add_widgets( aws_cloudwatch.GraphWidget( title="API Gateway Counts", width=6, height=6, left=[ aws_cloudwatch.Metric( namespace="AWS/ApiGateway", metric_name="5XXError", dimensions={ "ApiName": "bgtools-api", "Stage": api.deployment_stage.stage_name, }, period=core.Duration.minutes(amount=30), statistic="Sum", color="#d62728", ), aws_cloudwatch.Metric( namespace="AWS/ApiGateway", metric_name="4XXError", dimensions={ "ApiName": "bgtools-api", "Stage": api.deployment_stage.stage_name, }, period=core.Duration.minutes(amount=30), statistic="Sum", color="#8c564b", ), aws_cloudwatch.Metric( namespace="AWS/ApiGateway", metric_name="Count", dimensions={ "ApiName": "bgtools-api", "Stage": api.deployment_stage.stage_name, }, period=core.Duration.minutes(amount=30), statistic="Sum", color="#2ca02c", ), ], ), aws_cloudwatch.GraphWidget( title="API Gateway Latencies", width=6, height=6, left=[ aws_cloudwatch.Metric( namespace="AWS/ApiGateway", metric_name="Latency", dimensions={ "ApiName": "bgtools-api", "Stage": api.deployment_stage.stage_name, }, period=core.Duration.minutes(amount=30), statistic="Average", ), aws_cloudwatch.Metric( namespace="AWS/ApiGateway", metric_name="IntegrationLatency", dimensions={ "ApiName": "bgtools-api", "Stage": api.deployment_stage.stage_name, }, period=core.Duration.minutes(amount=30), statistic="Average", ), ], ), )
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) self.current_dir = os.path.dirname(__file__) self.website_bucket = s3.Bucket( self, "qs-embed-bucket", bucket_name=f'quicksight-embed-{core.Aws.ACCOUNT_ID}', block_public_access=s3.BlockPublicAccess.BLOCK_ALL) self.quicksight_embed_lambda_role = iam.Role( self, 'quicksight-embed-lambda-role', description='Role for the Quicksight dashboard embed Lambdas', role_name='quicksight-embed-lambda-role', max_session_duration=core.Duration.seconds(3600), assumed_by=iam.ServicePrincipal('lambda.amazonaws.com'), inline_policies={ 'AllowAccess': iam.PolicyDocument(statements=[ iam.PolicyStatement( effect=iam.Effect.ALLOW, actions=[ 'logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents' ], resources=[ f'arn:aws:logs:{core.Aws.REGION}:{core.Aws.ACCOUNT_ID}:*' ]), iam.PolicyStatement( effect=iam.Effect.ALLOW, actions=["secrets:GetSecretValue"], resources=[ f"arn:aws:secretsmanager:{core.Aws.REGION}:{core.Aws.ACCOUNT_ID}:secret:*" ]), iam.PolicyStatement(effect=iam.Effect.ALLOW, actions=[ "quicksight:GetDashboardEmbedUrl", "quicksight:GetAuthCode" ], resources=["*"]) ]) }) self.quicksight_migration_lambda = _lambda.Function( self, 'quicksight-migration-lambda', handler='quicksight_embed.lambda_handler', runtime=_lambda.Runtime.PYTHON_3_8, code=_lambda.Code.from_asset( os.path.join(self.current_dir, '../lambda/quicksight_embed/')), function_name='quicksight_embed_lambda', role=self.quicksight_embed_lambda_role, timeout=core.Duration.minutes(3), memory_size=512, environment={ 'DASHBOARD_ID': 'CHANGEME_DASHBOARD_ID', 'QUICKSIGHT_USER_ARN': f'arn:aws:quicksight:us-east-1:{core.Aws.ACCOUNT_ID}:user/default/quicksight-migration-user' }) self.apigw_lambda = ApiGatewayToLambda( self, "ApiGatewayToLambdaQSEmbed", existing_lambda_obj=self.quicksight_migration_lambda, api_gateway_props=apigw.LambdaRestApiProps( rest_api_name="quicksight-embed", handler=self.quicksight_migration_lambda, deploy=True, proxy=False, default_method_options=apigw.MethodOptions( authorization_type=apigw.AuthorizationType.NONE), policy=iam.PolicyDocument(statements=[ iam.PolicyStatement(effect=iam.Effect.ALLOW, actions=['execute-api:Invoke'], resources=["execute-api:/prod/*"], principals=[iam.ArnPrincipal("*")]) ]))) self.embedurl = self.apigw_lambda.api_gateway.root.add_resource( "embedurl") self.embedurl.add_method( "GET", method_responses=[{ 'statusCode': '200', 'responseParameters': { 'method.response.header.Access-Control-Allow-Headers': True, 'method.response.header.Access-Control-Allow-Methods': True, 'method.response.header.Access-Control-Allow-Origin': True } }], integration=apigw.LambdaIntegration( self.quicksight_migration_lambda, proxy=False, integration_responses=[{ 'statusCode': '200', 'responseTemplates': { "application/json": "" }, 'responseParameters': { 'method.response.header.Access-Control-Allow-Headers': "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'", 'method.response.header.Access-Control-Allow-Origin': "'*'", 'method.response.header.Access-Control-Allow-Methods': "'GET'" } }])) self.embedurl.add_method( 'OPTIONS', apigw.MockIntegration(integration_responses=[{ 'statusCode': '200', 'responseParameters': { 'method.response.header.Access-Control-Allow-Headers': "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'", 'method.response.header.Access-Control-Allow-Origin': "'*'", 'method.response.header.Access-Control-Allow-Methods': "'GET,OPTIONS'" } }], passthrough_behavior=apigw. PassthroughBehavior.WHEN_NO_MATCH, request_templates={ "application/json": "{\"statusCode\":200}" }), method_responses=[{ 'statusCode': '200', 'responseParameters': { 'method.response.header.Access-Control-Allow-Headers': True, 'method.response.header.Access-Control-Allow-Methods': True, 'method.response.header.Access-Control-Allow-Origin': True } }]) # Cloudfront Distribution for authentication self.embed_auth_lambda_role = iam.Role( self, 'embed-auth-lambda-role', description= 'Role for the Quicksight dashboard embed authentication Lambda', role_name='embed-auth-lambda-role', max_session_duration=core.Duration.seconds(3600), assumed_by=iam.ServicePrincipal('lambda.amazonaws.com'), inline_policies={ 'AllowAccess': iam.PolicyDocument(statements=[ iam.PolicyStatement( effect=iam.Effect.ALLOW, actions=[ 'logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents' ], resources=[ f'arn:aws:logs:{core.Aws.REGION}:{core.Aws.ACCOUNT_ID}:*' ]) ]) }) self.embed_auth_lambda = _lambda.Function( self, 'embed-auth-lambda', handler='index.handler', description= "A Lambda@Edge function for QuickSight embed authentication via CloudFront Distribution", runtime=_lambda.Runtime.NODEJS_14_X, code=_lambda.Code.from_asset( os.path.join(self.current_dir, '../lambda/embed_auth/')), function_name='embed_auth_lambda', role=self.embed_auth_lambda_role, timeout=core.Duration.seconds(5), memory_size=128) self.embed_auth_dist = cloudfront.Distribution( self, "embed-auth-dist", enabled=True, default_root_object="index.html", default_behavior=cloudfront.BehaviorOptions( origin=origins.S3Origin(self.website_bucket), allowed_methods=cloudfront.AllowedMethods.ALLOW_GET_HEAD, edge_lambdas=[{ "functionVersion": self.embed_auth_lambda.current_version, "eventType": cloudfront.LambdaEdgeEventType.VIEWER_REQUEST, "includeBody": True }])) core.CfnOutput(self, "EmbedAPIGatewayURL", value=self.apigw_lambda.api_gateway.url + "embedurl?", description="Embed API GW URL") core.CfnOutput(self, "EmbedCloudFrontURL", value="https://" + self.embed_auth_dist.distribution_domain_name, description="CloudFront Distribution URL")
def create_static_site(scope: InfraStack, hosted_zone: route53.HostedZone): bucket = s3.Bucket( scope, id=scope.context.construct_id("s3"), bucket_name=f'{scope.context.construct_id("s3")}-bucket', versioned=True, block_public_access=s3.BlockPublicAccess( restrict_public_buckets=True, block_public_policy=True, block_public_acls=True, ), removal_policy=RemovalPolicy.RETAIN, auto_delete_objects=False, lifecycle_rules=[ s3.LifecycleRule(noncurrent_version_expiration=Duration.days(7)) ], ) prod_domain_name = "gingerbeans.tech" lower_domain_name = f"{scope.context.env_name}.gingerbeans.tech" domain_name = (prod_domain_name if scope.context.env_name == PRODUCTION else lower_domain_name) my_certificate = acm.DnsValidatedCertificate( scope, scope.context.construct_id("certificate"), domain_name=domain_name, hosted_zone=hosted_zone, region="us-east-1", ) origin_access_identity = cloudfront.OriginAccessIdentity( scope, scope.context.construct_id("cfOriginAccessIdentity")) cf_s3_access = iam.PolicyStatement() cf_s3_access.add_actions("s3:GetBucket*") cf_s3_access.add_actions("s3:GetObject*") cf_s3_access.add_actions("s3:List*") cf_s3_access.add_resources(bucket.bucket_arn) cf_s3_access.add_resources(f"{bucket.bucket_arn}/*") cf_s3_access.add_canonical_user_principal( origin_access_identity. cloud_front_origin_access_identity_s3_canonical_user_id) bucket.add_to_resource_policy(cf_s3_access) distro = cloudfront.Distribution( scope, scope.context.construct_id("dist"), default_behavior=cloudfront.BehaviorOptions(origin=origins.S3Origin( bucket=bucket, origin_access_identity=origin_access_identity)), default_root_object="index.html", domain_names=[domain_name], certificate=my_certificate, ) route53.AaaaRecord( scope, scope.context.construct_id("AAAA"), record_name=domain_name, target=route53.RecordTarget.from_alias( targets.CloudFrontTarget(distro)), zone=hosted_zone, ) route53.ARecord( scope, scope.context.construct_id("A"), record_name=domain_name, target=route53.RecordTarget.from_alias( targets.CloudFrontTarget(distro)), zone=hosted_zone, ) s3_deployment.BucketDeployment( scope, scope.context.construct_id("s3_deployment"), sources=[s3_deployment.Source.asset("../gb-ui/build")], destination_key_prefix="/", destination_bucket=bucket, distribution=distro, distribution_paths=["/*"], )
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