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, )
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))
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)) ])
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)
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") ])
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
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)], ) ], )
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, )
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=['/*'])
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 )
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, )
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, )
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, )
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, )
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=["/*"], )
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'], )
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)
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)
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)