]> git.r.bdr.sh - rbdr/captura-backend-example/blob - index.js
Add code
[rbdr/captura-backend-example] / index.js
1 import { Config, asset } from '@pulumi/pulumi';
2 import { acm, apigateway, cloudfront, iam, lambda, route53, s3 } from '@pulumi/aws';
3 import { RestAPI } from '@pulumi/aws-apigateway';
4
5 const config = new Config();
6
7 // Bucket Config
8
9 const bucketName = config.require('bucketName');
10 const bucket = new s3.BucketV2('captura-backend-bucket', {
11 name: bucketName,
12 });
13
14 const bucketOwnershipControls = new s3.BucketOwnershipControls('captura-backend-bucket-ownership-control', {
15 bucket: bucket.id,
16 rule: {
17 objectOwnership: "BucketOwnerPreferred",
18 },
19 });
20
21 const bucketPublicAccessBlock = new s3.BucketPublicAccessBlock('captura-backend-bucket-access-block', {
22 bucket: bucket.id,
23 blockPublicAcls: false,
24 blockPublicPolicy: false,
25 ignorePublicAcls: false,
26 restrictPublicBuckets: false,
27 });
28
29 new s3.BucketLifecycleConfigurationV2('captura-backend-bucket-lifecycle', {
30 bucket: bucket.id,
31 rules: [{
32 id: 'expireAfter30Days',
33 status: 'Enabled',
34 expiration: {
35 days: 30,
36 },
37 }],
38 });
39 new s3.BucketAclV2('captura-backend-bucket-acl', {
40 bucket: bucket.id,
41 acl: 'public-read',
42 }, {
43 dependsOn: [
44 bucketOwnershipControls,
45 bucketPublicAccessBlock,
46 ],
47 });
48
49 const bucketCertificate = new acm.Certificate(`captura-backend-bucket-certificate`, {
50 domainName: config.require('bucketDomain'),
51 validationMethod: 'DNS'
52 });
53
54 const bucketValidationRecord = new route53.Record(`captura-backend-bucket-certificate-validation-record`, {
55 allowOverwrite: true,
56 name: bucketCertificate.domainValidationOptions[0].resourceRecordName,
57 records: [bucketCertificate.domainValidationOptions[0].resourceRecordValue],
58 type: bucketCertificate.domainValidationOptions[0].resourceRecordType,
59 ttl: 60,
60 zoneId: config.require('zoneId')
61 });
62
63 const bucketCertificateValidation = new acm.CertificateValidation(`captura-backend-bucket-certificate-validation`, {
64 certificateArn: bucketCertificate.arn,
65 validationRecordFqdns: [bucketValidationRecord.fqdn]
66 });
67
68 const bucketCdn = new cloudfront.Distribution('captura-backend-bucket-cdn', {
69 comment: 'captura-backend',
70 enabled: true,
71 isIpv6Enabled: true,
72 defaultRootObject: 'index.html',
73 aliases: [
74 config.require('bucketDomain')
75 ],
76 defaultCacheBehavior: {
77 targetOriginId: bucket.arn,
78 viewerProtocolPolicy: 'redirect-to-https',
79 allowedMethods: [
80 'GET',
81 'HEAD',
82 'OPTIONS'
83 ],
84 cachedMethods: [
85 'GET',
86 'HEAD',
87 'OPTIONS'
88 ],
89 forwardedValues: {
90 queryString: false,
91 cookies: {
92 forward: 'none'
93 },
94 headers: [
95 'Origin'
96 ]
97 },
98 compress: true,
99 minTtl: 0,
100 defaultTtl: 3600,
101 maxTtl: 86400
102 },
103 customErrorResponses: [
104 {
105 errorCode: 404,
106 errorCachingMinTtl: 300,
107 responseCode: 200,
108 responsePagePath: '/index.html'
109 }
110
111 ],
112 origins: [{
113 domainName: bucket.bucketRegionalDomainName,
114 originId: bucket.arn
115 }],
116 restrictions: {
117 geoRestriction: {
118 restrictionType: 'none'
119 }
120 },
121 viewerCertificate: {
122 acmCertificateArn: bucketCertificateValidation.certificateArn,
123 sslSupportMethod: 'sni-only',
124 minimumProtocolVersion: 'TLSv1.2_2021'
125 }
126 });
127
128 new route53.Record('captura-backend-bucket-domain', {
129 zoneId: config.require('zoneId'),
130 name: config.require('bucketDomain'),
131 type: 'A',
132 aliases: [{
133 name: bucketCdn.domainName,
134 zoneId: bucketCdn.hostedZoneId,
135 evaluateTargetHealth: true
136 }]
137 });
138
139
140 // API Config
141
142 const lambdaRole = new iam.Role('captura-backend-lambda-role', {
143 assumeRolePolicy: JSON.stringify({
144 Version: '2012-10-17',
145 Statement: [
146 {
147 Action: 'sts:AssumeRole',
148 Principal: {
149 Service: 'lambda.amazonaws.com',
150 },
151 Effect: 'Allow',
152 Sid: '',
153 },
154 ],
155 }),
156 });
157
158 new iam.RolePolicy('captura-backend-lambda-s3-policy', {
159 role: lambdaRole.id,
160 policy: {
161 Version: '2012-10-17',
162 Statement: [{
163 Effect: 'Allow',
164 Action: 's3:PutObject',
165 Resource: bucket.id.apply((id) => `arn:aws:s3:::${id}/*`),
166 }, {
167 Effect: 'Allow',
168 Action: 's3:PutObjectAcl',
169 Resource: bucket.id.apply((id) => `arn:aws:s3:::${id}/*`),
170 }],
171 },
172 });
173
174 // Allow the API Gateway service to invoke the Lambda function
175 new iam.RolePolicy('captura-backend-lambda-invoke-policy', {
176 role: lambdaRole.id,
177 policy: {
178 Version: '2012-10-17',
179 Statement: [{
180 Effect: 'Allow',
181 Action: 'lambda:InvokeFunction',
182 Resource: '*',
183 }],
184 },
185 });
186
187 new iam.RolePolicy('captura-backend-lambda-logs-policy', {
188 role: lambdaRole.id,
189 policy: {
190 Version: '2012-10-17',
191 Statement: [{
192 Effect: 'Allow',
193 Action: [
194 'logs:CreateLogGroup',
195 'logs:CreateLogStream',
196 'logs:PutLogEvents'
197 ],
198 Resource: 'arn:aws:logs:*:*:*'
199 }],
200 },
201 });
202
203 const integrationLambda = new lambda.Function('captura-backend-lambda', {
204 code: new asset.AssetArchive({
205 '.': new asset.FileArchive('./src'),
206 }),
207 role: lambdaRole.arn,
208 handler: 'index.handler',
209 runtime: 'nodejs18.x',
210 environment: {
211 variables: {
212 S3_BUCKET: bucket.id,
213 DOMAIN_NAME: config.require('bucketDomain')
214 }
215 },
216 role: lambdaRole.arn
217 });
218
219
220 const api = new RestAPI('captura-backend-api', {
221 routes: [{
222 path: '/',
223 method: 'POST',
224 eventHandler: integrationLambda,
225 }],
226 });
227
228 const apiCertificate = new acm.Certificate(`captura-backend-api-certificate`, {
229 domainName: config.require('apiDomain'),
230 validationMethod: 'DNS'
231 });
232
233 const apiValidationRecord = new route53.Record(`captura-backend-api-certificate-validation-record`, {
234 allowOverwrite: true,
235 name: apiCertificate.domainValidationOptions[0].resourceRecordName,
236 records: [apiCertificate.domainValidationOptions[0].resourceRecordValue],
237 type: apiCertificate.domainValidationOptions[0].resourceRecordType,
238 ttl: 60,
239 zoneId: config.require('zoneId')
240 });
241
242 new acm.CertificateValidation(`captura-backend-api-certificate-validation`, {
243 certificateArn: apiCertificate.arn,
244 validationRecordFqdns: [apiValidationRecord.fqdn]
245 });
246
247 const domain = new apigateway.DomainName('captura-backend-api-domain', {
248 certificateArn: apiCertificate.arn,
249 domainName: config.require('apiDomain')
250 });
251
252 new apigateway.BasePathMapping('captura-backend-base-path', {
253 restApi: api.api.id,
254 stageName: api.stage.stageName,
255 domainName: domain.domainName
256 });
257
258 new route53.Record('captura-backend-dns-record', {
259 zoneId: config.require('zoneId'),
260 name: config.require('apiDomain'),
261 type: 'A',
262 aliases: [{
263 name: domain.cloudfrontDomainName,
264 zoneId: domain.cloudfrontZoneId,
265 evaluateTargetHealth: true
266 }],
267 });