aboutsummaryrefslogtreecommitdiff
path: root/index.js
diff options
context:
space:
mode:
authorRuben Beltran del Rio <ruben@unlimited.pizza>2023-11-02 22:28:41 +0100
committerRuben Beltran del Rio <ruben@unlimited.pizza>2023-11-02 22:28:41 +0100
commit08b55c6db901910dd0540a45257122f9450cbe0a (patch)
tree155d28d3ff1b669add11879809d04f6b57071e92 /index.js
Add code
Diffstat (limited to 'index.js')
-rw-r--r--index.js267
1 files changed, 267 insertions, 0 deletions
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..b64a1a8
--- /dev/null
+++ b/index.js
@@ -0,0 +1,267 @@
+import { Config, asset } from '@pulumi/pulumi';
+import { acm, apigateway, cloudfront, iam, lambda, route53, s3 } from '@pulumi/aws';
+import { RestAPI } from '@pulumi/aws-apigateway';
+
+const config = new Config();
+
+// Bucket Config
+
+const bucketName = config.require('bucketName');
+const bucket = new s3.BucketV2('captura-backend-bucket', {
+ name: bucketName,
+});
+
+const bucketOwnershipControls = new s3.BucketOwnershipControls('captura-backend-bucket-ownership-control', {
+ bucket: bucket.id,
+ rule: {
+ objectOwnership: "BucketOwnerPreferred",
+ },
+});
+
+const bucketPublicAccessBlock = new s3.BucketPublicAccessBlock('captura-backend-bucket-access-block', {
+ bucket: bucket.id,
+ blockPublicAcls: false,
+ blockPublicPolicy: false,
+ ignorePublicAcls: false,
+ restrictPublicBuckets: false,
+});
+
+new s3.BucketLifecycleConfigurationV2('captura-backend-bucket-lifecycle', {
+ bucket: bucket.id,
+ rules: [{
+ id: 'expireAfter30Days',
+ status: 'Enabled',
+ expiration: {
+ days: 30,
+ },
+ }],
+});
+new s3.BucketAclV2('captura-backend-bucket-acl', {
+ bucket: bucket.id,
+ acl: 'public-read',
+}, {
+ dependsOn: [
+ bucketOwnershipControls,
+ bucketPublicAccessBlock,
+ ],
+});
+
+const bucketCertificate = new acm.Certificate(`captura-backend-bucket-certificate`, {
+ domainName: config.require('bucketDomain'),
+ validationMethod: 'DNS'
+});
+
+const bucketValidationRecord = new route53.Record(`captura-backend-bucket-certificate-validation-record`, {
+ allowOverwrite: true,
+ name: bucketCertificate.domainValidationOptions[0].resourceRecordName,
+ records: [bucketCertificate.domainValidationOptions[0].resourceRecordValue],
+ type: bucketCertificate.domainValidationOptions[0].resourceRecordType,
+ ttl: 60,
+ zoneId: config.require('zoneId')
+});
+
+const bucketCertificateValidation = new acm.CertificateValidation(`captura-backend-bucket-certificate-validation`, {
+ certificateArn: bucketCertificate.arn,
+ validationRecordFqdns: [bucketValidationRecord.fqdn]
+});
+
+const bucketCdn = new cloudfront.Distribution('captura-backend-bucket-cdn', {
+ comment: 'captura-backend',
+ enabled: true,
+ isIpv6Enabled: true,
+ defaultRootObject: 'index.html',
+ aliases: [
+ config.require('bucketDomain')
+ ],
+ defaultCacheBehavior: {
+ targetOriginId: bucket.arn,
+ viewerProtocolPolicy: 'redirect-to-https',
+ allowedMethods: [
+ 'GET',
+ 'HEAD',
+ 'OPTIONS'
+ ],
+ cachedMethods: [
+ 'GET',
+ 'HEAD',
+ 'OPTIONS'
+ ],
+ forwardedValues: {
+ queryString: false,
+ cookies: {
+ forward: 'none'
+ },
+ headers: [
+ 'Origin'
+ ]
+ },
+ compress: true,
+ minTtl: 0,
+ defaultTtl: 3600,
+ maxTtl: 86400
+ },
+ customErrorResponses: [
+ {
+ errorCode: 404,
+ errorCachingMinTtl: 300,
+ responseCode: 200,
+ responsePagePath: '/index.html'
+ }
+
+ ],
+ origins: [{
+ domainName: bucket.bucketRegionalDomainName,
+ originId: bucket.arn
+ }],
+ restrictions: {
+ geoRestriction: {
+ restrictionType: 'none'
+ }
+ },
+ viewerCertificate: {
+ acmCertificateArn: bucketCertificateValidation.certificateArn,
+ sslSupportMethod: 'sni-only',
+ minimumProtocolVersion: 'TLSv1.2_2021'
+ }
+});
+
+new route53.Record('captura-backend-bucket-domain', {
+ zoneId: config.require('zoneId'),
+ name: config.require('bucketDomain'),
+ type: 'A',
+ aliases: [{
+ name: bucketCdn.domainName,
+ zoneId: bucketCdn.hostedZoneId,
+ evaluateTargetHealth: true
+ }]
+});
+
+
+// API Config
+
+const lambdaRole = new iam.Role('captura-backend-lambda-role', {
+ assumeRolePolicy: JSON.stringify({
+ Version: '2012-10-17',
+ Statement: [
+ {
+ Action: 'sts:AssumeRole',
+ Principal: {
+ Service: 'lambda.amazonaws.com',
+ },
+ Effect: 'Allow',
+ Sid: '',
+ },
+ ],
+ }),
+});
+
+new iam.RolePolicy('captura-backend-lambda-s3-policy', {
+ role: lambdaRole.id,
+ policy: {
+ Version: '2012-10-17',
+ Statement: [{
+ Effect: 'Allow',
+ Action: 's3:PutObject',
+ Resource: bucket.id.apply((id) => `arn:aws:s3:::${id}/*`),
+ }, {
+ Effect: 'Allow',
+ Action: 's3:PutObjectAcl',
+ Resource: bucket.id.apply((id) => `arn:aws:s3:::${id}/*`),
+ }],
+ },
+});
+
+// Allow the API Gateway service to invoke the Lambda function
+new iam.RolePolicy('captura-backend-lambda-invoke-policy', {
+ role: lambdaRole.id,
+ policy: {
+ Version: '2012-10-17',
+ Statement: [{
+ Effect: 'Allow',
+ Action: 'lambda:InvokeFunction',
+ Resource: '*',
+ }],
+ },
+});
+
+new iam.RolePolicy('captura-backend-lambda-logs-policy', {
+ role: lambdaRole.id,
+ policy: {
+ Version: '2012-10-17',
+ Statement: [{
+ Effect: 'Allow',
+ Action: [
+ 'logs:CreateLogGroup',
+ 'logs:CreateLogStream',
+ 'logs:PutLogEvents'
+ ],
+ Resource: 'arn:aws:logs:*:*:*'
+ }],
+ },
+});
+
+const integrationLambda = new lambda.Function('captura-backend-lambda', {
+ code: new asset.AssetArchive({
+ '.': new asset.FileArchive('./src'),
+ }),
+ role: lambdaRole.arn,
+ handler: 'index.handler',
+ runtime: 'nodejs18.x',
+ environment: {
+ variables: {
+ S3_BUCKET: bucket.id,
+ DOMAIN_NAME: config.require('bucketDomain')
+ }
+ },
+ role: lambdaRole.arn
+});
+
+
+const api = new RestAPI('captura-backend-api', {
+ routes: [{
+ path: '/',
+ method: 'POST',
+ eventHandler: integrationLambda,
+ }],
+});
+
+const apiCertificate = new acm.Certificate(`captura-backend-api-certificate`, {
+ domainName: config.require('apiDomain'),
+ validationMethod: 'DNS'
+});
+
+const apiValidationRecord = new route53.Record(`captura-backend-api-certificate-validation-record`, {
+ allowOverwrite: true,
+ name: apiCertificate.domainValidationOptions[0].resourceRecordName,
+ records: [apiCertificate.domainValidationOptions[0].resourceRecordValue],
+ type: apiCertificate.domainValidationOptions[0].resourceRecordType,
+ ttl: 60,
+ zoneId: config.require('zoneId')
+});
+
+new acm.CertificateValidation(`captura-backend-api-certificate-validation`, {
+ certificateArn: apiCertificate.arn,
+ validationRecordFqdns: [apiValidationRecord.fqdn]
+});
+
+const domain = new apigateway.DomainName('captura-backend-api-domain', {
+ certificateArn: apiCertificate.arn,
+ domainName: config.require('apiDomain')
+});
+
+new apigateway.BasePathMapping('captura-backend-base-path', {
+ restApi: api.api.id,
+ stageName: api.stage.stageName,
+ domainName: domain.domainName
+});
+
+new route53.Record('captura-backend-dns-record', {
+ zoneId: config.require('zoneId'),
+ name: config.require('apiDomain'),
+ type: 'A',
+ aliases: [{
+ name: domain.cloudfrontDomainName,
+ zoneId: domain.cloudfrontZoneId,
+ evaluateTargetHealth: true
+ }],
+});