From 454c8f6cc35ec3d0ed436f8beaec7bf697354005 Mon Sep 17 00:00:00 2001 From: Pete Dunlap Date: Mon, 9 Dec 2024 11:27:44 -0500 Subject: [PATCH 1/9] CMDCT-4184 removing some things to prep for import --- deployment/stacks/parent.ts | 114 ++++++++++++------------ deployment/stacks/ui.ts | 172 +++++++++++++++++++++--------------- src/run.ts | 4 +- 3 files changed, 163 insertions(+), 127 deletions(-) diff --git a/deployment/stacks/parent.ts b/deployment/stacks/parent.ts index 3cdfd11e8..52dae60f5 100644 --- a/deployment/stacks/parent.ts +++ b/deployment/stacks/parent.ts @@ -2,19 +2,19 @@ import { Construct } from "constructs"; import { aws_ec2 as ec2, aws_iam as iam, - aws_ssm as ssm, - CfnOutput, + // aws_ssm as ssm, + // CfnOutput, Stack, StackProps, } from "aws-cdk-lib"; import { CloudWatchLogsResourcePolicy } from "../constructs/cloudwatch-logs-resource-policy"; import { DeploymentConfigProperties } from "../deployment-config"; import { createDataComponents } from "./data"; -import { createUiAuthComponents } from "./ui-auth"; +// import { createUiAuthComponents } from "./ui-auth"; import { createUiComponents } from "./ui"; import { createApiComponents } from "./api"; import { sortSubnets } from "../utils/vpc"; -import { deployFrontend } from "./deployFrontend"; +// import { deployFrontend } from "./deployFrontend"; import { createCustomResourceRole } from "./customResourceRole"; export class ParentStack extends Stack { @@ -30,8 +30,8 @@ export class ParentStack extends Stack { project, isDev, vpcName, - bootstrapUsersPasswordArn, - oktaMetadataUrl, + // bootstrapUsersPasswordArn, + // oktaMetadataUrl, brokerString, iamPermissionsBoundaryArn, iamPath, @@ -65,7 +65,8 @@ export class ParentStack extends Stack { customResourceRole, }); - const { apiGatewayRestApiUrl, restApiId } = createApiComponents({ + // const { apiGatewayRestApiUrl, restApiId } = + createApiComponents({ ...commonProps, vpc, privateSubnets, @@ -73,61 +74,62 @@ export class ParentStack extends Stack { brokerString, }); - const { - applicationEndpointUrl, - cloudfrontDistributionId, - distribution, - s3BucketName, - uiBucket, - } = createUiComponents({ + // const { + // // applicationEndpointUrl, + // // cloudfrontDistributionId, + // distribution, + // s3BucketName, + // uiBucket, + // } = + createUiComponents({ deploymentConfigParameters, ...commonProps, }); - const { - userPoolDomainName, - identityPoolId, - userPoolId, - userPoolClientId, - } = createUiAuthComponents({ - ...commonProps, - oktaMetadataUrl, - applicationEndpointUrl, - restApiId, - bootstrapUsersPasswordArn, - customResourceRole, - }); + // const { + // userPoolDomainName, + // identityPoolId, + // userPoolId, + // userPoolClientId, + // } = createUiAuthComponents({ + // ...commonProps, + // oktaMetadataUrl, + // applicationEndpointUrl, + // restApiId, + // bootstrapUsersPasswordArn, + // customResourceRole, + // }); - deployFrontend({ - ...commonProps, - uiBucket, - distribution, - apiGatewayRestApiUrl, - applicationEndpointUrl, - identityPoolId, - userPoolId, - userPoolClientId, - userPoolClientDomain: `${userPoolDomainName}.auth.${this.region}.amazoncognito.com`, - customResourceRole, - }); + // deployFrontend({ + // ...commonProps, + // uiBucket, + // distribution, + // apiGatewayRestApiUrl, + // applicationEndpointUrl, + // identityPoolId, + // userPoolId, + // userPoolClientId, + // userPoolClientDomain: `${userPoolDomainName}.auth.${this.region}.amazoncognito.com`, + // customResourceRole, + // }); - new ssm.StringParameter(this, "DeploymentOutput", { - parameterName: `/${project}/${stage}/deployment-output`, - stringValue: JSON.stringify({ - apiGatewayRestApiUrl, - applicationEndpointUrl, - s3BucketName, - cloudfrontDistributionId, - identityPoolId, - userPoolId, - userPoolClientId, - userPoolClientDomain: `${userPoolDomainName}.auth.${this.region}.amazoncognito.com`, - }), - description: `Deployment output for the ${stage} environment.`, - }); + // new ssm.StringParameter(this, "DeploymentOutput", { + // parameterName: `/${project}/${stage}/deployment-output`, + // stringValue: JSON.stringify({ + // apiGatewayRestApiUrl, + // applicationEndpointUrl, + // s3BucketName, + // cloudfrontDistributionId, + // identityPoolId, + // userPoolId, + // userPoolClientId, + // userPoolClientDomain: `${userPoolDomainName}.auth.${this.region}.amazoncognito.com`, + // }), + // description: `Deployment output for the ${stage} environment.`, + // }); - new CfnOutput(this, "CloudFrontUrl", { - value: applicationEndpointUrl, - }); + // new CfnOutput(this, "CloudFrontUrl", { + // value: applicationEndpointUrl, + // }); } } diff --git a/deployment/stacks/ui.ts b/deployment/stacks/ui.ts index eddfdf6d7..96531f9c2 100644 --- a/deployment/stacks/ui.ts +++ b/deployment/stacks/ui.ts @@ -1,17 +1,15 @@ import { Construct } from "constructs"; import { aws_cloudfront as cloudfront, - aws_cloudfront_origins as cloudfrontOrigins, + // aws_cloudfront_origins as cloudfrontOrigins, aws_iam as iam, aws_kinesisfirehose as firehose, - aws_route53 as route53, - aws_route53_targets as route53Targets, aws_s3 as s3, aws_wafv2 as wafv2, Aws, Duration, RemovalPolicy, - aws_certificatemanager as acm, + // aws_certificatemanager as acm, } from "aws-cdk-lib"; import { addIamPropertiesToBucketAutoDeleteRole } from "../utils/s3"; import { IManagedPolicy } from "aws-cdk-lib/aws-iam"; @@ -66,7 +64,8 @@ export function createUiComponents(props: CreateUiComponentsProps) { }) ); - const securityHeadersPolicy = new cloudfront.ResponseHeadersPolicy( + // const securityHeadersPolicy = new cloudfront.ResponseHeadersPolicy( + new cloudfront.ResponseHeadersPolicy( scope, "CloudFormationHeadersPolicy", { @@ -95,48 +94,104 @@ export function createUiComponents(props: CreateUiComponentsProps) { } ); - const distribution = new cloudfront.Distribution( - scope, - "CloudFrontDistribution", - { - certificate: deploymentConfigParameters.cloudfrontCertificateArn - ? acm.Certificate.fromCertificateArn( - scope, - "certArn", - deploymentConfigParameters.cloudfrontCertificateArn - ) - : undefined, - domainNames: deploymentConfigParameters.cloudfrontDomainName - ? [deploymentConfigParameters.cloudfrontDomainName] - : [], - defaultBehavior: { - origin: cloudfrontOrigins.S3BucketOrigin.withOriginAccessControl( - uiBucket - ), - allowedMethods: cloudfront.AllowedMethods.ALLOW_GET_HEAD, - viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, - cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED, - compress: true, - responseHeadersPolicy: securityHeadersPolicy, - }, - defaultRootObject: "index.html", - enableLogging: true, - logBucket: loggingBucket, - httpVersion: cloudfront.HttpVersion.HTTP2, - errorResponses: [ - { - httpStatus: 403, - responseHttpStatus: 200, - responsePagePath: "/index.html", - }, - ], - } - ); + // HERE + // new cloudfront.Distribution(scope, 'myCdn', { + // defaultBehavior: { + // origin: new cloudfrontOrigins.HttpOrigin('www.example.com'), + // }, + // }); + + // const dummyBucket = new s3.Bucket(scope, "DummyBucket", { + // encryption: s3.BucketEncryption.S3_MANAGED, + // // removalPolicy: RemovalPolicy.DESTROY, + // // autoDeleteObjects: true, + // // enforceSSL: true, + // }); + + // # CloudFrontOriginAccessIdentity: + // # Type: AWS::CloudFront::CloudFrontOriginAccessIdentity + // # DeletionPolicy: Retain + // # Properties: + // # CloudFrontOriginAccessIdentityConfig: + // # Comment: OAI to prevent direct public access to the bucket + + // const CloudFrontOriginAccessIdentity = + // new cloudfront.CfnCloudFrontOriginAccessIdentity( + // scope, 'CloudFrontOriginAccessIdentity', { + // cloudFrontOriginAccessIdentityConfig: { + // comment: 'OAI to prevent direct public access to the bucket', + // }, + // }); + + // new cloudfront.Distribution(scope, "HelloWorldDistribution", { + // defaultBehavior: { + // origin: new cloudfrontOrigins.HttpOrigin("example.com"), + // functionAssociations: [ + // { + // function: new cloudfront.Function(scope, "HelloWorldFunction", { + // code: cloudfront.FunctionCode.fromInline(` + // function handler(event) { + // var response = { + // statusCode: 200, + // statusDescription: 'OK', + // headers: { + // 'content-type': { value: 'text/html; charset=utf-8' }, + // }, + // body: '

Hello World

', + // }; + // return response; + // } + // `), + // }), + // eventType: cloudfront.FunctionEventType.VIEWER_REQUEST, + // }, + // ], + // viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, + // }, + // }); - const applicationEndpointUrl = `https://${distribution.distributionDomainName}/`; + // const distribution = new cloudfront.Distribution( + // scope, + // "CloudFrontDistribution", + // { + // // certificate: deploymentConfigParameters.cloudfrontCertificateArn + // // ? acm.Certificate.fromCertificateArn( + // // scope, + // // "certArn", + // // deploymentConfigParameters.cloudfrontCertificateArn + // // ) + // // : undefined, + // // domainNames: deploymentConfigParameters.cloudfrontDomainName + // // ? [deploymentConfigParameters.cloudfrontDomainName] + // // : [], + // domainNames: ['ui-cmdct-4184-sls-dummybucket-zss2xed1ezsv.s3-website-us-east-1.amazonaws.com'], + // defaultBehavior: { + // origin: cloudfrontOrigins.S3BucketOrigin.withOriginAccessControl( + // dummyBucket + // ), + // // allowedMethods: cloudfront.AllowedMethods.ALLOW_GET_HEAD, + // // viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, + // // cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED, + // // compress: true, + // // responseHeadersPolicy: securityHeadersPolicy, + // }, + // defaultRootObject: "index.html", + // // enableLogging: true, + // // logBucket: loggingBucket, + // httpVersion: cloudfront.HttpVersion.HTTP2, + // // errorResponses: [ + // // { + // // httpStatus: 403, + // // responseHttpStatus: 200, + // // responsePagePath: "/index.html", + // // }, + // // ], + // } + // ); + + // const applicationEndpointUrl = `https://${distribution.distributionDomainName}/`; setupWaf(scope, stage, project, deploymentConfigParameters); - setupRoute53(scope, distribution, deploymentConfigParameters); createFirehoseLogging( scope, @@ -154,9 +209,9 @@ export function createUiComponents(props: CreateUiComponentsProps) { ); return { - cloudfrontDistributionId: distribution.distributionId, - distribution, - applicationEndpointUrl, + // cloudfrontDistributionId: distribution.distributionId, + // distribution, + // applicationEndpointUrl, s3BucketName: uiBucket.bucketName, uiBucket, }; @@ -229,29 +284,6 @@ function setupWaf( }); } -function setupRoute53( - scope: Construct, - distribution: cloudfront.Distribution, - deploymentConfigParameters: { [name: string]: string | undefined } -) { - if ( - deploymentConfigParameters.hostedZoneId && - deploymentConfigParameters.domainName - ) { - const zone = route53.HostedZone.fromHostedZoneAttributes(scope, "Zone", { - hostedZoneId: deploymentConfigParameters.hostedZoneId, - zoneName: deploymentConfigParameters.domainName, - }); - - new route53.ARecord(scope, "AliasRecord", { - zone, - target: route53.RecordTarget.fromAlias( - new route53Targets.CloudFrontTarget(distribution) - ), - }); - } -} - function createFirehoseLogging( scope: Construct, stage: string, diff --git a/src/run.ts b/src/run.ts index 18f1ca7bc..365c134c3 100644 --- a/src/run.ts +++ b/src/run.ts @@ -47,7 +47,7 @@ async function confirmDestroyCommand(stack: string) { const confirmation = await question(` ${orange}********************************* STOP ******************************* -You've requested a destroy for: +You've requested a destroy for: ${stack} @@ -209,6 +209,8 @@ async function deploy(options: { stage: string }) { const stage = options.stage; const runner = new LabeledProcessRunner(); await prepare_services(runner); + // const importCmd = ["cdk", "import", "--context", `stage=${stage}`]; //#--force + // await runner.run_command_and_output("CDK import", importCmd, "."); const deployCmd = ["cdk", "deploy", "--context", `stage=${stage}`, "--all"]; await runner.run_command_and_output("CDK deploy", deployCmd, "."); } From 17176722f42c1e4fe67769901e1925159532f498 Mon Sep 17 00:00:00 2001 From: Pete Dunlap Date: Mon, 9 Dec 2024 14:28:37 -0500 Subject: [PATCH 2/9] CMDCT-4184 - end state for cloudfront distribution --- deployment/stacks/parent.ts | 114 ++++++++++++++------------- deployment/stacks/ui.ts | 148 ++++++++++++------------------------ 2 files changed, 106 insertions(+), 156 deletions(-) diff --git a/deployment/stacks/parent.ts b/deployment/stacks/parent.ts index 52dae60f5..3cdfd11e8 100644 --- a/deployment/stacks/parent.ts +++ b/deployment/stacks/parent.ts @@ -2,19 +2,19 @@ import { Construct } from "constructs"; import { aws_ec2 as ec2, aws_iam as iam, - // aws_ssm as ssm, - // CfnOutput, + aws_ssm as ssm, + CfnOutput, Stack, StackProps, } from "aws-cdk-lib"; import { CloudWatchLogsResourcePolicy } from "../constructs/cloudwatch-logs-resource-policy"; import { DeploymentConfigProperties } from "../deployment-config"; import { createDataComponents } from "./data"; -// import { createUiAuthComponents } from "./ui-auth"; +import { createUiAuthComponents } from "./ui-auth"; import { createUiComponents } from "./ui"; import { createApiComponents } from "./api"; import { sortSubnets } from "../utils/vpc"; -// import { deployFrontend } from "./deployFrontend"; +import { deployFrontend } from "./deployFrontend"; import { createCustomResourceRole } from "./customResourceRole"; export class ParentStack extends Stack { @@ -30,8 +30,8 @@ export class ParentStack extends Stack { project, isDev, vpcName, - // bootstrapUsersPasswordArn, - // oktaMetadataUrl, + bootstrapUsersPasswordArn, + oktaMetadataUrl, brokerString, iamPermissionsBoundaryArn, iamPath, @@ -65,8 +65,7 @@ export class ParentStack extends Stack { customResourceRole, }); - // const { apiGatewayRestApiUrl, restApiId } = - createApiComponents({ + const { apiGatewayRestApiUrl, restApiId } = createApiComponents({ ...commonProps, vpc, privateSubnets, @@ -74,62 +73,61 @@ export class ParentStack extends Stack { brokerString, }); - // const { - // // applicationEndpointUrl, - // // cloudfrontDistributionId, - // distribution, - // s3BucketName, - // uiBucket, - // } = - createUiComponents({ + const { + applicationEndpointUrl, + cloudfrontDistributionId, + distribution, + s3BucketName, + uiBucket, + } = createUiComponents({ deploymentConfigParameters, ...commonProps, }); - // const { - // userPoolDomainName, - // identityPoolId, - // userPoolId, - // userPoolClientId, - // } = createUiAuthComponents({ - // ...commonProps, - // oktaMetadataUrl, - // applicationEndpointUrl, - // restApiId, - // bootstrapUsersPasswordArn, - // customResourceRole, - // }); + const { + userPoolDomainName, + identityPoolId, + userPoolId, + userPoolClientId, + } = createUiAuthComponents({ + ...commonProps, + oktaMetadataUrl, + applicationEndpointUrl, + restApiId, + bootstrapUsersPasswordArn, + customResourceRole, + }); - // deployFrontend({ - // ...commonProps, - // uiBucket, - // distribution, - // apiGatewayRestApiUrl, - // applicationEndpointUrl, - // identityPoolId, - // userPoolId, - // userPoolClientId, - // userPoolClientDomain: `${userPoolDomainName}.auth.${this.region}.amazoncognito.com`, - // customResourceRole, - // }); + deployFrontend({ + ...commonProps, + uiBucket, + distribution, + apiGatewayRestApiUrl, + applicationEndpointUrl, + identityPoolId, + userPoolId, + userPoolClientId, + userPoolClientDomain: `${userPoolDomainName}.auth.${this.region}.amazoncognito.com`, + customResourceRole, + }); - // new ssm.StringParameter(this, "DeploymentOutput", { - // parameterName: `/${project}/${stage}/deployment-output`, - // stringValue: JSON.stringify({ - // apiGatewayRestApiUrl, - // applicationEndpointUrl, - // s3BucketName, - // cloudfrontDistributionId, - // identityPoolId, - // userPoolId, - // userPoolClientId, - // userPoolClientDomain: `${userPoolDomainName}.auth.${this.region}.amazoncognito.com`, - // }), - // description: `Deployment output for the ${stage} environment.`, - // }); + new ssm.StringParameter(this, "DeploymentOutput", { + parameterName: `/${project}/${stage}/deployment-output`, + stringValue: JSON.stringify({ + apiGatewayRestApiUrl, + applicationEndpointUrl, + s3BucketName, + cloudfrontDistributionId, + identityPoolId, + userPoolId, + userPoolClientId, + userPoolClientDomain: `${userPoolDomainName}.auth.${this.region}.amazoncognito.com`, + }), + description: `Deployment output for the ${stage} environment.`, + }); - // new CfnOutput(this, "CloudFrontUrl", { - // value: applicationEndpointUrl, - // }); + new CfnOutput(this, "CloudFrontUrl", { + value: applicationEndpointUrl, + }); } } diff --git a/deployment/stacks/ui.ts b/deployment/stacks/ui.ts index 96531f9c2..61ea71def 100644 --- a/deployment/stacks/ui.ts +++ b/deployment/stacks/ui.ts @@ -1,7 +1,7 @@ import { Construct } from "constructs"; import { aws_cloudfront as cloudfront, - // aws_cloudfront_origins as cloudfrontOrigins, + aws_cloudfront_origins as cloudfrontOrigins, aws_iam as iam, aws_kinesisfirehose as firehose, aws_s3 as s3, @@ -9,7 +9,7 @@ import { Aws, Duration, RemovalPolicy, - // aws_certificatemanager as acm, + aws_certificatemanager as acm, } from "aws-cdk-lib"; import { addIamPropertiesToBucketAutoDeleteRole } from "../utils/s3"; import { IManagedPolicy } from "aws-cdk-lib/aws-iam"; @@ -64,8 +64,7 @@ export function createUiComponents(props: CreateUiComponentsProps) { }) ); - // const securityHeadersPolicy = new cloudfront.ResponseHeadersPolicy( - new cloudfront.ResponseHeadersPolicy( + const securityHeadersPolicy = new cloudfront.ResponseHeadersPolicy( scope, "CloudFormationHeadersPolicy", { @@ -94,102 +93,55 @@ export function createUiComponents(props: CreateUiComponentsProps) { } ); - // HERE - // new cloudfront.Distribution(scope, 'myCdn', { + // new cloudfront.Distribution(scope, 'CloudFrontDistribution', { // defaultBehavior: { - // origin: new cloudfrontOrigins.HttpOrigin('www.example.com'), + // origin: new cloudfrontOrigins.HttpOrigin( + // 'www.example.com', + // { originId: 'Default'} + // ), + // cachePolicy: cloudfront.CachePolicy.CACHING_DISABLED, // }, // }); - // const dummyBucket = new s3.Bucket(scope, "DummyBucket", { - // encryption: s3.BucketEncryption.S3_MANAGED, - // // removalPolicy: RemovalPolicy.DESTROY, - // // autoDeleteObjects: true, - // // enforceSSL: true, - // }); - - // # CloudFrontOriginAccessIdentity: - // # Type: AWS::CloudFront::CloudFrontOriginAccessIdentity - // # DeletionPolicy: Retain - // # Properties: - // # CloudFrontOriginAccessIdentityConfig: - // # Comment: OAI to prevent direct public access to the bucket - - // const CloudFrontOriginAccessIdentity = - // new cloudfront.CfnCloudFrontOriginAccessIdentity( - // scope, 'CloudFrontOriginAccessIdentity', { - // cloudFrontOriginAccessIdentityConfig: { - // comment: 'OAI to prevent direct public access to the bucket', - // }, - // }); - - // new cloudfront.Distribution(scope, "HelloWorldDistribution", { - // defaultBehavior: { - // origin: new cloudfrontOrigins.HttpOrigin("example.com"), - // functionAssociations: [ - // { - // function: new cloudfront.Function(scope, "HelloWorldFunction", { - // code: cloudfront.FunctionCode.fromInline(` - // function handler(event) { - // var response = { - // statusCode: 200, - // statusDescription: 'OK', - // headers: { - // 'content-type': { value: 'text/html; charset=utf-8' }, - // }, - // body: '

Hello World

', - // }; - // return response; - // } - // `), - // }), - // eventType: cloudfront.FunctionEventType.VIEWER_REQUEST, - // }, - // ], - // viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, - // }, - // }); - - // const distribution = new cloudfront.Distribution( - // scope, - // "CloudFrontDistribution", - // { - // // certificate: deploymentConfigParameters.cloudfrontCertificateArn - // // ? acm.Certificate.fromCertificateArn( - // // scope, - // // "certArn", - // // deploymentConfigParameters.cloudfrontCertificateArn - // // ) - // // : undefined, - // // domainNames: deploymentConfigParameters.cloudfrontDomainName - // // ? [deploymentConfigParameters.cloudfrontDomainName] - // // : [], - // domainNames: ['ui-cmdct-4184-sls-dummybucket-zss2xed1ezsv.s3-website-us-east-1.amazonaws.com'], - // defaultBehavior: { - // origin: cloudfrontOrigins.S3BucketOrigin.withOriginAccessControl( - // dummyBucket - // ), - // // allowedMethods: cloudfront.AllowedMethods.ALLOW_GET_HEAD, - // // viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, - // // cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED, - // // compress: true, - // // responseHeadersPolicy: securityHeadersPolicy, - // }, - // defaultRootObject: "index.html", - // // enableLogging: true, - // // logBucket: loggingBucket, - // httpVersion: cloudfront.HttpVersion.HTTP2, - // // errorResponses: [ - // // { - // // httpStatus: 403, - // // responseHttpStatus: 200, - // // responsePagePath: "/index.html", - // // }, - // // ], - // } - // ); + const distribution = new cloudfront.Distribution( + scope, + "CloudFrontDistribution", + { + certificate: deploymentConfigParameters.cloudfrontCertificateArn + ? acm.Certificate.fromCertificateArn( + scope, + "certArn", + deploymentConfigParameters.cloudfrontCertificateArn + ) + : undefined, + domainNames: deploymentConfigParameters.cloudfrontDomainName + ? [deploymentConfigParameters.cloudfrontDomainName] + : [], + defaultBehavior: { + origin: cloudfrontOrigins.S3BucketOrigin.withOriginAccessControl( + uiBucket + ), + allowedMethods: cloudfront.AllowedMethods.ALLOW_GET_HEAD, + viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, + cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED, + compress: true, + responseHeadersPolicy: securityHeadersPolicy, + }, + defaultRootObject: "index.html", + enableLogging: true, + logBucket: loggingBucket, + httpVersion: cloudfront.HttpVersion.HTTP2, + errorResponses: [ + { + httpStatus: 403, + responseHttpStatus: 200, + responsePagePath: "/index.html", + }, + ], + } + ); - // const applicationEndpointUrl = `https://${distribution.distributionDomainName}/`; + const applicationEndpointUrl = `https://${distribution.distributionDomainName}/`; setupWaf(scope, stage, project, deploymentConfigParameters); @@ -209,9 +161,9 @@ export function createUiComponents(props: CreateUiComponentsProps) { ); return { - // cloudfrontDistributionId: distribution.distributionId, - // distribution, - // applicationEndpointUrl, + cloudfrontDistributionId: distribution.distributionId, + distribution, + applicationEndpointUrl, s3BucketName: uiBucket.bucketName, uiBucket, }; From 3794bdfc5f054a37c02599e48884ed8758894e60 Mon Sep 17 00:00:00 2001 From: Pete Dunlap Date: Mon, 9 Dec 2024 15:44:05 -0500 Subject: [PATCH 3/9] CMDCT-4184 - adds import instructions for serverless -> cdk cutover --- import_instructions.md | 46 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 import_instructions.md diff --git a/import_instructions.md b/import_instructions.md new file mode 100644 index 000000000..533c06d95 --- /dev/null +++ b/import_instructions.md @@ -0,0 +1,46 @@ +# Import Instructions + +From `pete-sls` branch: + +1. deploy sls to get it ready for deletion with retained resources configured for import + +``` +./run deploy --stage master +``` + +2. destroy sls + +``` +./run destroy --stage master +``` + +From `jon-cdk` branch: + +1. comment out Cloudfront Distribution definition and dependent resources + +``` +# ONCE YOU COMMENTED THEM OUT +./run deploy --stage master +``` + +2. Restore Cloudfront Distribution definition in the simplified version (there are 2) + +``` +PROJECT=seds cdk import --context stage=master --force +``` + +3. Answer questions as you import to make sure you get the SLS UI stack's retained Cloudfront Distribution + +4. Run a cdk deploy + +``` +./run deploy --stage master +``` + +5. Comment out the simplified version of Cloudfront Distribution definition. Restore the complicated Cloudfront Distribution definition and dependent resources + +6. Run a cdk deploy again + +``` +./run deploy --stage master +``` From 3935ac4ac3323c9415c361e67ce73a802f048033 Mon Sep 17 00:00:00 2001 From: Pete Dunlap Date: Mon, 9 Dec 2024 15:50:22 -0500 Subject: [PATCH 4/9] CMDCT-4184 - cleaning up whitespace and comments --- deployment/stacks/ui.ts | 24 ++++++++++++++---------- import_instructions.md | 12 ++++++------ src/run.ts | 2 -- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/deployment/stacks/ui.ts b/deployment/stacks/ui.ts index 61ea71def..b8ab18d5b 100644 --- a/deployment/stacks/ui.ts +++ b/deployment/stacks/ui.ts @@ -93,19 +93,23 @@ export function createUiComponents(props: CreateUiComponentsProps) { } ); - // new cloudfront.Distribution(scope, 'CloudFrontDistribution', { - // defaultBehavior: { - // origin: new cloudfrontOrigins.HttpOrigin( - // 'www.example.com', - // { originId: 'Default'} - // ), - // cachePolicy: cloudfront.CachePolicy.CACHING_DISABLED, - // }, - // }); + // new cloudfront.Distribution( + // scope, + // 'CloudFrontDistribution', + // { + // defaultBehavior: { + // origin: new cloudfrontOrigins.HttpOrigin( + // 'www.example.com', + // { originId: 'Default'} + // ), + // cachePolicy: cloudfront.CachePolicy.CACHING_DISABLED, + // }, + // } + // ); const distribution = new cloudfront.Distribution( scope, - "CloudFrontDistribution", + "CloudFrontDistribution", { certificate: deploymentConfigParameters.cloudfrontCertificateArn ? acm.Certificate.fromCertificateArn( diff --git a/import_instructions.md b/import_instructions.md index 533c06d95..d1b35681b 100644 --- a/import_instructions.md +++ b/import_instructions.md @@ -1,25 +1,25 @@ # Import Instructions -From `pete-sls` branch: +## From `pete-sls` branch: -1. deploy sls to get it ready for deletion with retained resources configured for import +1. Deploy sls to get it ready for deletion with retained resources configured for import ``` ./run deploy --stage master ``` -2. destroy sls +2. Destroy sls ``` ./run destroy --stage master ``` -From `jon-cdk` branch: +## From `jon-cdk` branch: -1. comment out Cloudfront Distribution definition and dependent resources +1. Comment out Cloudfront Distribution definition and dependent resources ``` -# ONCE YOU COMMENTED THEM OUT +# ONLY RUN ONCE YOU COMMENTED THEM OUT ./run deploy --stage master ``` diff --git a/src/run.ts b/src/run.ts index 365c134c3..0da3b3dd0 100644 --- a/src/run.ts +++ b/src/run.ts @@ -209,8 +209,6 @@ async function deploy(options: { stage: string }) { const stage = options.stage; const runner = new LabeledProcessRunner(); await prepare_services(runner); - // const importCmd = ["cdk", "import", "--context", `stage=${stage}`]; //#--force - // await runner.run_command_and_output("CDK import", importCmd, "."); const deployCmd = ["cdk", "deploy", "--context", `stage=${stage}`, "--all"]; await runner.run_command_and_output("CDK deploy", deployCmd, "."); } From 1b8b11d0cfe839f5028c1d9d7bcb3e6e603a0d1f Mon Sep 17 00:00:00 2001 From: Pete Dunlap Date: Wed, 11 Dec 2024 16:48:07 -0500 Subject: [PATCH 5/9] CMDCT-4188 - comments out distribution with dependencies --- deployment/stacks/parent.ts | 114 ++++++++++++++++++------------------ deployment/stacks/ui.ts | 89 ++++++++++++++-------------- 2 files changed, 103 insertions(+), 100 deletions(-) diff --git a/deployment/stacks/parent.ts b/deployment/stacks/parent.ts index 3cdfd11e8..99b70433b 100644 --- a/deployment/stacks/parent.ts +++ b/deployment/stacks/parent.ts @@ -2,19 +2,19 @@ import { Construct } from "constructs"; import { aws_ec2 as ec2, aws_iam as iam, - aws_ssm as ssm, - CfnOutput, + // aws_ssm as ssm, + // CfnOutput, Stack, StackProps, } from "aws-cdk-lib"; import { CloudWatchLogsResourcePolicy } from "../constructs/cloudwatch-logs-resource-policy"; import { DeploymentConfigProperties } from "../deployment-config"; import { createDataComponents } from "./data"; -import { createUiAuthComponents } from "./ui-auth"; +// import { createUiAuthComponents } from "./ui-auth"; import { createUiComponents } from "./ui"; import { createApiComponents } from "./api"; import { sortSubnets } from "../utils/vpc"; -import { deployFrontend } from "./deployFrontend"; +// import { deployFrontend } from "./deployFrontend"; import { createCustomResourceRole } from "./customResourceRole"; export class ParentStack extends Stack { @@ -30,8 +30,8 @@ export class ParentStack extends Stack { project, isDev, vpcName, - bootstrapUsersPasswordArn, - oktaMetadataUrl, + // bootstrapUsersPasswordArn, + // oktaMetadataUrl, brokerString, iamPermissionsBoundaryArn, iamPath, @@ -65,7 +65,8 @@ export class ParentStack extends Stack { customResourceRole, }); - const { apiGatewayRestApiUrl, restApiId } = createApiComponents({ + // const { apiGatewayRestApiUrl, restApiId } = + createApiComponents({ ...commonProps, vpc, privateSubnets, @@ -73,61 +74,62 @@ export class ParentStack extends Stack { brokerString, }); - const { - applicationEndpointUrl, - cloudfrontDistributionId, - distribution, - s3BucketName, - uiBucket, - } = createUiComponents({ + // const { + // // applicationEndpointUrl, + // // cloudfrontDistributionId, + // // distribution, + // s3BucketName, + // uiBucket, + // } = + createUiComponents({ deploymentConfigParameters, ...commonProps, }); - const { - userPoolDomainName, - identityPoolId, - userPoolId, - userPoolClientId, - } = createUiAuthComponents({ - ...commonProps, - oktaMetadataUrl, - applicationEndpointUrl, - restApiId, - bootstrapUsersPasswordArn, - customResourceRole, - }); + // const { + // userPoolDomainName, + // identityPoolId, + // userPoolId, + // userPoolClientId, + // } = createUiAuthComponents({ + // ...commonProps, + // oktaMetadataUrl, + // applicationEndpointUrl, + // restApiId, + // bootstrapUsersPasswordArn, + // customResourceRole, + // }); - deployFrontend({ - ...commonProps, - uiBucket, - distribution, - apiGatewayRestApiUrl, - applicationEndpointUrl, - identityPoolId, - userPoolId, - userPoolClientId, - userPoolClientDomain: `${userPoolDomainName}.auth.${this.region}.amazoncognito.com`, - customResourceRole, - }); + // deployFrontend({ + // ...commonProps, + // uiBucket, + // distribution, + // apiGatewayRestApiUrl, + // applicationEndpointUrl, + // identityPoolId, + // userPoolId, + // userPoolClientId, + // userPoolClientDomain: `${userPoolDomainName}.auth.${this.region}.amazoncognito.com`, + // customResourceRole, + // }); - new ssm.StringParameter(this, "DeploymentOutput", { - parameterName: `/${project}/${stage}/deployment-output`, - stringValue: JSON.stringify({ - apiGatewayRestApiUrl, - applicationEndpointUrl, - s3BucketName, - cloudfrontDistributionId, - identityPoolId, - userPoolId, - userPoolClientId, - userPoolClientDomain: `${userPoolDomainName}.auth.${this.region}.amazoncognito.com`, - }), - description: `Deployment output for the ${stage} environment.`, - }); + // new ssm.StringParameter(this, "DeploymentOutput", { + // parameterName: `/${project}/${stage}/deployment-output`, + // stringValue: JSON.stringify({ + // apiGatewayRestApiUrl, + // applicationEndpointUrl, + // s3BucketName, + // cloudfrontDistributionId, + // identityPoolId, + // userPoolId, + // userPoolClientId, + // userPoolClientDomain: `${userPoolDomainName}.auth.${this.region}.amazoncognito.com`, + // }), + // description: `Deployment output for the ${stage} environment.`, + // }); - new CfnOutput(this, "CloudFrontUrl", { - value: applicationEndpointUrl, - }); + // new CfnOutput(this, "CloudFrontUrl", { + // value: applicationEndpointUrl, + // }); } } diff --git a/deployment/stacks/ui.ts b/deployment/stacks/ui.ts index b8ab18d5b..0309c622a 100644 --- a/deployment/stacks/ui.ts +++ b/deployment/stacks/ui.ts @@ -1,7 +1,7 @@ import { Construct } from "constructs"; import { aws_cloudfront as cloudfront, - aws_cloudfront_origins as cloudfrontOrigins, + // aws_cloudfront_origins as cloudfrontOrigins, aws_iam as iam, aws_kinesisfirehose as firehose, aws_s3 as s3, @@ -9,7 +9,7 @@ import { Aws, Duration, RemovalPolicy, - aws_certificatemanager as acm, + // aws_certificatemanager as acm, } from "aws-cdk-lib"; import { addIamPropertiesToBucketAutoDeleteRole } from "../utils/s3"; import { IManagedPolicy } from "aws-cdk-lib/aws-iam"; @@ -64,7 +64,8 @@ export function createUiComponents(props: CreateUiComponentsProps) { }) ); - const securityHeadersPolicy = new cloudfront.ResponseHeadersPolicy( + // const securityHeadersPolicy = + new cloudfront.ResponseHeadersPolicy( scope, "CloudFormationHeadersPolicy", { @@ -107,45 +108,45 @@ export function createUiComponents(props: CreateUiComponentsProps) { // } // ); - const distribution = new cloudfront.Distribution( - scope, - "CloudFrontDistribution", - { - certificate: deploymentConfigParameters.cloudfrontCertificateArn - ? acm.Certificate.fromCertificateArn( - scope, - "certArn", - deploymentConfigParameters.cloudfrontCertificateArn - ) - : undefined, - domainNames: deploymentConfigParameters.cloudfrontDomainName - ? [deploymentConfigParameters.cloudfrontDomainName] - : [], - defaultBehavior: { - origin: cloudfrontOrigins.S3BucketOrigin.withOriginAccessControl( - uiBucket - ), - allowedMethods: cloudfront.AllowedMethods.ALLOW_GET_HEAD, - viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, - cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED, - compress: true, - responseHeadersPolicy: securityHeadersPolicy, - }, - defaultRootObject: "index.html", - enableLogging: true, - logBucket: loggingBucket, - httpVersion: cloudfront.HttpVersion.HTTP2, - errorResponses: [ - { - httpStatus: 403, - responseHttpStatus: 200, - responsePagePath: "/index.html", - }, - ], - } - ); + // const distribution = new cloudfront.Distribution( + // scope, + // "CloudFrontDistribution", + // { + // certificate: deploymentConfigParameters.cloudfrontCertificateArn + // ? acm.Certificate.fromCertificateArn( + // scope, + // "certArn", + // deploymentConfigParameters.cloudfrontCertificateArn + // ) + // : undefined, + // domainNames: deploymentConfigParameters.cloudfrontDomainName + // ? [deploymentConfigParameters.cloudfrontDomainName] + // : [], + // defaultBehavior: { + // origin: cloudfrontOrigins.S3BucketOrigin.withOriginAccessControl( + // uiBucket + // ), + // allowedMethods: cloudfront.AllowedMethods.ALLOW_GET_HEAD, + // viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, + // cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED, + // compress: true, + // responseHeadersPolicy: securityHeadersPolicy, + // }, + // defaultRootObject: "index.html", + // enableLogging: true, + // logBucket: loggingBucket, + // httpVersion: cloudfront.HttpVersion.HTTP2, + // errorResponses: [ + // { + // httpStatus: 403, + // responseHttpStatus: 200, + // responsePagePath: "/index.html", + // }, + // ], + // } + // ); - const applicationEndpointUrl = `https://${distribution.distributionDomainName}/`; + // const applicationEndpointUrl = `https://${distribution.distributionDomainName}/`; setupWaf(scope, stage, project, deploymentConfigParameters); @@ -165,9 +166,9 @@ export function createUiComponents(props: CreateUiComponentsProps) { ); return { - cloudfrontDistributionId: distribution.distributionId, - distribution, - applicationEndpointUrl, + // cloudfrontDistributionId: distribution.distributionId, + // distribution, + // applicationEndpointUrl, s3BucketName: uiBucket.bucketName, uiBucket, }; From 7777c3a021d3a866970022dca2f1176adb7595d8 Mon Sep 17 00:00:00 2001 From: Pete Dunlap Date: Wed, 11 Dec 2024 17:04:03 -0500 Subject: [PATCH 6/9] Revert "CMDCT-4188 - comments out distribution with dependencies" This reverts commit 1b8b11d0cfe839f5028c1d9d7bcb3e6e603a0d1f. --- deployment/stacks/parent.ts | 114 ++++++++++++++++++------------------ deployment/stacks/ui.ts | 89 ++++++++++++++-------------- 2 files changed, 100 insertions(+), 103 deletions(-) diff --git a/deployment/stacks/parent.ts b/deployment/stacks/parent.ts index 99b70433b..3cdfd11e8 100644 --- a/deployment/stacks/parent.ts +++ b/deployment/stacks/parent.ts @@ -2,19 +2,19 @@ import { Construct } from "constructs"; import { aws_ec2 as ec2, aws_iam as iam, - // aws_ssm as ssm, - // CfnOutput, + aws_ssm as ssm, + CfnOutput, Stack, StackProps, } from "aws-cdk-lib"; import { CloudWatchLogsResourcePolicy } from "../constructs/cloudwatch-logs-resource-policy"; import { DeploymentConfigProperties } from "../deployment-config"; import { createDataComponents } from "./data"; -// import { createUiAuthComponents } from "./ui-auth"; +import { createUiAuthComponents } from "./ui-auth"; import { createUiComponents } from "./ui"; import { createApiComponents } from "./api"; import { sortSubnets } from "../utils/vpc"; -// import { deployFrontend } from "./deployFrontend"; +import { deployFrontend } from "./deployFrontend"; import { createCustomResourceRole } from "./customResourceRole"; export class ParentStack extends Stack { @@ -30,8 +30,8 @@ export class ParentStack extends Stack { project, isDev, vpcName, - // bootstrapUsersPasswordArn, - // oktaMetadataUrl, + bootstrapUsersPasswordArn, + oktaMetadataUrl, brokerString, iamPermissionsBoundaryArn, iamPath, @@ -65,8 +65,7 @@ export class ParentStack extends Stack { customResourceRole, }); - // const { apiGatewayRestApiUrl, restApiId } = - createApiComponents({ + const { apiGatewayRestApiUrl, restApiId } = createApiComponents({ ...commonProps, vpc, privateSubnets, @@ -74,62 +73,61 @@ export class ParentStack extends Stack { brokerString, }); - // const { - // // applicationEndpointUrl, - // // cloudfrontDistributionId, - // // distribution, - // s3BucketName, - // uiBucket, - // } = - createUiComponents({ + const { + applicationEndpointUrl, + cloudfrontDistributionId, + distribution, + s3BucketName, + uiBucket, + } = createUiComponents({ deploymentConfigParameters, ...commonProps, }); - // const { - // userPoolDomainName, - // identityPoolId, - // userPoolId, - // userPoolClientId, - // } = createUiAuthComponents({ - // ...commonProps, - // oktaMetadataUrl, - // applicationEndpointUrl, - // restApiId, - // bootstrapUsersPasswordArn, - // customResourceRole, - // }); + const { + userPoolDomainName, + identityPoolId, + userPoolId, + userPoolClientId, + } = createUiAuthComponents({ + ...commonProps, + oktaMetadataUrl, + applicationEndpointUrl, + restApiId, + bootstrapUsersPasswordArn, + customResourceRole, + }); - // deployFrontend({ - // ...commonProps, - // uiBucket, - // distribution, - // apiGatewayRestApiUrl, - // applicationEndpointUrl, - // identityPoolId, - // userPoolId, - // userPoolClientId, - // userPoolClientDomain: `${userPoolDomainName}.auth.${this.region}.amazoncognito.com`, - // customResourceRole, - // }); + deployFrontend({ + ...commonProps, + uiBucket, + distribution, + apiGatewayRestApiUrl, + applicationEndpointUrl, + identityPoolId, + userPoolId, + userPoolClientId, + userPoolClientDomain: `${userPoolDomainName}.auth.${this.region}.amazoncognito.com`, + customResourceRole, + }); - // new ssm.StringParameter(this, "DeploymentOutput", { - // parameterName: `/${project}/${stage}/deployment-output`, - // stringValue: JSON.stringify({ - // apiGatewayRestApiUrl, - // applicationEndpointUrl, - // s3BucketName, - // cloudfrontDistributionId, - // identityPoolId, - // userPoolId, - // userPoolClientId, - // userPoolClientDomain: `${userPoolDomainName}.auth.${this.region}.amazoncognito.com`, - // }), - // description: `Deployment output for the ${stage} environment.`, - // }); + new ssm.StringParameter(this, "DeploymentOutput", { + parameterName: `/${project}/${stage}/deployment-output`, + stringValue: JSON.stringify({ + apiGatewayRestApiUrl, + applicationEndpointUrl, + s3BucketName, + cloudfrontDistributionId, + identityPoolId, + userPoolId, + userPoolClientId, + userPoolClientDomain: `${userPoolDomainName}.auth.${this.region}.amazoncognito.com`, + }), + description: `Deployment output for the ${stage} environment.`, + }); - // new CfnOutput(this, "CloudFrontUrl", { - // value: applicationEndpointUrl, - // }); + new CfnOutput(this, "CloudFrontUrl", { + value: applicationEndpointUrl, + }); } } diff --git a/deployment/stacks/ui.ts b/deployment/stacks/ui.ts index 0309c622a..b8ab18d5b 100644 --- a/deployment/stacks/ui.ts +++ b/deployment/stacks/ui.ts @@ -1,7 +1,7 @@ import { Construct } from "constructs"; import { aws_cloudfront as cloudfront, - // aws_cloudfront_origins as cloudfrontOrigins, + aws_cloudfront_origins as cloudfrontOrigins, aws_iam as iam, aws_kinesisfirehose as firehose, aws_s3 as s3, @@ -9,7 +9,7 @@ import { Aws, Duration, RemovalPolicy, - // aws_certificatemanager as acm, + aws_certificatemanager as acm, } from "aws-cdk-lib"; import { addIamPropertiesToBucketAutoDeleteRole } from "../utils/s3"; import { IManagedPolicy } from "aws-cdk-lib/aws-iam"; @@ -64,8 +64,7 @@ export function createUiComponents(props: CreateUiComponentsProps) { }) ); - // const securityHeadersPolicy = - new cloudfront.ResponseHeadersPolicy( + const securityHeadersPolicy = new cloudfront.ResponseHeadersPolicy( scope, "CloudFormationHeadersPolicy", { @@ -108,45 +107,45 @@ export function createUiComponents(props: CreateUiComponentsProps) { // } // ); - // const distribution = new cloudfront.Distribution( - // scope, - // "CloudFrontDistribution", - // { - // certificate: deploymentConfigParameters.cloudfrontCertificateArn - // ? acm.Certificate.fromCertificateArn( - // scope, - // "certArn", - // deploymentConfigParameters.cloudfrontCertificateArn - // ) - // : undefined, - // domainNames: deploymentConfigParameters.cloudfrontDomainName - // ? [deploymentConfigParameters.cloudfrontDomainName] - // : [], - // defaultBehavior: { - // origin: cloudfrontOrigins.S3BucketOrigin.withOriginAccessControl( - // uiBucket - // ), - // allowedMethods: cloudfront.AllowedMethods.ALLOW_GET_HEAD, - // viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, - // cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED, - // compress: true, - // responseHeadersPolicy: securityHeadersPolicy, - // }, - // defaultRootObject: "index.html", - // enableLogging: true, - // logBucket: loggingBucket, - // httpVersion: cloudfront.HttpVersion.HTTP2, - // errorResponses: [ - // { - // httpStatus: 403, - // responseHttpStatus: 200, - // responsePagePath: "/index.html", - // }, - // ], - // } - // ); + const distribution = new cloudfront.Distribution( + scope, + "CloudFrontDistribution", + { + certificate: deploymentConfigParameters.cloudfrontCertificateArn + ? acm.Certificate.fromCertificateArn( + scope, + "certArn", + deploymentConfigParameters.cloudfrontCertificateArn + ) + : undefined, + domainNames: deploymentConfigParameters.cloudfrontDomainName + ? [deploymentConfigParameters.cloudfrontDomainName] + : [], + defaultBehavior: { + origin: cloudfrontOrigins.S3BucketOrigin.withOriginAccessControl( + uiBucket + ), + allowedMethods: cloudfront.AllowedMethods.ALLOW_GET_HEAD, + viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, + cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED, + compress: true, + responseHeadersPolicy: securityHeadersPolicy, + }, + defaultRootObject: "index.html", + enableLogging: true, + logBucket: loggingBucket, + httpVersion: cloudfront.HttpVersion.HTTP2, + errorResponses: [ + { + httpStatus: 403, + responseHttpStatus: 200, + responsePagePath: "/index.html", + }, + ], + } + ); - // const applicationEndpointUrl = `https://${distribution.distributionDomainName}/`; + const applicationEndpointUrl = `https://${distribution.distributionDomainName}/`; setupWaf(scope, stage, project, deploymentConfigParameters); @@ -166,9 +165,9 @@ export function createUiComponents(props: CreateUiComponentsProps) { ); return { - // cloudfrontDistributionId: distribution.distributionId, - // distribution, - // applicationEndpointUrl, + cloudfrontDistributionId: distribution.distributionId, + distribution, + applicationEndpointUrl, s3BucketName: uiBucket.bucketName, uiBucket, }; From 75311ccc3541bd59f1e133b41264c91cdaf87826 Mon Sep 17 00:00:00 2001 From: Pete Dunlap Date: Fri, 13 Dec 2024 11:19:34 -0500 Subject: [PATCH 7/9] CMDCT-4188 - import instructions now ready for failed conversion to cdk --- deployment/import_instructions.md | 107 ++++++++++++++++++++++++++++++ import_instructions.md | 46 ------------- 2 files changed, 107 insertions(+), 46 deletions(-) create mode 100644 deployment/import_instructions.md delete mode 100644 import_instructions.md diff --git a/deployment/import_instructions.md b/deployment/import_instructions.md new file mode 100644 index 000000000..cb996cd6b --- /dev/null +++ b/deployment/import_instructions.md @@ -0,0 +1,107 @@ +# Import Instructions + +## From `pete-sls` branch: + +1. Deploy sls to get it ready for deletion with retained resources configured for import + +``` +./run deploy --stage master +``` + +2. Destroy sls + +``` +./run destroy --stage master +``` + +## From `jon-cdk` branch: + +1. Comment out Cloudfront Distribution definition and dependent resources + +``` +# ONLY RUN ONCE YOU COMMENTED THEM OUT +./run deploy --stage master +``` + +2. Restore Cloudfront Distribution definition in the simplified version (there are 2) + +``` +PROJECT=seds cdk import --context stage=master --force +``` + +3. Answer questions as you import to make sure you get the SLS UI stack's retained Cloudfront Distribution + +4. Run a cdk deploy + +``` +./run deploy --stage master +``` + +5. Comment out the simplified version of Cloudfront Distribution definition. Restore the complicated Cloudfront Distribution definition and dependent resources + +6. Run a cdk deploy again + +``` +./run deploy --stage master +``` + +## What if it all goes pear shaped? + +### If during the middle of the migration, things begin to break and we need to reinstate the serverless stack, we need a way to bring the Cloudfront Distribution back into the newly rebuilt serverless stack. Fortunately this is possible if you follow these steps. + +1) Get the Cloudfront Distribution unaffiliated with any Cloudformation stack. If it's already been successfully imported into the new cdk stack then you'll need to destroy the cdk stack to eject it from that stack. +``` +# this assumes you're on `jon-cdk` branch +./run destroy --stage master +``` + +2) Now you need switch to `pete-sls` branch and comment out any CloudfrontDistribution and dependent configuration. +These are the necessary changes: https://github.com/Enterprise-CMCS/macpro-mdct-seds/commit/8eb551f980a37355729dc1795f5d229987699c84 + +3) Deploy serverless stack (without CloudfrontDistribution) via Github Action (necessary because of permissions limitations) by pushing up changes made in the last step. + +4) Now you need to import the CloudfrontDistribution to the existing ui-XXXXX stack created by the last step. First you'll need to get the existing stack's template and save it to a local file. +``` +aws cloudformation get-template --stack-name ui-cmdct-4188-sls | jq '.TemplateBody' > deployment/cfn_template.json +``` + +5) Now open up the file you just created (deployment/cfn_template.json) and add the following Cloudfront Distribution config to it's resources section: +```json + "CloudFrontDistribution": { + "Type": "AWS::CloudFront::Distribution", + "DeletionPolicy": "Retain", + "Properties": { + "DistributionConfig": { + "CustomOrigin": { + "DNSName": "www.example.com", + "OriginProtocolPolicy": "http-only", + "OriginSSLProtocols": [ + "TLSv1" + ] + }, + "Enabled": true, + "DefaultCacheBehavior": { + "CachePolicyId": "Managed-CachingDisabled", + "TargetOriginId": "some_target_origin_id", + "ViewerProtocolPolicy": "allow-all" + } + } + } + }, +``` + +6) Now open up the AWS console and navigate to the Cloudformation console's show page for the particular ui-XXXXX stack. + +7) Import the stack by doing the following: + - Under `Stack Actions` select `Import resources into stack` + - In the `Specify template` section choose upload a template file and upload the one we just created: `deployment/cfn_template.json` + - In the `Identify resources` section you'll have to provide the ID of the incoming Cloudfront Distribution + - Next and confirm until it begins the import + +8) Once the import is complete, take a breath. + +9) Revert the changes where you commented out the Serverless definition of Cloudfront Distribution (undo step 2). + +10) Verify that the Serverless definition now contains the Cloudfront Distribution then deploy via Github Action. + +11) Verify that Cloudfront Distribution is back into the stack and appropriately pointing at the application. diff --git a/import_instructions.md b/import_instructions.md deleted file mode 100644 index d1b35681b..000000000 --- a/import_instructions.md +++ /dev/null @@ -1,46 +0,0 @@ -# Import Instructions - -## From `pete-sls` branch: - -1. Deploy sls to get it ready for deletion with retained resources configured for import - -``` -./run deploy --stage master -``` - -2. Destroy sls - -``` -./run destroy --stage master -``` - -## From `jon-cdk` branch: - -1. Comment out Cloudfront Distribution definition and dependent resources - -``` -# ONLY RUN ONCE YOU COMMENTED THEM OUT -./run deploy --stage master -``` - -2. Restore Cloudfront Distribution definition in the simplified version (there are 2) - -``` -PROJECT=seds cdk import --context stage=master --force -``` - -3. Answer questions as you import to make sure you get the SLS UI stack's retained Cloudfront Distribution - -4. Run a cdk deploy - -``` -./run deploy --stage master -``` - -5. Comment out the simplified version of Cloudfront Distribution definition. Restore the complicated Cloudfront Distribution definition and dependent resources - -6. Run a cdk deploy again - -``` -./run deploy --stage master -``` From 6ef6632dc62505e1f8ca7c25b1c6c794183c98cc Mon Sep 17 00:00:00 2001 From: Pete Dunlap Date: Thu, 19 Dec 2024 15:17:02 -0500 Subject: [PATCH 8/9] CMDCT-4194 - fixes env bug for table names --- deployment/stacks/api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/stacks/api.ts b/deployment/stacks/api.ts index 7d7a8ab0d..3aef6c6ce 100644 --- a/deployment/stacks/api.ts +++ b/deployment/stacks/api.ts @@ -140,7 +140,7 @@ export function createApiComponents(props: CreateApiComponentsProps) { BOOTSTRAP_BROKER_STRING_TLS: brokerString, stage, ...Object.fromEntries( - tables.map((table) => [`${table.id}Name`, table.name]) + tables.map((table) => [`${table.id}TableName`, table.name]) ), }; From 73b225bf0837797ab10517891dfe0bcdb140f6f8 Mon Sep 17 00:00:00 2001 From: Pete Dunlap Date: Mon, 23 Dec 2024 10:17:54 -0500 Subject: [PATCH 9/9] CMDCT-4194 cdk side, creating a better way to import resources from serverless including Cognito UserPool (#15012) --- deployment/app.ts | 83 +++++++++++---------- deployment/import_instructions.md | 46 ++++++------ deployment/stacks/data.ts | 35 +++++---- deployment/stacks/ui-auth.ts | 55 +++++++------- deployment/stacks/ui.ts | 14 ---- deployment/stacks/with_imports/parent.ts | 28 +++++++ deployment/stacks/with_imports/ui-auth.ts | 45 +++++++++++ deployment/stacks/with_imports/ui.ts | 29 +++++++ deployment/stacks/without_imports/parent.ts | 16 ++++ services/ui-auth/serverless.yml | 6 +- services/ui/serverless.yml | 4 +- src/run.ts | 2 +- 12 files changed, 237 insertions(+), 126 deletions(-) create mode 100644 deployment/stacks/with_imports/parent.ts create mode 100644 deployment/stacks/with_imports/ui-auth.ts create mode 100644 deployment/stacks/with_imports/ui.ts create mode 100644 deployment/stacks/without_imports/parent.ts diff --git a/deployment/app.ts b/deployment/app.ts index 98f6e2a98..2f654f84f 100644 --- a/deployment/app.ts +++ b/deployment/app.ts @@ -1,57 +1,62 @@ #!/usr/bin/env node import "source-map-support/register"; import * as cdk from "aws-cdk-lib"; +import { WithoutImportsParentStack } from "./stacks/without_imports/parent"; +import { WithImportsParentStack} from "./stacks/with_imports/parent"; import { ParentStack } from "./stacks/parent"; import { determineDeploymentConfig } from "./deployment-config"; import { getSecret } from "./utils/secrets-manager"; import { getDeploymentConfigParameters } from "./utils/systems-manager"; async function main() { - try { - const app = new cdk.App({ - defaultStackSynthesizer: new cdk.DefaultStackSynthesizer( - JSON.parse((await getSecret("cdkSynthesizerConfig"))!) - ), - }); + const app = new cdk.App({ + defaultStackSynthesizer: new cdk.DefaultStackSynthesizer( + JSON.parse((await getSecret("cdkSynthesizerConfig"))!) + ), + }); - const stage = app.node.getContext("stage"); - const config = await determineDeploymentConfig(stage); + const stage = app.node.getContext("stage"); + const config = await determineDeploymentConfig(stage); - const parametersToFetch = { - cloudfrontCertificateArn: { - name: "cloudfront/certificateArn", - useDefault: true, - }, - cloudfrontDomainName: { - name: "cloudfront/domainName", - useDefault: false, - }, - vpnIpSetArn: { name: "vpnIpSetArn", useDefault: true }, - vpnIpv6SetArn: { name: "vpnIpv6SetArn", useDefault: true }, - hostedZoneId: { name: "route53/hostedZoneId", useDefault: true }, - domainName: { name: "route53/domainName", useDefault: true }, - }; + const parametersToFetch = { + cloudfrontCertificateArn: { + name: "cloudfront/certificateArn", + useDefault: true, + }, + cloudfrontDomainName: { + name: "cloudfront/domainName", + useDefault: false, + }, + vpnIpSetArn: { name: "vpnIpSetArn", useDefault: true }, + vpnIpv6SetArn: { name: "vpnIpv6SetArn", useDefault: true }, + hostedZoneId: { name: "route53/hostedZoneId", useDefault: true }, + domainName: { name: "route53/domainName", useDefault: true }, + }; - const deploymentConfigParameters = await getDeploymentConfigParameters( - parametersToFetch, - stage - ); + const deploymentConfigParameters = await getDeploymentConfigParameters( + parametersToFetch, + stage + ); - cdk.Tags.of(app).add("STAGE", stage); - cdk.Tags.of(app).add("PROJECT", config.project); + cdk.Tags.of(app).add("STAGE", stage); + cdk.Tags.of(app).add("PROJECT", config.project); - new ParentStack(app, `${config.project}-${stage}`, { - ...config, - env: { - account: process.env.CDK_DEFAULT_ACCOUNT, - region: process.env.CDK_DEFAULT_REGION, - }, - deploymentConfigParameters, - }); - } catch (error) { - console.error("Error:", error); - process.exit(1); + let correctParentStack; + if (process.env.WITHOUT_IMPORTS) { + correctParentStack = WithoutImportsParentStack + } else if (process.env.WITH_IMPORTS) { + correctParentStack = WithImportsParentStack + } else { + correctParentStack = ParentStack } + new correctParentStack(app, `${config.project}-${stage}`, { + ...config, + env: { + account: process.env.CDK_DEFAULT_ACCOUNT, + region: process.env.CDK_DEFAULT_REGION, + }, + deploymentConfigParameters, + }); } main(); diff --git a/deployment/import_instructions.md b/deployment/import_instructions.md index cb996cd6b..3407ef286 100644 --- a/deployment/import_instructions.md +++ b/deployment/import_instructions.md @@ -5,54 +5,58 @@ 1. Deploy sls to get it ready for deletion with retained resources configured for import ``` -./run deploy --stage master +./run deploy --stage ``` -2. Destroy sls +2. Collect information about the resources we're going to be importing into the new cdk stack. +``` +cloudfront.Distribution - +cognito.UserPool - +``` + +3. Destroy sls ``` -./run destroy --stage master +./run destroy --stage ``` ## From `jon-cdk` branch: -1. Comment out Cloudfront Distribution definition and dependent resources -``` -# ONLY RUN ONCE YOU COMMENTED THEM OUT -./run deploy --stage master +1. Create just the new cdk stack without anything inside of it. + +```bash +WITHOUT_IMPORTS=true ./run deploy --stage ``` -2. Restore Cloudfront Distribution definition in the simplified version (there are 2) +2. Now import all the serverless ejected resources. +```bash +WITH_IMPORTS=true PROJECT=seds cdk import --context stage= --force ``` -PROJECT=seds cdk import --context stage=master --force -``` +As this import occurs you'll have to provide the information you gathered just before destroying the serverless stacks. -3. Answer questions as you import to make sure you get the SLS UI stack's retained Cloudfront Distribution +3. Run a deploy on that same imported resource set. -4. Run a cdk deploy - -``` -./run deploy --stage master +```bash +WITH_IMPORTS=true ./run deploy --stage ``` -5. Comment out the simplified version of Cloudfront Distribution definition. Restore the complicated Cloudfront Distribution definition and dependent resources +4. Run a full deploy by kicking off the full cdk deploy via Github Action. Permissions for individual developers are limited so you must use Github Action to do this part. -6. Run a cdk deploy again +5. Find the Cloudfront Url in the Github Action's logs (or in the outputs section of your Cloudformation Stack). Visit the site and confirm that you can login and use the application. :tada: Congrats, you did it! -``` -./run deploy --stage master -``` ## What if it all goes pear shaped? ### If during the middle of the migration, things begin to break and we need to reinstate the serverless stack, we need a way to bring the Cloudfront Distribution back into the newly rebuilt serverless stack. Fortunately this is possible if you follow these steps. +:grey_exclamation: These instructions are specific to reimporting a Cloudfront Distribution but the same pattern should also apply to any other imported resources that need un-importing should the need arise. + 1) Get the Cloudfront Distribution unaffiliated with any Cloudformation stack. If it's already been successfully imported into the new cdk stack then you'll need to destroy the cdk stack to eject it from that stack. ``` # this assumes you're on `jon-cdk` branch -./run destroy --stage master +./run destroy --stage ``` 2) Now you need switch to `pete-sls` branch and comment out any CloudfrontDistribution and dependent configuration. diff --git a/deployment/stacks/data.ts b/deployment/stacks/data.ts index 8573c62a3..684f6164d 100644 --- a/deployment/stacks/data.ts +++ b/deployment/stacks/data.ts @@ -79,26 +79,29 @@ export function createDataComponents(props: CreateDataComponentsProps) { "service-role/AWSLambdaVPCAccessExecutionRole" ), ], + inlinePolicies: { + DynamoPolicy: new iam.PolicyDocument({ + statements: [ + new iam.PolicyStatement({ + effect: iam.Effect.ALLOW, + actions: [ + "dynamodb:DescribeTable", + "dynamodb:Query", + "dynamodb:Scan", + "dynamodb:GetItem", + "dynamodb:PutItem", + "dynamodb:UpdateItem", + "dynamodb:DeleteItem", + ], + resources: ["*"], + }) + ] + }) + }, permissionsBoundary: props.iamPermissionsBoundary, path: props.iamPath, }); - lambdaApiRole.addToPolicy( - new iam.PolicyStatement({ - effect: iam.Effect.ALLOW, - actions: [ - "dynamodb:DescribeTable", - "dynamodb:Query", - "dynamodb:Scan", - "dynamodb:GetItem", - "dynamodb:PutItem", - "dynamodb:UpdateItem", - "dynamodb:DeleteItem", - ], - resources: ["*"], - }) - ); - // TODO: test deploy and watch performance with this using lambda.Function vs lambda_nodejs.NodejsFunction const seedDataFunction = new lambda_nodejs.NodejsFunction(scope, "seedData", { entry: "services/database/handlers/seed/seed.js", diff --git a/deployment/stacks/ui-auth.ts b/deployment/stacks/ui-auth.ts index 5a929473e..538514f00 100644 --- a/deployment/stacks/ui-auth.ts +++ b/deployment/stacks/ui-auth.ts @@ -6,7 +6,6 @@ import { aws_lambda_nodejs as lambda_nodejs, aws_wafv2 as wafv2, aws_ssm as ssm, - RemovalPolicy, Aws, Duration, custom_resources as cr, @@ -40,7 +39,6 @@ export function createUiAuthComponents(props: CreateUiAuthComponentsProps) { const userPool = new cognito.UserPool(scope, "UserPool", { userPoolName: `${stage}-user-pool`, - removalPolicy: RemovalPolicy.DESTROY, signInAliases: { email: true, }, @@ -208,36 +206,33 @@ export function createUiAuthComponents(props: CreateUiAuthComponentsProps) { "service-role/AWSLambdaVPCAccessExecutionRole" ), ], + inlinePolicies: { + LambdaApiRolePolicy: new iam.PolicyDocument({ + statements: [ + new iam.PolicyStatement({ + actions: [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + ], + resources: ["arn:aws:logs:*:*:*"], + effect: iam.Effect.ALLOW, + }), + new iam.PolicyStatement({ + actions: ["*"], + resources: [userPool.userPoolArn], + effect: iam.Effect.ALLOW, + }), + new iam.PolicyStatement({ + actions: ["ssm:GetParameter"], + resources: [bootstrapUsersPasswordArn], + effect: iam.Effect.ALLOW, + }), + ], + }), + }, }); - lambdaApiRole.addToPolicy( - new iam.PolicyStatement({ - effect: iam.Effect.ALLOW, - actions: [ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:PutLogEvents", - ], - resources: ["arn:aws:logs:*:*:*"], - }) - ); - - lambdaApiRole.addToPolicy( - new iam.PolicyStatement({ - effect: iam.Effect.ALLOW, - actions: ["*"], - resources: [userPool.userPoolArn], - }) - ); - - lambdaApiRole.addToPolicy( - new iam.PolicyStatement({ - effect: iam.Effect.ALLOW, - actions: ["ssm:GetParameter"], - resources: [bootstrapUsersPasswordArn], - }) - ); - // TODO: test deploy and watch performance with scope using lambda.Function vs lambda_nodejs.NodejsFunction bootstrapUsersFunction = new lambda_nodejs.NodejsFunction( scope, diff --git a/deployment/stacks/ui.ts b/deployment/stacks/ui.ts index b8ab18d5b..ca253b3b2 100644 --- a/deployment/stacks/ui.ts +++ b/deployment/stacks/ui.ts @@ -93,20 +93,6 @@ export function createUiComponents(props: CreateUiComponentsProps) { } ); - // new cloudfront.Distribution( - // scope, - // 'CloudFrontDistribution', - // { - // defaultBehavior: { - // origin: new cloudfrontOrigins.HttpOrigin( - // 'www.example.com', - // { originId: 'Default'} - // ), - // cachePolicy: cloudfront.CachePolicy.CACHING_DISABLED, - // }, - // } - // ); - const distribution = new cloudfront.Distribution( scope, "CloudFrontDistribution", diff --git a/deployment/stacks/with_imports/parent.ts b/deployment/stacks/with_imports/parent.ts new file mode 100644 index 000000000..5e341fd8f --- /dev/null +++ b/deployment/stacks/with_imports/parent.ts @@ -0,0 +1,28 @@ +import { Construct } from "constructs"; +import { + Stack, + StackProps, +} from "aws-cdk-lib"; +import { DeploymentConfigProperties } from "../../deployment-config"; +import { createUiComponents } from "./ui"; +import { createUiAuthComponents } from "./ui-auth"; + +export class WithImportsParentStack extends Stack { + constructor( + scope: Construct, + id: string, + props: StackProps & DeploymentConfigProperties + ) { + super(scope, id, props); + + const { + stage, + } = props; + + createUiComponents({scope: this}); + createUiAuthComponents({ + scope: this, + stage, + }); + } +} diff --git a/deployment/stacks/with_imports/ui-auth.ts b/deployment/stacks/with_imports/ui-auth.ts new file mode 100644 index 000000000..ba4731963 --- /dev/null +++ b/deployment/stacks/with_imports/ui-auth.ts @@ -0,0 +1,45 @@ +import { Construct } from "constructs"; +import { + aws_cognito as cognito, +} from "aws-cdk-lib"; + +interface CreateUiAuthComponentsProps { + scope: Construct; + stage: string; +} + +export function createUiAuthComponents(props: CreateUiAuthComponentsProps) { + const { + scope, + stage, + } = props; + + new cognito.UserPool(scope, "UserPool", { + userPoolName: `${stage}-user-pool`, + signInAliases: { + email: true, + }, + autoVerify: { + email: true, + }, + selfSignUpEnabled: false, + standardAttributes: { + givenName: { + required: false, + mutable: true, + }, + familyName: { + required: false, + mutable: true, + }, + phoneNumber: { + required: false, + mutable: true, + }, + }, + customAttributes: { + ismemberof: new cognito.StringAttribute({ mutable: true }), + }, + advancedSecurityMode: cognito.AdvancedSecurityMode.ENFORCED, + }); +} diff --git a/deployment/stacks/with_imports/ui.ts b/deployment/stacks/with_imports/ui.ts new file mode 100644 index 000000000..4945c3940 --- /dev/null +++ b/deployment/stacks/with_imports/ui.ts @@ -0,0 +1,29 @@ +import { Construct } from "constructs"; +import { + aws_cloudfront as cloudfront, + aws_cloudfront_origins as cloudfrontOrigins, +} from "aws-cdk-lib"; + +interface CreateUiComponentsProps { + scope: Construct; +} + +export function createUiComponents(props: CreateUiComponentsProps) { + const { + scope, + } = props; + + new cloudfront.Distribution( + scope, + 'CloudFrontDistribution', + { + defaultBehavior: { + origin: new cloudfrontOrigins.HttpOrigin( + 'www.example.com', + { originId: 'Default'} + ), + cachePolicy: cloudfront.CachePolicy.CACHING_DISABLED, + }, + } + ); +} diff --git a/deployment/stacks/without_imports/parent.ts b/deployment/stacks/without_imports/parent.ts new file mode 100644 index 000000000..f4b3c6c24 --- /dev/null +++ b/deployment/stacks/without_imports/parent.ts @@ -0,0 +1,16 @@ +import { Construct } from "constructs"; +import { + Stack, + StackProps, +} from "aws-cdk-lib"; +import { DeploymentConfigProperties } from "../../deployment-config"; + +export class WithoutImportsParentStack extends Stack { + constructor( + scope: Construct, + id: string, + props: StackProps & DeploymentConfigProperties + ) { + super(scope, id, props); + } +} diff --git a/services/ui-auth/serverless.yml b/services/ui-auth/serverless.yml index ba3a4d1cf..4faa8b166 100644 --- a/services/ui-auth/serverless.yml +++ b/services/ui-auth/serverless.yml @@ -14,9 +14,9 @@ provider: name: aws runtime: nodejs20.x region: us-east-1 - stackTags: + stackTags: PROJECT: ${self:custom.project} - SERVICE: ${self:service} + SERVICE: ${self:service} iam: role: # Even though we are creating our own IAM role that is used in each lambda function below @@ -155,7 +155,7 @@ resources: Properties: ResourceArn: !GetAtt CognitoUserPool.Arn WebACLArn: !GetAtt WafPluginAcl.Arn - + CognitoUserPoolClient: Type: AWS::Cognito::UserPoolClient Properties: diff --git a/services/ui/serverless.yml b/services/ui/serverless.yml index 9aa4aac9f..13789d277 100644 --- a/services/ui/serverless.yml +++ b/services/ui/serverless.yml @@ -11,9 +11,9 @@ provider: name: aws runtime: nodejs20.x region: us-east-1 - stackTags: + stackTags: PROJECT: ${self:custom.project} - SERVICE: ${self:service} + SERVICE: ${self:service} custom: project: "seds" diff --git a/src/run.ts b/src/run.ts index 0da3b3dd0..e7def9080 100644 --- a/src/run.ts +++ b/src/run.ts @@ -209,7 +209,7 @@ async function deploy(options: { stage: string }) { const stage = options.stage; const runner = new LabeledProcessRunner(); await prepare_services(runner); - const deployCmd = ["cdk", "deploy", "--context", `stage=${stage}`, "--all"]; + const deployCmd = ["cdk", "deploy", "--context", `stage=${stage}`, "--method=direct", "--all"]; await runner.run_command_and_output("CDK deploy", deployCmd, "."); }