-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.ts
157 lines (142 loc) · 4.45 KB
/
index.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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/* eslint-disable @typescript-eslint/no-unused-vars */
import * as pulumi from '@pulumi/pulumi';
import * as aws from '@pulumi/aws';
import { createFrontendPipelineUser } from './src/iam/frontendPipelineUser';
import { createBucketPolicyDocument } from './src/s3/bucketPolicy';
import { getARN } from './src/utils/getARN';
import { requestRewriterLambda } from './src/lambda@edge/requestRewriter';
import { getExistingCertificate } from './src/acm/getCertificate';
import { createBackend } from './src/backend/backend';
// Import the program's configuration settings.
const config = new pulumi.Config();
const path = config.get('path') || './www';
const indexDocument = config.get('indexDocument') || 'index.html';
const errorDocument = config.get('errorDocument') || 'error.html';
const domain = config.require('domain');
const subdomain = config.require('subdomain');
const domainName = `${subdomain}.${domain}`;
// Create an S3 bucket and configure it as a website.
const bucket = new aws.s3.Bucket('bucket', {
bucket: 'dev.jss.computer', // prepended to pulumi's auto-generated name
});
// Configure ownership controls for the new S3 bucket
const ownershipControls = new aws.s3.BucketOwnershipControls(
'ownership-controls',
{
bucket: bucket.bucket,
rule: {
objectOwnership: 'ObjectWriter',
},
}
);
// Configure public ACL block on the new S3 bucket
const publicAccessBlock = new aws.s3.BucketPublicAccessBlock(
'public-access-block',
{
bucket: bucket.bucket,
blockPublicAcls: true, // block all direct access with these settings
blockPublicPolicy: true,
ignorePublicAcls: true,
restrictPublicBuckets: true,
}
);
// Get existing Certificate from ACM
const certificate = getExistingCertificate(domain);
const OAC = new aws.cloudfront.OriginAccessControl('example', {
description: 'OAC for CDN to access bucket',
originAccessControlOriginType: 's3',
signingBehavior: 'always',
signingProtocol: 'sigv4',
});
// Create a CloudFront CDN to distribute and cache the website.
const cdn = new aws.cloudfront.Distribution('cdn', {
enabled: true,
origins: [
{
originId: bucket.arn,
domainName: bucket.bucketDomainName,
originAccessControlId: OAC.id,
},
],
defaultCacheBehavior: {
targetOriginId: bucket.arn,
viewerProtocolPolicy: 'redirect-to-https',
allowedMethods: ['GET', 'HEAD', 'OPTIONS'],
cachedMethods: ['GET', 'HEAD', 'OPTIONS'],
defaultTtl: 600,
maxTtl: 600,
minTtl: 600,
forwardedValues: {
queryString: true,
cookies: {
forward: 'all',
},
},
// Include a Lambda to rewrite origin requests including a '+' to using '%2B' since S3 interprets '+' incorrectly
lambdaFunctionAssociations: [
{
eventType: 'origin-request',
lambdaArn: requestRewriterLambda.qualifiedArn,
},
],
},
priceClass: 'PriceClass_100',
defaultRootObject: 'index.html',
customErrorResponses: [
{
errorCode: 404,
responseCode: 404,
responsePagePath: `/${errorDocument}`,
},
],
restrictions: {
geoRestriction: {
restrictionType: 'none',
},
},
aliases: [domainName],
viewerCertificate: {
cloudfrontDefaultCertificate: false,
acmCertificateArn: getARN(certificate),
sslSupportMethod: 'sni-only', // avoiding extra charges
},
});
// Create CI-CD User
const pipelineUser = createFrontendPipelineUser(bucket, cdn);
const bucketPolicyDocument = createBucketPolicyDocument({
bucket,
distribution: cdn,
pipelineUser,
});
const attachedBucketPolicy = new aws.s3.BucketPolicy('s3bucketPolicy', {
bucket: bucket.id,
policy: bucketPolicyDocument.json,
});
// Create a DNS A record to point to the CDN for the subdomain.
const zone = aws.route53.getZoneOutput({ name: domain });
const record = new aws.route53.Record(domainName, {
name: subdomain,
zoneId: zone.zoneId,
type: 'A',
aliases: [
{
name: cdn.domainName,
zoneId: cdn.hostedZoneId,
evaluateTargetHealth: true,
},
],
});
// Create Backend
export const {
loadBalancerUrl,
repoName,
serviceName,
clusterName,
containerName,
} = createBackend();
// Export the URLs and hostnames of the bucket and distribution.
export const originURL = pulumi.interpolate`http://${bucket.websiteEndpoint}`;
export const originHostname = bucket.websiteEndpoint;
export const cdnURL = pulumi.interpolate`https://${cdn.domainName}`;
export const cdnHostname = cdn.domainName;
export const domainURL = `https://${domainName}`;