diff --git a/.gitignore b/.gitignore index 0eac307261..2cb4863fee 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,13 @@ dist-ssr *.njsproj *.sln *.sw? + + +infra/*.js +infra/!jest.config.js +infra/*.d.ts +infra/node_modules + +# CDK asset staging directory +infra/.cdk.staging +infra/cdk.out diff --git a/README.md b/README.md index ef911c67fc..963921f972 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,17 @@ +#links + + - s3ObjectUrl - https://deploywebappstack-deploymentfrontendbucketpeerbe50-pxzhgtc68oce.s3.us-east-1.amazonaws.com/index.html - //will get 403 as permission is configured only for cloudfront + + - cloudfrontUrl - https://d2855wervvjyj6.cloudfront.net/ + + +# added necessary scripts to automated builds and deploy in infra/package.json" + +git reset --hard HEAD~1 +fatal: ambiguous argument 'HEAD~1': unknown revision or path not in the working tree. +Use '--' to separate paths from revisions, like this: +'git [...] -- [...]' + # React-shop-cloudfront This is frontend starter project for nodejs-aws mentoring program. It uses the following technologies: diff --git a/infra/.npmignore b/infra/.npmignore new file mode 100644 index 0000000000..c1d6d45dcf --- /dev/null +++ b/infra/.npmignore @@ -0,0 +1,6 @@ +*.ts +!*.d.ts + +# CDK asset staging directory +.cdk.staging +cdk.out diff --git a/infra/bin/infra.d.ts b/infra/bin/infra.d.ts new file mode 100644 index 0000000000..b7988016da --- /dev/null +++ b/infra/bin/infra.d.ts @@ -0,0 +1,2 @@ +#!/usr/bin/env node +export {}; diff --git a/infra/bin/infra.js b/infra/bin/infra.js new file mode 100644 index 0000000000..1519312a41 --- /dev/null +++ b/infra/bin/infra.js @@ -0,0 +1,52 @@ +#!/usr/bin/env node +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +const cdk = __importStar(require("aws-cdk-lib/core")); +const infra_stack_1 = require("../lib/infra-stack"); +const app = new cdk.App(); +new infra_stack_1.DeployWebAppStack(app, 'DeployWebAppStack', { +/* If you don't specify 'env', this stack will be environment-agnostic. + * Account/Region-dependent features and context lookups will not work, + * but a single synthesized template can be deployed anywhere. */ +/* Uncomment the next line to specialize this stack for the AWS Account + * and Region that are implied by the current CLI configuration. */ +// env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION }, +/* Uncomment the next line if you know exactly what Account and Region you + * want to deploy the stack to. */ +// env: { account: '123456789012', region: 'us-east-1' }, +/* For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html */ +}); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5mcmEuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmZyYS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFDQSxzREFBd0M7QUFDeEMsb0RBQXVEO0FBRXZELE1BQU0sR0FBRyxHQUFHLElBQUksR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDO0FBQzFCLElBQUksK0JBQWlCLENBQUMsR0FBRyxFQUFFLG1CQUFtQixFQUFFO0FBQzlDOztpRUFFaUU7QUFFakU7bUVBQ21FO0FBQ25FLDZGQUE2RjtBQUU3RjtrQ0FDa0M7QUFDbEMseURBQXlEO0FBRXpELDhGQUE4RjtDQUMvRixDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIjIS91c3IvYmluL2VudiBub2RlXG5pbXBvcnQgKiBhcyBjZGsgZnJvbSAnYXdzLWNkay1saWIvY29yZSc7XG5pbXBvcnQgeyBEZXBsb3lXZWJBcHBTdGFjayB9IGZyb20gJy4uL2xpYi9pbmZyYS1zdGFjayc7XG5cbmNvbnN0IGFwcCA9IG5ldyBjZGsuQXBwKCk7XG5uZXcgRGVwbG95V2ViQXBwU3RhY2soYXBwLCAnRGVwbG95V2ViQXBwU3RhY2snLCB7XG4gIC8qIElmIHlvdSBkb24ndCBzcGVjaWZ5ICdlbnYnLCB0aGlzIHN0YWNrIHdpbGwgYmUgZW52aXJvbm1lbnQtYWdub3N0aWMuXG4gICAqIEFjY291bnQvUmVnaW9uLWRlcGVuZGVudCBmZWF0dXJlcyBhbmQgY29udGV4dCBsb29rdXBzIHdpbGwgbm90IHdvcmssXG4gICAqIGJ1dCBhIHNpbmdsZSBzeW50aGVzaXplZCB0ZW1wbGF0ZSBjYW4gYmUgZGVwbG95ZWQgYW55d2hlcmUuICovXG5cbiAgLyogVW5jb21tZW50IHRoZSBuZXh0IGxpbmUgdG8gc3BlY2lhbGl6ZSB0aGlzIHN0YWNrIGZvciB0aGUgQVdTIEFjY291bnRcbiAgICogYW5kIFJlZ2lvbiB0aGF0IGFyZSBpbXBsaWVkIGJ5IHRoZSBjdXJyZW50IENMSSBjb25maWd1cmF0aW9uLiAqL1xuICAvLyBlbnY6IHsgYWNjb3VudDogcHJvY2Vzcy5lbnYuQ0RLX0RFRkFVTFRfQUNDT1VOVCwgcmVnaW9uOiBwcm9jZXNzLmVudi5DREtfREVGQVVMVF9SRUdJT04gfSxcblxuICAvKiBVbmNvbW1lbnQgdGhlIG5leHQgbGluZSBpZiB5b3Uga25vdyBleGFjdGx5IHdoYXQgQWNjb3VudCBhbmQgUmVnaW9uIHlvdVxuICAgKiB3YW50IHRvIGRlcGxveSB0aGUgc3RhY2sgdG8uICovXG4gIC8vIGVudjogeyBhY2NvdW50OiAnMTIzNDU2Nzg5MDEyJywgcmVnaW9uOiAndXMtZWFzdC0xJyB9LFxuXG4gIC8qIEZvciBtb3JlIGluZm9ybWF0aW9uLCBzZWUgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL2Nkay9sYXRlc3QvZ3VpZGUvZW52aXJvbm1lbnRzLmh0bWwgKi9cbn0pO1xuIl19 \ No newline at end of file diff --git a/infra/bin/infra.ts b/infra/bin/infra.ts new file mode 100644 index 0000000000..a65066943d --- /dev/null +++ b/infra/bin/infra.ts @@ -0,0 +1,20 @@ +#!/usr/bin/env node +import * as cdk from 'aws-cdk-lib/core'; +import { DeployWebAppStack } from '../lib/infra-stack'; + +const app = new cdk.App(); +new DeployWebAppStack(app, 'DeployWebAppStack', { + /* If you don't specify 'env', this stack will be environment-agnostic. + * Account/Region-dependent features and context lookups will not work, + * but a single synthesized template can be deployed anywhere. */ + + /* Uncomment the next line to specialize this stack for the AWS Account + * and Region that are implied by the current CLI configuration. */ + // env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION }, + + /* Uncomment the next line if you know exactly what Account and Region you + * want to deploy the stack to. */ + // env: { account: '123456789012', region: 'us-east-1' }, + + /* For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html */ +}); diff --git a/infra/cdk.json b/infra/cdk.json new file mode 100644 index 0000000000..023623338a --- /dev/null +++ b/infra/cdk.json @@ -0,0 +1,103 @@ +{ + "app": "npx ts-node --prefer-ts-exts bin/infra.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-signer:signingProfileNamePassedToCfn": true, + "@aws-cdk/aws-ecs-patterns:secGroupsDisablesImplicitOpenListener": true, + "@aws-cdk/aws-lambda:recognizeLayerVersion": true, + "@aws-cdk/core:checkSecretUsage": true, + "@aws-cdk/core:target-partitions": [ + "aws", + "aws-cn" + ], + "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, + "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, + "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, + "@aws-cdk/aws-iam:minimizePolicies": true, + "@aws-cdk/core:validateSnapshotRemovalPolicy": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, + "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, + "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, + "@aws-cdk/core:enablePartitionLiterals": true, + "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, + "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, + "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, + "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "@aws-cdk/customresources:installLatestAwsSdkDefault": false, + "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, + "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, + "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, + "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, + "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, + "@aws-cdk/aws-redshift:columnId": true, + "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, + "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, + "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, + "@aws-cdk/aws-kms:aliasNameRef": true, + "@aws-cdk/aws-kms:applyImportedAliasPermissionsToPrincipal": true, + "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true, + "@aws-cdk/core:includePrefixInUniqueNameGeneration": true, + "@aws-cdk/aws-efs:denyAnonymousAccess": true, + "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true, + "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true, + "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true, + "@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true, + "@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true, + "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true, + "@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true, + "@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true, + "@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true, + "@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true, + "@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true, + "@aws-cdk/aws-eks:nodegroupNameAttribute": true, + "@aws-cdk/aws-eks:useNativeOidcProvider": true, + "@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true, + "@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true, + "@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false, + "@aws-cdk/aws-s3:keepNotificationInImportedBucket": false, + "@aws-cdk/core:explicitStackTags": true, + "@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions": true, + "@aws-cdk/aws-dynamodb:resourcePolicyPerReplica": true, + "@aws-cdk/aws-ec2:ec2SumTImeoutEnabled": true, + "@aws-cdk/aws-appsync:appSyncGraphQLAPIScopeLambdaPermission": true, + "@aws-cdk/aws-rds:setCorrectValueForDatabaseInstanceReadReplicaInstanceResourceId": true, + "@aws-cdk/core:cfnIncludeRejectComplexResourceUpdateCreatePolicyIntrinsics": true, + "@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": true, + "@aws-cdk/aws-stepfunctions-tasks:fixRunEcsTaskPolicy": true, + "@aws-cdk/aws-ec2:bastionHostUseAmazonLinux2023ByDefault": true, + "@aws-cdk/aws-route53-targets:userPoolDomainNameMethodWithoutCustomResource": true, + "@aws-cdk/aws-elasticloadbalancingV2:albDualstackWithoutPublicIpv4SecurityGroupRulesDefault": true, + "@aws-cdk/aws-iam:oidcRejectUnauthorizedConnections": true, + "@aws-cdk/core:enableAdditionalMetadataCollection": true, + "@aws-cdk/aws-lambda:createNewPoliciesWithAddToRolePolicy": false, + "@aws-cdk/aws-s3:setUniqueReplicationRoleName": true, + "@aws-cdk/aws-events:requireEventBusPolicySid": true, + "@aws-cdk/core:aspectPrioritiesMutating": true, + "@aws-cdk/aws-dynamodb:retainTableReplica": true, + "@aws-cdk/aws-stepfunctions:useDistributedMapResultWriterV2": true, + "@aws-cdk/s3-notifications:addS3TrustKeyPolicyForSnsSubscriptions": true, + "@aws-cdk/aws-ec2:requirePrivateSubnetsForEgressOnlyInternetGateway": true, + "@aws-cdk/aws-s3:publicAccessBlockedByDefault": true, + "@aws-cdk/aws-lambda:useCdkManagedLogGroup": true, + "@aws-cdk/aws-elasticloadbalancingv2:networkLoadBalancerWithSecurityGroupByDefault": true, + "@aws-cdk/aws-ecs-patterns:uniqueTargetGroupId": true, + "@aws-cdk/aws-route53-patterns:useDistribution": true + } +} diff --git a/infra/lib/infra-stack.d.ts b/infra/lib/infra-stack.d.ts new file mode 100644 index 0000000000..1a29982b9a --- /dev/null +++ b/infra/lib/infra-stack.d.ts @@ -0,0 +1,8 @@ +import { Stack, type StackProps } from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +export declare class DeployWebAppStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps); +} +export declare class DeployMentService extends Construct { + constructor(scope: Construct, id: string); +} diff --git a/infra/lib/infra-stack.js b/infra/lib/infra-stack.js new file mode 100644 index 0000000000..81101034ab --- /dev/null +++ b/infra/lib/infra-stack.js @@ -0,0 +1,100 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +exports.DeployMentService = exports.DeployWebAppStack = void 0; +const aws_cdk_lib_1 = require("aws-cdk-lib"); +const constructs_1 = require("constructs"); +// import * as sqs from 'aws-cdk-lib/aws-sqs'; +const path = __importStar(require("path")); +const relativePath = "../../dist"; +class DeployWebAppStack extends aws_cdk_lib_1.Stack { + constructor(scope, id, props) { + super(scope, id, props); + // The code that defines your stack goes here + // example resource + // const queue = new sqs.Queue(this, 'InfraQueue', { + // visibilityTimeout: cdk.Duration.seconds(300) + // }); + new DeployMentService(this, 'deployment'); + } +} +exports.DeployWebAppStack = DeployWebAppStack; +class DeployMentService extends constructs_1.Construct { + constructor(scope, id) { + super(scope, id); + const hostingBucket = new aws_cdk_lib_1.aws_s3.Bucket(this, "FrontEndBucketPeer", { + blockPublicAccess: aws_cdk_lib_1.aws_s3.BlockPublicAccess.BLOCK_ALL, + removalPolicy: aws_cdk_lib_1.RemovalPolicy.DESTROY + }); + const originAccessIdentity = new aws_cdk_lib_1.aws_cloudfront.OriginAccessIdentity(this, 'OriginAccessIdentityPeer', { + comment: 'Allow CloudFront to access the frontend bucket' + }); + hostingBucket.grantRead(originAccessIdentity); + const distribution = new aws_cdk_lib_1.aws_cloudfront.Distribution(this, "CloudfrontDistributionPeer", { + defaultBehavior: { + origin: new aws_cdk_lib_1.aws_cloudfront_origins.S3Origin(hostingBucket, { + originAccessIdentity, + }), + viewerProtocolPolicy: aws_cdk_lib_1.aws_cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS + }, + defaultRootObject: "index.html", + errorResponses: [ + { + httpStatus: 404, + responseHttpStatus: 200, + responsePagePath: "/index.html" + } + ] + }); + new aws_cdk_lib_1.aws_s3_deployment.BucketDeployment(this, "BucketDeploymentPeer", { + sources: [aws_cdk_lib_1.aws_s3_deployment.Source.asset(path.join(__dirname, relativePath))], + destinationBucket: hostingBucket, + distribution, + distributionPaths: ["/*"] + }); + new aws_cdk_lib_1.CfnOutput(this, "CloudFrontURLPeer", { + value: distribution.domainName, + description: "The distribution URL", + exportName: "CloudfrontURLPeer" + }); + new aws_cdk_lib_1.CfnOutput(this, "BucketNamePeer", { + value: hostingBucket.bucketName, + description: "The name of the s3 bucket", + exportName: "BucketNamePeer" + }); + } +} +exports.DeployMentService = DeployMentService; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5mcmEtc3RhY2suanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmZyYS1zdGFjay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSw2Q0FBK0k7QUFDL0ksMkNBQXVDO0FBQ3ZDLDhDQUE4QztBQUM5QywyQ0FBNkI7QUFDN0IsTUFBTSxZQUFZLEdBQUcsWUFBWSxDQUFBO0FBRWpDLE1BQWEsaUJBQWtCLFNBQVEsbUJBQUs7SUFDMUMsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUFrQjtRQUMxRCxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUV4Qiw2Q0FBNkM7UUFFN0MsbUJBQW1CO1FBQ25CLG9EQUFvRDtRQUNwRCxpREFBaUQ7UUFDakQsTUFBTTtRQUVOLElBQUksaUJBQWlCLENBQUMsSUFBSSxFQUFFLFlBQVksQ0FBQyxDQUFDO0lBQzVDLENBQUM7Q0FFRjtBQWRELDhDQWNDO0FBRUQsTUFBYSxpQkFBa0IsU0FBUSxzQkFBUztJQUM5QyxZQUFZLEtBQWdCLEVBQUUsRUFBVTtRQUN0QyxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRWpCLE1BQU0sYUFBYSxHQUFHLElBQUksb0JBQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLG9CQUFvQixFQUFFO1lBQ2xFLGlCQUFpQixFQUFFLG9CQUFNLENBQUMsaUJBQWlCLENBQUMsU0FBUztZQUNyRCxhQUFhLEVBQUUsMkJBQWEsQ0FBQyxPQUFPO1NBQ3JDLENBQUMsQ0FBQztRQUVILE1BQU0sb0JBQW9CLEdBQUcsSUFBSSw0QkFBYyxDQUFDLG9CQUFvQixDQUFDLElBQUksRUFBRSwwQkFBMEIsRUFBRTtZQUNyRyxPQUFPLEVBQUUsZ0RBQWdEO1NBQzFELENBQUMsQ0FBQztRQUVILGFBQWEsQ0FBQyxTQUFTLENBQUMsb0JBQW9CLENBQUMsQ0FBQztRQUU5QyxNQUFNLFlBQVksR0FBRyxJQUFJLDRCQUFjLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSw0QkFBNEIsRUFBRTtZQUN2RixlQUFlLEVBQUM7Z0JBQ2QsTUFBTSxFQUFFLElBQUksb0NBQXNCLENBQUMsUUFBUSxDQUFDLGFBQWEsRUFBRTtvQkFDekQsb0JBQW9CO2lCQUNyQixDQUFDO2dCQUNGLG9CQUFvQixFQUFFLDRCQUFjLENBQUMsb0JBQW9CLENBQUMsaUJBQWlCO2FBQzVFO1lBQ0QsaUJBQWlCLEVBQUUsWUFBWTtZQUMvQixjQUFjLEVBQUM7Z0JBQ2I7b0JBQ0UsVUFBVSxFQUFDLEdBQUc7b0JBQ2Qsa0JBQWtCLEVBQUMsR0FBRztvQkFDdEIsZ0JBQWdCLEVBQUMsYUFBYTtpQkFDL0I7YUFDRjtTQUNGLENBQUMsQ0FBQztRQUVILElBQUksK0JBQWlCLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxFQUFFLHNCQUFzQixFQUFFO1lBQ25FLE9BQU8sRUFBQyxDQUFDLCtCQUFpQixDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsWUFBWSxDQUFDLENBQUMsQ0FBQztZQUM1RSxpQkFBaUIsRUFBQyxhQUFhO1lBQy9CLFlBQVk7WUFDWixpQkFBaUIsRUFBQyxDQUFDLElBQUksQ0FBQztTQUN6QixDQUFDLENBQUM7UUFFSCxJQUFJLHVCQUFTLENBQUMsSUFBSSxFQUFFLG1CQUFtQixFQUFFO1lBQ3ZDLEtBQUssRUFBQyxZQUFZLENBQUMsVUFBVTtZQUM3QixXQUFXLEVBQUMsc0JBQXNCO1lBQ2xDLFVBQVUsRUFBQyxtQkFBbUI7U0FDL0IsQ0FBQyxDQUFDO1FBRUgsSUFBSSx1QkFBUyxDQUFDLElBQUksRUFBRSxnQkFBZ0IsRUFBRTtZQUNwQyxLQUFLLEVBQUMsYUFBYSxDQUFDLFVBQVU7WUFDOUIsV0FBVyxFQUFDLDJCQUEyQjtZQUN2QyxVQUFVLEVBQUMsZ0JBQWdCO1NBQzVCLENBQUMsQ0FBQztJQUNMLENBQUM7Q0FDRjtBQW5ERCw4Q0FtREMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge2F3c19jbG91ZGZyb250LCBTdGFjayx0eXBlIFN0YWNrUHJvcHMsIGF3c19jbG91ZGZyb250X29yaWdpbnMsIGF3c19zMywgYXdzX3MzX2RlcGxveW1lbnQsIENmbk91dHB1dCwgUmVtb3ZhbFBvbGljeX0gZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG4vLyBpbXBvcnQgKiBhcyBzcXMgZnJvbSAnYXdzLWNkay1saWIvYXdzLXNxcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gXCJwYXRoXCI7XG5jb25zdCByZWxhdGl2ZVBhdGggPSBcIi4uLy4uL2Rpc3RcIlxuXG5leHBvcnQgY2xhc3MgRGVwbG95V2ViQXBwU3RhY2sgZXh0ZW5kcyBTdGFjayB7XG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzPzogU3RhY2tQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCwgcHJvcHMpO1xuXG4gICAgLy8gVGhlIGNvZGUgdGhhdCBkZWZpbmVzIHlvdXIgc3RhY2sgZ29lcyBoZXJlXG5cbiAgICAvLyBleGFtcGxlIHJlc291cmNlXG4gICAgLy8gY29uc3QgcXVldWUgPSBuZXcgc3FzLlF1ZXVlKHRoaXMsICdJbmZyYVF1ZXVlJywge1xuICAgIC8vICAgdmlzaWJpbGl0eVRpbWVvdXQ6IGNkay5EdXJhdGlvbi5zZWNvbmRzKDMwMClcbiAgICAvLyB9KTtcblxuICAgIG5ldyBEZXBsb3lNZW50U2VydmljZSh0aGlzLCAnZGVwbG95bWVudCcpO1xuICB9XG4gIFxufVxuXG5leHBvcnQgY2xhc3MgRGVwbG95TWVudFNlcnZpY2UgZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgIGNvbnN0IGhvc3RpbmdCdWNrZXQgPSBuZXcgYXdzX3MzLkJ1Y2tldCh0aGlzLCBcIkZyb250RW5kQnVja2V0UGVlclwiLCB7XG4gICAgICBibG9ja1B1YmxpY0FjY2VzczogYXdzX3MzLkJsb2NrUHVibGljQWNjZXNzLkJMT0NLX0FMTCxcbiAgICAgIHJlbW92YWxQb2xpY3k6IFJlbW92YWxQb2xpY3kuREVTVFJPWVxuICAgIH0pO1xuXG4gICAgY29uc3Qgb3JpZ2luQWNjZXNzSWRlbnRpdHkgPSBuZXcgYXdzX2Nsb3VkZnJvbnQuT3JpZ2luQWNjZXNzSWRlbnRpdHkodGhpcywgJ09yaWdpbkFjY2Vzc0lkZW50aXR5UGVlcicsIHtcbiAgICAgIGNvbW1lbnQ6ICdBbGxvdyBDbG91ZEZyb250IHRvIGFjY2VzcyB0aGUgZnJvbnRlbmQgYnVja2V0J1xuICAgIH0pO1xuXG4gICAgaG9zdGluZ0J1Y2tldC5ncmFudFJlYWQob3JpZ2luQWNjZXNzSWRlbnRpdHkpO1xuXG4gICAgY29uc3QgZGlzdHJpYnV0aW9uID0gbmV3IGF3c19jbG91ZGZyb250LkRpc3RyaWJ1dGlvbih0aGlzLCBcIkNsb3VkZnJvbnREaXN0cmlidXRpb25QZWVyXCIsIHtcbiAgICAgIGRlZmF1bHRCZWhhdmlvcjp7XG4gICAgICAgIG9yaWdpbjogbmV3IGF3c19jbG91ZGZyb250X29yaWdpbnMuUzNPcmlnaW4oaG9zdGluZ0J1Y2tldCwge1xuICAgICAgICAgIG9yaWdpbkFjY2Vzc0lkZW50aXR5LFxuICAgICAgICB9KSxcbiAgICAgICAgdmlld2VyUHJvdG9jb2xQb2xpY3k6IGF3c19jbG91ZGZyb250LlZpZXdlclByb3RvY29sUG9saWN5LlJFRElSRUNUX1RPX0hUVFBTXG4gICAgICB9LFxuICAgICAgZGVmYXVsdFJvb3RPYmplY3Q6IFwiaW5kZXguaHRtbFwiLFxuICAgICAgZXJyb3JSZXNwb25zZXM6W1xuICAgICAgICB7XG4gICAgICAgICAgaHR0cFN0YXR1czo0MDQsXG4gICAgICAgICAgcmVzcG9uc2VIdHRwU3RhdHVzOjIwMCxcbiAgICAgICAgICByZXNwb25zZVBhZ2VQYXRoOlwiL2luZGV4Lmh0bWxcIlxuICAgICAgICB9XG4gICAgICBdXG4gICAgfSk7XG5cbiAgICBuZXcgYXdzX3MzX2RlcGxveW1lbnQuQnVja2V0RGVwbG95bWVudCh0aGlzLCBcIkJ1Y2tldERlcGxveW1lbnRQZWVyXCIsIHtcbiAgICAgIHNvdXJjZXM6W2F3c19zM19kZXBsb3ltZW50LlNvdXJjZS5hc3NldChwYXRoLmpvaW4oX19kaXJuYW1lLCByZWxhdGl2ZVBhdGgpKV0sXG4gICAgICBkZXN0aW5hdGlvbkJ1Y2tldDpob3N0aW5nQnVja2V0LFxuICAgICAgZGlzdHJpYnV0aW9uLFxuICAgICAgZGlzdHJpYnV0aW9uUGF0aHM6W1wiLypcIl1cbiAgICB9KTtcblxuICAgIG5ldyBDZm5PdXRwdXQodGhpcywgXCJDbG91ZEZyb250VVJMUGVlclwiLCB7XG4gICAgICB2YWx1ZTpkaXN0cmlidXRpb24uZG9tYWluTmFtZSxcbiAgICAgIGRlc2NyaXB0aW9uOlwiVGhlIGRpc3RyaWJ1dGlvbiBVUkxcIixcbiAgICAgIGV4cG9ydE5hbWU6XCJDbG91ZGZyb250VVJMUGVlclwiXG4gICAgfSk7XG5cbiAgICBuZXcgQ2ZuT3V0cHV0KHRoaXMsIFwiQnVja2V0TmFtZVBlZXJcIiwge1xuICAgICAgdmFsdWU6aG9zdGluZ0J1Y2tldC5idWNrZXROYW1lLFxuICAgICAgZGVzY3JpcHRpb246XCJUaGUgbmFtZSBvZiB0aGUgczMgYnVja2V0XCIsXG4gICAgICBleHBvcnROYW1lOlwiQnVja2V0TmFtZVBlZXJcIlxuICAgIH0pO1xuICB9XG59XG4iXX0= \ No newline at end of file diff --git a/infra/lib/infra-stack.ts b/infra/lib/infra-stack.ts new file mode 100644 index 0000000000..78a5be67fb --- /dev/null +++ b/infra/lib/infra-stack.ts @@ -0,0 +1,77 @@ +import {aws_cloudfront, Stack,type StackProps, aws_cloudfront_origins, aws_s3, aws_s3_deployment, CfnOutput, RemovalPolicy} from 'aws-cdk-lib'; +import { aws_lambda, Duration } from 'aws-cdk-lib'; +import { aws_apigateway } from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +// import * as sqs from 'aws-cdk-lib/aws-sqs'; +import * as path from "path"; +const relativePathFrontend = "../../dist" + +export class DeployWebAppStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + + // The code that defines your stack goes here + + // example resource + // const queue = new sqs.Queue(this, 'InfraQueue', { + // visibilityTimeout: cdk.Duration.seconds(300) + // }); + + new DeployMentService(this, 'deployment'); + } + +} + +export class DeployMentService extends Construct { + constructor(scope: Construct, id: string) { + super(scope, id); + + const hostingBucket = new aws_s3.Bucket(this, "FrontEndBucketPeer", { + blockPublicAccess: aws_s3.BlockPublicAccess.BLOCK_ALL, + removalPolicy: RemovalPolicy.DESTROY + }); + + const originAccessIdentity = new aws_cloudfront.OriginAccessIdentity(this, 'OriginAccessIdentityPeer', { + comment: 'Allow CloudFront to access the frontend bucket' + }); + + hostingBucket.grantRead(originAccessIdentity); + + const distribution = new aws_cloudfront.Distribution(this, "CloudfrontDistributionPeer", { + defaultBehavior:{ + origin: new aws_cloudfront_origins.S3Origin(hostingBucket, { + originAccessIdentity, + }), + viewerProtocolPolicy: aws_cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS + }, + defaultRootObject: "index.html", + errorResponses:[ + { + httpStatus:404, + responseHttpStatus:200, + responsePagePath:"/index.html" + } + ] + }); + + new aws_s3_deployment.BucketDeployment(this, "BucketDeploymentPeer", { + sources:[aws_s3_deployment.Source.asset(path.join(__dirname, relativePathFrontend))], + destinationBucket:hostingBucket, + distribution, + distributionPaths:["/*"] + }); + + new CfnOutput(this, "CloudFrontURLPeer", { + value:distribution.domainName, + description:"The distribution URL", + exportName:"CloudfrontURLPeer" + }); + + new CfnOutput(this, "BucketNamePeer", { + value:hostingBucket.bucketName, + description:"The name of the s3 bucket", + exportName:"BucketNamePeer" + }); + } +} +