Untitled
unknown
plain_text
3 years ago
9.1 kB
3
Indexable
Never
import json import mimetypes import os from pulumi import export, FileAsset, ResourceOptions, Config, Output import pulumi import pulumi_aws import pulumi_aws.acm import pulumi_aws.cloudfront import pulumi_aws.config import pulumi_aws.route53 import pulumi_aws.s3 def get_domain_and_subdomain(domain): """ Returns the subdomain and the parent domain. """ parts = domain.split('.') if len(parts) < 2: raise Exception(f'No TLD found on ${domain}') if len(parts) == 2: return '', domain subdomain = parts[0] parts.pop(0) return subdomain, '.'.join(parts) + '.' # Read the configuration for this stack. stack_config = Config() stack = pulumi.get_stack() target_domain = stack_config.require('targetDomain') path_to_website_contents = stack_config.require('pathToWebsiteContents') certificate_arn = stack_config.get('certificateArn') tags = {"Environment": stack, "Name": target_domain} policy = { "Version": "2008-10-17", "Id": "PolicyForCloudFrontPrivateContent", "Statement": [ { "Sid": "1", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E2Z3TU7BBE9W01" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::cloud.notubes.link/*" } ] } ##Create Cloudfront Identity identity = pulumi_aws.cloudfront.OriginAccessIdentity("S3-identity", comment="S3-access") # Create an S3 bucket configured as a website bucket. content_bucket = pulumi_aws.s3.Bucket('contentBucket', bucket=target_domain, website=pulumi_aws.s3.BucketWebsiteArgs( index_document='index.html' ), acl = "private", #policy = policy, tags = tags ) def crawl_directory(content_dir, f): """ Crawl `content_dir` (including subdirectories) and apply the function `f` to each file. """ for file in os.listdir(content_dir): filepath = os.path.join(content_dir, file) if os.path.isdir(filepath): crawl_directory(filepath, f) elif os.path.isfile(filepath): f(filepath) web_contents_root_path = os.path.join(os.getcwd(), path_to_website_contents) def bucket_object_converter(filepath): """ Takes a file path and returns an bucket object managed by Pulumi """ relative_path = filepath.replace(web_contents_root_path + '/', '') # Determine the mimetype using the `mimetypes` module. mime_type, _ = mimetypes.guess_type(filepath) content_file = pulumi_aws.s3.BucketObject( relative_path, key=relative_path, acl='public-read', bucket=content_bucket.id, content_type=mime_type, source=FileAsset(filepath), opts=ResourceOptions(parent=content_bucket) ) # Crawl the web content root path and convert the file paths to S3 object resources. crawl_directory(web_contents_root_path, bucket_object_converter) TEN_MINUTES = 60 * 10 # Provision a certificate if the arn is not provided via configuration. if certificate_arn is None: # CloudFront is in us-east-1 and expects the ACM certificate to also be in us-east-1. # So, we create an east_region provider specifically for these operations. east_region = pulumi_aws.Provider('east', profile=pulumi_aws.config.profile, region='us-east-1') # Get a certificate for our website domain name. certificate = pulumi_aws.acm.Certificate('certificate', domain_name=target_domain, validation_method='DNS', opts=ResourceOptions(provider=east_region)) # Find the Route 53 hosted zone so we can create the validation record. subdomain, parent_domain = get_domain_and_subdomain(target_domain) hzid = pulumi_aws.route53.get_zone(name=parent_domain).id # Create a validation record to prove that we own the domain. cert_validation_domain = pulumi_aws.route53.Record(f'{target_domain}-validation', name=certificate.domain_validation_options.apply( lambda o: o[0].resource_record_name), zone_id=hzid, type=certificate.domain_validation_options.apply( lambda o: o[0].resource_record_type), records=[certificate.domain_validation_options.apply( lambda o: o[0].resource_record_value)], ttl=TEN_MINUTES) # Create a special resource to await complete validation of the cert. # Note that this is not a real AWS resource. cert_validation = pulumi_aws.acm.CertificateValidation('certificateValidation', certificate_arn=certificate.arn, validation_record_fqdns=[cert_validation_domain.fqdn], opts=ResourceOptions(provider=east_region)) certificate_arn = cert_validation.certificate_arn # Create a logs bucket for the CloudFront logs logs_bucket = pulumi_aws.s3.Bucket('requestLogs', bucket=f'{target_domain}-logs', acl='private',tags = tags) # Create the CloudFront distribution cdn = pulumi_aws.cloudfront.Distribution('cdn', enabled=True, aliases=[ target_domain ], origins=[pulumi_aws.cloudfront.DistributionOriginArgs( origin_id=content_bucket.arn, domain_name=content_bucket.bucket_regional_domain_name, s3_origin_config=pulumi_aws.cloudfront.DistributionOriginS3OriginConfigArgs( origin_access_identity=identity.cloudfront_access_identity_path, ) )], default_root_object='index.html', default_cache_behavior=pulumi_aws.cloudfront.DistributionDefaultCacheBehaviorArgs( target_origin_id=content_bucket.arn, viewer_protocol_policy='redirect-to-https', allowed_methods=['GET', 'HEAD', 'OPTIONS'], cached_methods=['GET', 'HEAD', 'OPTIONS'], forwarded_values=pulumi_aws.cloudfront.DistributionDefaultCacheBehaviorForwardedValuesArgs( cookies=pulumi_aws.cloudfront.DistributionDefaultCacheBehaviorForwardedValuesCookiesArgs(forward='none'), query_string=False, ), min_ttl=0, default_ttl=TEN_MINUTES, max_ttl=TEN_MINUTES, ), # PriceClass_100 is the lowest cost tier (US/EU only). price_class= 'PriceClass_100', # Use the certificate we generated for this distribution. viewer_certificate=pulumi_aws.cloudfront.DistributionViewerCertificateArgs( acm_certificate_arn=certificate_arn, minimum_protocol_version='TLSv1.2_2021', ssl_support_method='sni-only', ), restrictions=pulumi_aws.cloudfront.DistributionRestrictionsArgs( geo_restriction=pulumi_aws.cloudfront.DistributionRestrictionsGeoRestrictionArgs( restriction_type='none' ) ), # Put access logs in the log bucket we created earlier. logging_config=pulumi_aws.cloudfront.DistributionLoggingConfigArgs( bucket=logs_bucket.bucket_domain_name, include_cookies=False, prefix=f'${target_domain}/', ), tags = tags, # CloudFront typically takes 15 minutes to fully deploy a new distribution. # Skip waiting for that to complete. wait_for_deployment=False) def create_alias_record(target_domain, distribution): """ Create a Route 53 Alias A record from the target domain name to the CloudFront distribution. """ subdomain, parent_domain = get_domain_and_subdomain(target_domain) hzid = pulumi_aws.route53.get_zone(name=parent_domain).id return pulumi_aws.route53.Record(target_domain, name=subdomain, zone_id=hzid, type='A', aliases=[ pulumi_aws.route53.RecordAliasArgs( name=distribution.domain_name, zone_id=distribution.hosted_zone_id, evaluate_target_health=True, ) ] ) alias_a_record = create_alias_record(target_domain, cdn) ##Policy for bucket allow_access_from_another_account_policy_document = pulumi_aws.iam.get_policy_document_output(statements=[pulumi_aws.iam.GetPolicyDocumentStatementArgs( principals=[pulumi_aws.iam.GetPolicyDocumentStatementPrincipalArgs( type="AWS", identifiers=[identity.id], )], actions=[ "s3:GetObject", "s3:ListBucket", ], resources=[ content_bucket.arn, content_bucket.arn.apply(lambda arn: f"{arn}/*"), ], )]) allow_cdn = pulumi_aws.s3.BucketPolicy("allowAccessFromAnotherAccountBucketPolicy", bucket=content_bucket.id, policy=allow_access_from_another_account_policy_document.json) #Export the bucket URL, bucket website endpoint, and the CloudFront distribution information. export('content_bucket_url', Output.concat('s3://', content_bucket.bucket)) export('content_bucket_website_endpoint', content_bucket.website_endpoint) export('cloudfront_domain', cdn.domain_name) export('target_domain_endpoint', f'https://{target_domain}/') export('identity',identity.iam_arn) export("identity.id",identity.id) export("s3",content_bucket.id) export("name",content_bucket.bucket_regional_domain_name) export("idy",identity.caller_reference) export("idy",identity.etag) export("idy",identity.comment)