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';
5 const config
= new Config();
9 const bucketName
= config
.require('bucketName');
10 const bucket
= new s3
.BucketV2('captura-backend-bucket', {
14 const bucketOwnershipControls
= new s3
.BucketOwnershipControls('captura-backend-bucket-ownership-control', {
17 objectOwnership: "BucketOwnerPreferred",
21 const bucketPublicAccessBlock
= new s3
.BucketPublicAccessBlock('captura-backend-bucket-access-block', {
23 blockPublicAcls: false,
24 blockPublicPolicy: false,
25 ignorePublicAcls: false,
26 restrictPublicBuckets: false,
29 new s3
.BucketLifecycleConfigurationV2('captura-backend-bucket-lifecycle', {
32 id: 'expireAfter30Days',
39 new s3
.BucketAclV2('captura-backend-bucket-acl', {
44 bucketOwnershipControls
,
45 bucketPublicAccessBlock
,
49 const bucketCertificate
= new acm
.Certificate(`captura-backend-bucket-certificate`, {
50 domainName: config
.require('bucketDomain'),
51 validationMethod: 'DNS'
54 const bucketValidationRecord
= new route53
.Record(`captura-backend-bucket-certificate-validation-record`, {
56 name: bucketCertificate
.domainValidationOptions
[0].resourceRecordName
,
57 records: [bucketCertificate
.domainValidationOptions
[0].resourceRecordValue
],
58 type: bucketCertificate
.domainValidationOptions
[0].resourceRecordType
,
60 zoneId: config
.require('zoneId')
63 const bucketCertificateValidation
= new acm
.CertificateValidation(`captura-backend-bucket-certificate-validation`, {
64 certificateArn: bucketCertificate
.arn
,
65 validationRecordFqdns: [bucketValidationRecord
.fqdn
]
68 const bucketCdn
= new cloudfront
.Distribution('captura-backend-bucket-cdn', {
69 comment: 'captura-backend',
72 defaultRootObject: 'index.html',
74 config
.require('bucketDomain')
76 defaultCacheBehavior: {
77 targetOriginId: bucket
.arn
,
78 viewerProtocolPolicy: 'redirect-to-https',
103 customErrorResponses: [
106 errorCachingMinTtl: 300,
108 responsePagePath: '/index.html'
113 domainName: bucket
.bucketRegionalDomainName
,
118 restrictionType: 'none'
122 acmCertificateArn: bucketCertificateValidation
.certificateArn
,
123 sslSupportMethod: 'sni-only',
124 minimumProtocolVersion: 'TLSv1.2_2021'
128 new route53
.Record('captura-backend-bucket-domain', {
129 zoneId: config
.require('zoneId'),
130 name: config
.require('bucketDomain'),
133 name: bucketCdn
.domainName
,
134 zoneId: bucketCdn
.hostedZoneId
,
135 evaluateTargetHealth: true
142 const lambdaRole
= new iam
.Role('captura-backend-lambda-role', {
143 assumeRolePolicy: JSON
.stringify({
144 Version: '2012-10-17',
147 Action: 'sts:AssumeRole',
149 Service: 'lambda.amazonaws.com',
158 new iam
.RolePolicy('captura-backend-lambda-s3-policy', {
161 Version: '2012-10-17',
164 Action: 's3:PutObject',
165 Resource: bucket
.id
.apply((id
) => `arn:aws:s3:::${id}/*`),
168 Action: 's3:PutObjectAcl',
169 Resource: bucket
.id
.apply((id
) => `arn:aws:s3:::${id}/*`),
174 // Allow the API Gateway service to invoke the Lambda function
175 new iam
.RolePolicy('captura-backend-lambda-invoke-policy', {
178 Version: '2012-10-17',
181 Action: 'lambda:InvokeFunction',
187 new iam
.RolePolicy('captura-backend-lambda-logs-policy', {
190 Version: '2012-10-17',
194 'logs:CreateLogGroup',
195 'logs:CreateLogStream',
198 Resource: 'arn:aws:logs:*:*:*'
203 const integrationLambda
= new lambda
.Function('captura-backend-lambda', {
204 code: new asset
.AssetArchive({
205 '.': new asset
.FileArchive('./src'),
207 role: lambdaRole
.arn
,
208 handler: 'index.handler',
209 runtime: 'nodejs18.x',
212 S3_BUCKET: bucket
.id
,
213 DOMAIN_NAME: config
.require('bucketDomain')
220 const api
= new RestAPI('captura-backend-api', {
224 eventHandler: integrationLambda
,
228 const apiCertificate
= new acm
.Certificate(`captura-backend-api-certificate`, {
229 domainName: config
.require('apiDomain'),
230 validationMethod: 'DNS'
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
,
239 zoneId: config
.require('zoneId')
242 new acm
.CertificateValidation(`captura-backend-api-certificate-validation`, {
243 certificateArn: apiCertificate
.arn
,
244 validationRecordFqdns: [apiValidationRecord
.fqdn
]
247 const domain
= new apigateway
.DomainName('captura-backend-api-domain', {
248 certificateArn: apiCertificate
.arn
,
249 domainName: config
.require('apiDomain')
252 new apigateway
.BasePathMapping('captura-backend-base-path', {
254 stageName: api
.stage
.stageName
,
255 domainName: domain
.domainName
258 new route53
.Record('captura-backend-dns-record', {
259 zoneId: config
.require('zoneId'),
260 name: config
.require('apiDomain'),
263 name: domain
.cloudfrontDomainName
,
264 zoneId: domain
.cloudfrontZoneId
,
265 evaluateTargetHealth: true