-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstatic-site.ts
88 lines (79 loc) · 3.25 KB
/
static-site.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#!/usr/bin/env node
import cloudfront = require("@aws-cdk/aws-cloudfront");
import route53 = require("@aws-cdk/aws-route53");
import s3 = require("@aws-cdk/aws-s3");
import s3deploy = require("@aws-cdk/aws-s3-deployment");
import acm = require("@aws-cdk/aws-certificatemanager");
import cdk = require("@aws-cdk/core");
import targets = require("@aws-cdk/aws-route53-targets/lib");
import { Construct } from "@aws-cdk/core";
export interface StaticSiteProps {
domainName: string;
siteSubDomain: string;
}
/**
* Static site infrastructure, which deploys site content to an S3 bucket.
*
* The site redirects from HTTP to HTTPS, using a CloudFront distribution,
* Route53 alias record, and ACM certificate.
*/
export class StaticSite extends Construct {
constructor(parent: Construct, name: string, props: StaticSiteProps) {
super(parent, name);
const zone = route53.HostedZone.fromLookup(this, "Zone", {
domainName: props.domainName,
});
const siteDomain = props.siteSubDomain + "." + props.domainName;
new cdk.CfnOutput(this, "Site", { value: "https://" + siteDomain });
// Content bucket
const siteBucket = new s3.Bucket(this, "SiteBucket", {
bucketName: siteDomain,
websiteIndexDocument: "index.html",
websiteErrorDocument: "error.html",
publicReadAccess: true,
// The default removal policy is RETAIN, which means that cdk destroy will not attempt to delete
// the new bucket, and it will remain in your account until manually deleted. By setting the policy to
// DESTROY, cdk destroy will attempt to delete the bucket, but will error if the bucket is not empty.
removalPolicy: cdk.RemovalPolicy.DESTROY, // NOT recommended for production code
});
new cdk.CfnOutput(this, "Bucket", { value: siteBucket.bucketName });
// TLS certificate
const certificateArn = new acm.DnsValidatedCertificate(this, "SiteCertificate", {
domainName: props.domainName,
subjectAlternativeNames: ["*." + props.domainName],
hostedZone: zone,
}).certificateArn;
new cdk.CfnOutput(this, "Certificate", { value: certificateArn });
// CloudFront distribution that provides HTTPS
const distribution = new cloudfront.CloudFrontWebDistribution(this, "SiteDistribution", {
aliasConfiguration: {
acmCertRef: certificateArn,
names: [siteDomain],
sslMethod: cloudfront.SSLMethod.SNI,
securityPolicy: cloudfront.SecurityPolicyProtocol.TLS_V1_1_2016,
},
originConfigs: [
{
s3OriginSource: {
s3BucketSource: siteBucket,
},
behaviors: [{ isDefaultBehavior: true }],
},
],
});
new cdk.CfnOutput(this, "DistributionId", { value: distribution.distributionId });
// Route53 alias record for the CloudFront distribution
new route53.ARecord(this, "SiteAliasRecord", {
recordName: siteDomain,
target: route53.AddressRecordTarget.fromAlias(new targets.CloudFrontTarget(distribution)),
zone,
});
// Deploy site contents to S3 bucket
new s3deploy.BucketDeployment(this, "DeployWithInvalidation", {
sources: [s3deploy.Source.asset("./site-contents")],
destinationBucket: siteBucket,
distribution,
distributionPaths: ["/*"],
});
}
}