mirror of https://github.com/docusealco/docuseal
				
				
				
			
							parent
							
								
									a317c030a1
								
							
						
					
					
						commit
						e39ab1fba3
					
				| @ -0,0 +1,5 @@ | ||||
| node_modules | ||||
| 
 | ||||
| # CDK asset staging directory | ||||
| .cdk.staging | ||||
| cdk.out | ||||
| @ -0,0 +1,3 @@ | ||||
| # CDK asset staging directory | ||||
| .cdk.staging | ||||
| cdk.out | ||||
| @ -0,0 +1,153 @@ | ||||
| # CP Docuseal CDK Infrastructure | ||||
| 
 | ||||
| This directory contains AWS CDK v2 infrastructure code for deploying the CP Docuseal app. At present it only deploys to development and staging; production will follow. | ||||
| 
 | ||||
| ## Architecture Overview | ||||
| 
 | ||||
| This infrastructure is basically nicked wholesale from the Integration Station application, just dialed down a notch as our needs are a bit less than theirs. | ||||
| 
 | ||||
| - **Internal Application Load Balancer (ALB)** - Routes traffic to ECS services within the VPC | ||||
| - **Amazon ECS Cluster** - Runs containerized applications on EC2 instances (ARM64 t4g.small) | ||||
| - **ECS Service** - Manages container deployment and scaling | ||||
| - **ECS Task Definition** - Defines container configuration and resource requirements | ||||
| - **CloudWatch Logging** - Centralized logging for application monitoring | ||||
| - **Security Groups** - Network security controls | ||||
| - **ECR Integration** - Uses existing "integration-station" ECR repository | ||||
| 
 | ||||
| ## Prerequisites | ||||
| 
 | ||||
| 1. **AWS CLI** configured with appropriate permissions | ||||
| 2. **Node.js** (version 22 or later) | ||||
| 3. **AWS CDK v2** installed globally: `npm install -g aws-cdk` | ||||
| 4. **Existing AWS Infrastructure**: | ||||
|    - VPC with public and private subnets | ||||
|    - ECR repository named "cp-docuseal" | ||||
|    - Appropriate IAM permissions for CDK deployment | ||||
| 
 | ||||
| ## Setup | ||||
| 
 | ||||
| 1. **Install dependencies**: | ||||
|    ```bash | ||||
|    cd cdk_deploy | ||||
|    npm install | ||||
|    ``` | ||||
| 
 | ||||
| 2. **Bootstrap CDK** (application setup ONLY): | ||||
|    ```bash | ||||
|    npm run bootstrap | ||||
|    ``` | ||||
| 
 | ||||
| 3. **Update VPC and Subnet IDs**: | ||||
|    Edit `app.js` and replace the placeholder IDs with your actual VPC and subnet IDs: | ||||
|    ```javascript | ||||
|    vpcId: 'vpc-your-actual-vpc-id', | ||||
|    privateSubnetIds: ['subnet-your-private-1', 'subnet-your-private-2'], | ||||
|    publicSubnetIds: ['subnet-your-public-1', 'subnet-your-public-2'] | ||||
|    ``` | ||||
| 
 | ||||
| ## Environment Configuration | ||||
| 
 | ||||
| The infrastructure supports three environments with different resource allocations: | ||||
| 
 | ||||
| ### Development | ||||
| - **Instances**: 1 ECS instance | ||||
| - **CPU**: 512 units | ||||
| - **Memory**: 1024 MB | ||||
| 
 | ||||
| ### Staging | ||||
| - **Instances**: 1 ECS instance | ||||
| - **CPU**: 512 units | ||||
| - **Memory**: 1024 MB | ||||
| 
 | ||||
| ### Production | ||||
| - N/A | ||||
| 
 | ||||
| 
 | ||||
| ## Deployment | ||||
| 
 | ||||
| ### Deploy to Development | ||||
| ```bash | ||||
| npm run deploy:dev | ||||
| ``` | ||||
| 
 | ||||
| ### Deploy to Staging | ||||
| ```bash | ||||
| npm run deploy:staging | ||||
| ``` | ||||
| 
 | ||||
| ### Deploy to Production - NOT YET SUPPORTED | ||||
| ```bash | ||||
| npm run deploy:prod | ||||
| ``` | ||||
| 
 | ||||
| ### View CloudFormation Template | ||||
| ```bash | ||||
| npm run synth | ||||
| ``` | ||||
| 
 | ||||
| ### Compare Changes | ||||
| ```bash | ||||
| npm run diff | ||||
| ``` | ||||
| 
 | ||||
| ## Cleanup | ||||
| 
 | ||||
| ### Destroy Development Environment | ||||
| ```bash | ||||
| npm run destroy:dev | ||||
| ``` | ||||
| 
 | ||||
| ### Destroy Staging Environment | ||||
| ```bash | ||||
| npm run destroy:staging | ||||
| ``` | ||||
| 
 | ||||
| ### Destroy Production Environment - NOT YET SUPPORTED | ||||
| ```bash | ||||
| npm run destroy:prod | ||||
| ``` | ||||
| 
 | ||||
| ## Important Notes | ||||
| 
 | ||||
| 1. **Internal ALB**: The Application Load Balancer is configured as internal-only and deployed in private subnets for security. | ||||
| 
 | ||||
| 2. **ARM64 Instances**: The ECS cluster uses t4g.small ARM64 instances for cost efficiency. Ensure your container images are built for ARM64 architecture. | ||||
| 
 | ||||
| 3. **Health Checks**: The ALB target group is configured to perform health checks on `/health` endpoint. Make sure your application responds to this endpoint. | ||||
| 
 | ||||
| 4. **Logging**: All ECS tasks automatically log to CloudWatch under `/ecs/cp-docuseal-{environment}` log groups. | ||||
| 
 | ||||
| 5. **Security**: Security groups are configured to allow: | ||||
|    - ALB: HTTP (80) and HTTPS (443) traffic | ||||
|    - ECS: Traffic from ALB on port 3000 | ||||
| 
 | ||||
| ## Troubleshooting | ||||
| 
 | ||||
| 1. **VPC Lookup Issues**: Ensure the VPC IDs and subnet IDs in `app.js` are correct and exist in your AWS account. | ||||
| 
 | ||||
| 2. **ECR Repository**: Verify that the "cp-docuseal" ECR repository exists and contains the required Docker images. | ||||
| 
 | ||||
| 3. **Permissions**: Ensure your AWS credentials have sufficient permissions for: | ||||
|    - EC2 (VPC, Security Groups, Launch Templates) | ||||
|    - ECS (Clusters, Services, Tasks) | ||||
|    - ELB (Application Load Balancers, Target Groups) | ||||
|    - CloudWatch (Log Groups) | ||||
|    - IAM (Roles and Policies) | ||||
| 
 | ||||
| 4. **Container Health**: If services fail to start, check CloudWatch logs for container startup issues. | ||||
| 
 | ||||
| ## Customization | ||||
| 
 | ||||
| You can modify the following aspects: | ||||
| 
 | ||||
| - **Instance Types**: Change `ec2.InstanceClass.T4G` and `ec2.InstanceSize.SMALL` in the stack | ||||
| - **Container Port**: Update port mappings if your application uses a different port | ||||
| - **Resource Limits**: Adjust CPU and memory allocations in the environment configurations | ||||
| - **Auto Scaling**: Modify `minCapacity` and `maxCapacity` for different scaling behaviors | ||||
| 
 | ||||
| ## Stack Outputs | ||||
| 
 | ||||
| After deployment, the stack provides: | ||||
| - **ALB DNS Name**: Internal DNS name for the Application Load Balancer | ||||
| - **ECS Cluster Name**: Name of the created ECS cluster | ||||
| - **ECS Service Name**: Name of the ECS service  | ||||
| @ -0,0 +1,109 @@ | ||||
| #!/usr/bin/env node
 | ||||
| 
 | ||||
| const { App } = require('aws-cdk-lib'); | ||||
| const { CPDocusealStack } = require('./lib/cp-docuseal-stack'); | ||||
| const fs = require('fs'); | ||||
| 
 | ||||
| const app = new App(); | ||||
| 
 | ||||
| const userDataScript = fs.readFileSync('./userdata.txt', 'utf8'); | ||||
| 
 | ||||
| // Get staging number from context if provided
 | ||||
| const stagingNumber = app.node.tryGetContext('stagingNumber'); | ||||
| 
 | ||||
| // Function to get certificate ARN based on staging number
 | ||||
| function getStagingCertificateArn(stagingNumber) { | ||||
|   if (!stagingNumber) { | ||||
|     // Default certificate for staging when no staging number is provided
 | ||||
|     return 'arn:aws:acm:us-east-1:788066832395:certificate/5b1f59b9-ab27-4056-a5e2-0d89554e5f35'; | ||||
|   } | ||||
| 
 | ||||
|   const num = parseInt(stagingNumber); | ||||
| 
 | ||||
|   if (num >= 1 && num <= 11) { | ||||
|     return 'arn:aws:acm:us-east-1:788066832395:certificate/d3ae2320-6da3-4a6f-a3d9-0f00f85033cb'; | ||||
|   } else if (num >= 12 && num <= 22) { | ||||
|     return 'arn:aws:acm:us-east-1:788066832395:certificate/5b1f59b9-ab27-4056-a5e2-0d89554e5f35'; | ||||
|   } else if (num >= 23 && num <= 24) { | ||||
|     return 'arn:aws:acm:us-east-1:788066832395:certificate/69a8fe61-f12f-4251-9e55-d68c21553388'; | ||||
|   } else if (num >= 25 && num <= 27) { | ||||
|     return 'arn:aws:acm:us-east-1:788066832395:certificate/3ce231d1-b2ec-4013-80db-b231db5a1e02'; | ||||
|   } else { | ||||
|     // Default certificate for staging numbers outside defined ranges
 | ||||
|     return 'arn:aws:acm:us-east-1:788066832395:certificate/5b1f59b9-ab27-4056-a5e2-0d89554e5f35'; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // Environment configurations
 | ||||
| const environments = { | ||||
|   dev: { | ||||
|     account: process.env.CDK_DEFAULT_ACCOUNT, | ||||
|     region: process.env.CDK_DEFAULT_REGION || 'us-east-1', | ||||
|     vpcId: 'vpc-95c19df2', | ||||
|     publicSubnetIds: ['subnet-ff02dbb6', 'subnet-69fe1132', 'subnet-cb8e63f7' ], | ||||
|     instanceCount: 1, | ||||
|     instanceSize: 'SMALL', | ||||
|     cpu: 512, | ||||
|     memory: 1024, | ||||
|     securityGroupIds: ["sg-0f0da2fa2d6088742", "sg-006e8df67aec60469"], | ||||
|     userDataScript: userDataScript, | ||||
|     certificateArn: 'arn:aws:acm:us-east-1:788066832395:certificate/5b1f59b9-ab27-4056-a5e2-0d89554e5f35', | ||||
|   }, | ||||
|   staging: { | ||||
|     account: process.env.CDK_DEFAULT_ACCOUNT, | ||||
|     region: process.env.CDK_DEFAULT_REGION || 'us-east-1', | ||||
|     vpcId: 'vpc-95c19df2', | ||||
|     publicSubnetIds: ['subnet-ff02dbb6', 'subnet-69fe1132', 'subnet-cb8e63f7'], | ||||
|     instanceCount: 1, | ||||
|     instanceSize: 'SMALL', | ||||
|     apiCpu: 512, | ||||
|     apiMemory: 1024, | ||||
|     securityGroupIds: ["sg-0f0da2fa2d6088742", "sg-006e8df67aec60469"], | ||||
|     userDataScript: userDataScript, | ||||
|     certificateArn: getStagingCertificateArn(stagingNumber), | ||||
|   }, | ||||
|   // production: {
 | ||||
|   //   account: process.env.CDK_DEFAULT_ACCOUNT,
 | ||||
|   //   region: process.env.CDK_DEFAULT_REGION || 'us-east-1',
 | ||||
|   //   vpcId: 'vpc-95c19df2',
 | ||||
|   //   publicSubnetIds: ['subnet-ff02dbb6', 'subnet-69fe1132', 'subnet-cb8e63f7' ],
 | ||||
|   //   instanceCount: 2,
 | ||||
|   //   instanceSize: 'LARGE',
 | ||||
|   //   apiCpu: 900,
 | ||||
|   //   apiMemory: 3000,
 | ||||
|   //   sidekiqCpu: 900,
 | ||||
|   //   sidekiqMemory: 3000,
 | ||||
|   //   securityGroupIds: ["sg-09fa17711757036e6", "sg-006e8df67aec60469"],
 | ||||
|   //   userDataScript: userDataScript,
 | ||||
|   //   certificateArn: 'arn:aws:acm:us-east-1:788066832395:certificate/05fa2bb8-5589-4425-9f28-427f1082a64b',
 | ||||
|   // }
 | ||||
| }; | ||||
| 
 | ||||
| // Create stacks for each environment
 | ||||
| Object.entries(environments).forEach(([envName, config]) => { | ||||
|   // Construct stack name with staging number if provided
 | ||||
|   let stackName = `CPDocusealStack-${envName}`; | ||||
|   let environmentName = envName; | ||||
| 
 | ||||
|   // Append staging number for staging environments
 | ||||
|   if (envName === 'staging' && stagingNumber) { | ||||
|     stackName += `-${stagingNumber}`; | ||||
|     environmentName += `-${stagingNumber}`; | ||||
|   } | ||||
| 
 | ||||
|   new CPDocusealStack(app, stackName, { | ||||
|     env: { | ||||
|       account: config.account, | ||||
|       region: config.region | ||||
|     }, | ||||
|     environment: envName, | ||||
|     vpcConfig: { | ||||
|       vpcId: config.vpcId, | ||||
|       publicSubnetIds: config.publicSubnetIds | ||||
|     }, | ||||
|     ecsConfig: config, | ||||
|     certificateArn: config.certificateArn, | ||||
|     securityGroupIds: config.securityGroupIds, | ||||
|     userDataScript: config.userDataScript | ||||
|   }); | ||||
| });  | ||||
| @ -0,0 +1,82 @@ | ||||
| { | ||||
|   "vpc-provider:account=788066832395:filter.vpc-id=vpc-95c19df2:region=us-east-1:returnAsymmetricSubnets=true": { | ||||
|     "vpcId": "vpc-95c19df2", | ||||
|     "vpcCidrBlock": "172.30.0.0/16", | ||||
|     "ownerAccountId": "788066832395", | ||||
|     "availabilityZones": [], | ||||
|     "subnetGroups": [ | ||||
|       { | ||||
|         "name": "Public", | ||||
|         "type": "Public", | ||||
|         "subnets": [ | ||||
|           { | ||||
|             "subnetId": "subnet-ff02dbb6", | ||||
|             "cidr": "172.30.0.0/24", | ||||
|             "availabilityZone": "us-east-1a", | ||||
|             "routeTableId": "rtb-27219141" | ||||
|           }, | ||||
|           { | ||||
|             "subnetId": "subnet-69fe1132", | ||||
|             "cidr": "172.30.1.0/24", | ||||
|             "availabilityZone": "us-east-1b", | ||||
|             "routeTableId": "rtb-27219141" | ||||
|           }, | ||||
|           { | ||||
|             "subnetId": "subnet-95927bb8", | ||||
|             "cidr": "172.30.2.0/24", | ||||
|             "availabilityZone": "us-east-1d", | ||||
|             "routeTableId": "rtb-27219141" | ||||
|           }, | ||||
|           { | ||||
|             "subnetId": "subnet-0a1feb6c1333efbab", | ||||
|             "cidr": "172.30.8.0/24", | ||||
|             "availabilityZone": "us-east-1d", | ||||
|             "routeTableId": "rtb-27219141" | ||||
|           }, | ||||
|           { | ||||
|             "subnetId": "subnet-cb8e63f7", | ||||
|             "cidr": "172.30.3.0/24", | ||||
|             "availabilityZone": "us-east-1e", | ||||
|             "routeTableId": "rtb-27219141" | ||||
|           }, | ||||
|           { | ||||
|             "subnetId": "subnet-0f5743e7967df31ef", | ||||
|             "cidr": "172.30.4.0/24", | ||||
|             "availabilityZone": "us-east-1f", | ||||
|             "routeTableId": "rtb-27219141" | ||||
|           }, | ||||
|           { | ||||
|             "subnetId": "subnet-0118637ce4cf80f0a", | ||||
|             "cidr": "172.30.10.0/24", | ||||
|             "availabilityZone": "us-east-1f", | ||||
|             "routeTableId": "rtb-27219141" | ||||
|           } | ||||
|         ] | ||||
|       }, | ||||
|       { | ||||
|         "name": "Private", | ||||
|         "type": "Private", | ||||
|         "subnets": [ | ||||
|           { | ||||
|             "subnetId": "subnet-0a263997449735cfd", | ||||
|             "cidr": "172.30.5.0/24", | ||||
|             "availabilityZone": "us-east-1a", | ||||
|             "routeTableId": "rtb-07ee1e39f005b06f2" | ||||
|           }, | ||||
|           { | ||||
|             "subnetId": "subnet-05e98535001316fe8", | ||||
|             "cidr": "172.30.6.0/24", | ||||
|             "availabilityZone": "us-east-1b", | ||||
|             "routeTableId": "rtb-07ee1e39f005b06f2" | ||||
|           }, | ||||
|           { | ||||
|             "subnetId": "subnet-0bcf29b2a2a47fbb7", | ||||
|             "cidr": "172.30.9.0/24", | ||||
|             "availabilityZone": "us-east-1e", | ||||
|             "routeTableId": "rtb-07ee1e39f005b06f2" | ||||
|           } | ||||
|         ] | ||||
|       } | ||||
|     ] | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,64 @@ | ||||
| { | ||||
|   "app": "node app.js", | ||||
|   "watch": { | ||||
|     "include": [ | ||||
|       "**" | ||||
|     ], | ||||
|     "exclude": [ | ||||
|       "README.md", | ||||
|       "cdk*.json", | ||||
|       "**/*.js", | ||||
|       "package*.json", | ||||
|       "yarn.lock", | ||||
|       "node_modules" | ||||
|     ] | ||||
|   }, | ||||
|   "context": { | ||||
|     "@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-iam:standardizedServicePrincipals": 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:enableLoggingConfiguration": true, | ||||
|     "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, | ||||
|     "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, | ||||
|     "@aws-cdk/aws-kms:aliasNameRef": true, | ||||
|     "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true, | ||||
|     "@aws-cdk/core:includePrefixInUniqueNameGeneration": true, | ||||
|     "@aws-cdk/aws-efs:denyAnonymousAccess": true, | ||||
|     "@aws-cdk/aws-opensearchservice:enableLogging": true, | ||||
|     "@aws-cdk/aws-noralization:emptyOperationContext": true, | ||||
|     "@aws-cdk/aws-lambda:codecommitPolicyDefaultTargetsBranch": true, | ||||
|     "@aws-cdk/aws-lambda:recognizeVersionProps": true, | ||||
|     "@aws-cdk/aws-cloudformation:parseParamsAndSecretsConfiguration": true, | ||||
|     "@aws-cdk/aws-eks:nodegroupNameAttribute": true, | ||||
|     "@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true, | ||||
|     "@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions": true, | ||||
|     "@aws-cdk/aws-ec2:disableSubnetCreateDefaultRouteToIgw": true, | ||||
|     "@aws-cdk/aws-ec2:ipv4IpamPoolPublicIpSource": true | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,382 @@ | ||||
| const { | ||||
|   Stack, | ||||
|   Duration, | ||||
|   aws_ec2: ec2, | ||||
|   aws_ecs: ecs, | ||||
|   aws_elasticloadbalancingv2: elbv2, | ||||
|   aws_logs: logs, | ||||
|   aws_iam: iam, | ||||
|   aws_ecr: ecr, | ||||
|   aws_secretsmanager: secretsmanager, | ||||
|   aws_certificatemanager: acm, | ||||
|   aws_route53: route53, | ||||
|   aws_route53_targets: targets, | ||||
|   Aspects, | ||||
|   RemovalPolicy | ||||
| } = require('aws-cdk-lib'); | ||||
| const { Construct } = require('constructs'); | ||||
| 
 | ||||
| class CPDocusealStack extends Stack { | ||||
|   constructor(scope, id, props) { | ||||
|     super(scope, id, props); | ||||
| 
 | ||||
|     const { environment, vpcConfig, ecsConfig, securityGroupIds, userDataScript } = props; | ||||
|      | ||||
|     // Get the image tag from CDK context, default to 'latest' if not provided
 | ||||
|     const imageTag = this.node.tryGetContext('imageTag') || 'latest'; | ||||
|     const stagingNumber = this.node.tryGetContext('stagingNumber') || null; | ||||
|     const envDescription = stagingNumber ? `${environment}-${stagingNumber}` : environment; | ||||
| 
 | ||||
|     // Import existing VPC
 | ||||
|     const vpc = ec2.Vpc.fromLookup(this, 'VPC', { | ||||
|       vpcId: vpcConfig.vpcId | ||||
|     }); | ||||
| 
 | ||||
|     // Import existing subnets
 | ||||
|     const publicSubnets = vpcConfig.publicSubnetIds.map((subnetId, index) => | ||||
|       ec2.Subnet.fromSubnetId(this, `PublicSubnet${index}`, subnetId) | ||||
|     ); | ||||
| 
 | ||||
|     // Security Group for ALB
 | ||||
|     const albSecurityGroup = new ec2.SecurityGroup(this, 'ALBSecurityGroup', { | ||||
|       vpc, | ||||
|       description: `ALB Security Group for ${envDescription}`, | ||||
|       allowAllOutbound: true | ||||
|     }); | ||||
| 
 | ||||
|     // we may not need this...
 | ||||
|     albSecurityGroup.addIngressRule( | ||||
|       ec2.Peer.anyIpv4(), | ||||
|       ec2.Port.tcp(80), | ||||
|       'Allow HTTP traffic' | ||||
|     ); | ||||
| 
 | ||||
|     albSecurityGroup.addIngressRule( | ||||
|       ec2.Peer.anyIpv4(), | ||||
|       ec2.Port.tcp(443), | ||||
|       'Allow HTTPS traffic' | ||||
|     ); | ||||
| 
 | ||||
|     // Security Group for ECS Tasks
 | ||||
|     const ecsSecurityGroup = new ec2.SecurityGroup(this, 'ECSSecurityGroup', { | ||||
|       vpc, | ||||
|       description: `ECS Security Group for ${envDescription}`, | ||||
|       allowAllOutbound: true | ||||
|     }); | ||||
| 
 | ||||
|     ecsSecurityGroup.addIngressRule( | ||||
|       albSecurityGroup, | ||||
|       ec2.Port.tcp(3001), | ||||
|       'Allow traffic from ALB' | ||||
|     ); | ||||
| 
 | ||||
|     // Internal Application Load Balancer
 | ||||
|     const alb = new elbv2.ApplicationLoadBalancer(this, 'InternalALB', { | ||||
|       vpc, | ||||
|       internetFacing: true, | ||||
|       vpcSubnets: { | ||||
|         subnets: publicSubnets | ||||
|       }, | ||||
|       securityGroup: albSecurityGroup, | ||||
|       loadBalancerName: `cpd-alb-${envDescription}` | ||||
|     }); | ||||
| 
 | ||||
|     // Target Group for ECS Service
 | ||||
|     const targetGroup = new elbv2.ApplicationTargetGroup(this, 'ECSTargetGroup', { | ||||
|       vpc, | ||||
|       port: 3001, | ||||
|       protocol: elbv2.ApplicationProtocol.HTTP, | ||||
|       targetType: elbv2.TargetType.INSTANCE, | ||||
|       healthCheck: { | ||||
|         enabled: true, | ||||
|         healthyHttpCodes: '200', | ||||
|         path: '/up', | ||||
|         protocol: elbv2.Protocol.HTTP, | ||||
|         interval: Duration.seconds(30), | ||||
|         timeout: Duration.seconds(5), | ||||
|         healthyThresholdCount: 2, | ||||
|         unhealthyThresholdCount: 5 | ||||
|       }, | ||||
|       deregistrationDelay: Duration.seconds(20), | ||||
|       targetGroupName: `cpd-tg-${envDescription}` | ||||
|     }); | ||||
| 
 | ||||
|     // ALB Listener
 | ||||
|     const listener = alb.addListener('ALBListener', { | ||||
|       port: 80, | ||||
|       protocol: elbv2.ApplicationProtocol.HTTP, | ||||
|       defaultTargetGroups: [targetGroup] | ||||
|     }); | ||||
| 
 | ||||
|     // Accept certificateArn as input (default to provided value if not in props)
 | ||||
|     const certificateArn = props.certificateArn || 'arn:aws:acm:us-east-1:788066832395:certificate/05fa2bb8-5589-4425-9f28-427f1082a64b'; | ||||
| 
 | ||||
|     // Add HTTPS Listener with ACM certificate
 | ||||
|     const certificate = acm.Certificate.fromCertificateArn(this, 'ALBCertificate', certificateArn); | ||||
|     alb.addListener('ALBListenerHTTPS', { | ||||
|       port: 443, | ||||
|       protocol: elbv2.ApplicationProtocol.HTTPS, | ||||
|       certificates: [certificate], | ||||
|       defaultTargetGroups: [targetGroup] | ||||
|     }); | ||||
| 
 | ||||
|     // Create Route53 A record for staging and production environments
 | ||||
|     let hostedZoneDomain = null; | ||||
|      | ||||
|     if (environment === 'staging' && stagingNumber) { | ||||
|       hostedZoneDomain = `cpstaging${stagingNumber}.name`; | ||||
|     // } else if (environment === 'production') {
 | ||||
|     //   hostedZoneDomain = 'careerplug.com';
 | ||||
|     } | ||||
| 
 | ||||
|     if (hostedZoneDomain) { | ||||
|       const recordName = 'cpd'; | ||||
| 
 | ||||
|       // Import the existing hosted zone
 | ||||
|       const hostedZone = route53.HostedZone.fromLookup(this, 'HostedZone', { | ||||
|         domainName: hostedZoneDomain | ||||
|       }); | ||||
| 
 | ||||
|       // Create A record pointing to ALB
 | ||||
|       new route53.ARecord(this, 'ALBARecord', { | ||||
|         zone: hostedZone, | ||||
|         recordName: recordName, | ||||
|         target: route53.RecordTarget.fromAlias(new targets.LoadBalancerTarget(alb)), | ||||
|         ttl: Duration.minutes(1), | ||||
|         comment: `A record for CP Docuseal ${envDescription}` | ||||
|       }); | ||||
|     } | ||||
| 
 | ||||
|     // ECS Cluster
 | ||||
|     const cluster = new ecs.Cluster(this, 'ECSCluster', { | ||||
|       vpc, | ||||
|       clusterName: `cp-docuseal-${envDescription}`, | ||||
|       containerInsightsV2: ecs.ContainerInsights.ENABLED | ||||
|     }); | ||||
| 
 | ||||
|     // Determine instance size based on configuration
 | ||||
|     const instanceSize = ecsConfig.instanceSize || 'SMALL'; | ||||
|      | ||||
|     // Import additional existing security groups by ID from props
 | ||||
|     const importedSecurityGroups = (securityGroupIds || []).map((sgId, idx) => | ||||
|       ec2.SecurityGroup.fromSecurityGroupId(this, `ImportedSG${idx + 1}`, sgId) | ||||
|     ); | ||||
| 
 | ||||
|     // Auto Scaling Group for ECS with ARM64 instances
 | ||||
|     const autoScalingGroup = cluster.addCapacity('ECSAutoScalingGroup', { | ||||
|       instanceType: ec2.InstanceType.of(ec2.InstanceClass.T4G, ec2.InstanceSize[instanceSize]), // ARM64
 | ||||
|       machineImage: ecs.EcsOptimizedImage.amazonLinux2(ecs.AmiHardwareType.ARM), | ||||
|       minCapacity: ecsConfig.instanceCount, | ||||
|       maxCapacity: ecsConfig.instanceCount, | ||||
|       vpcSubnets: { | ||||
|         subnets: publicSubnets | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
|     // Attach imported security groups to the EC2 instances
 | ||||
|     importedSecurityGroups.forEach((sg, idx) => { | ||||
|       autoScalingGroup.addSecurityGroup(sg); | ||||
|     }); | ||||
| 
 | ||||
|     // Add security group rule to EC2 instances for HOST network mode
 | ||||
|     // Allow ALB to reach containers on port 3001
 | ||||
|     autoScalingGroup.addSecurityGroup(ecsSecurityGroup); | ||||
| 
 | ||||
|     if (userDataScript) { | ||||
|       autoScalingGroup.addUserData(userDataScript); | ||||
|     } | ||||
| 
 | ||||
|     // CloudWatch Log Groups
 | ||||
|     const apiLogGroup = new logs.LogGroup(this, 'APILogGroup', { | ||||
|       logGroupName: `/ecs/cp-docuseal-api-${envDescription}`, | ||||
|       retention: logs.RetentionDays.ONE_WEEK | ||||
|     }); | ||||
|     apiLogGroup.applyRemovalPolicy(RemovalPolicy.DESTROY); | ||||
| 
 | ||||
|     // const sidekiqLogGroup = new logs.LogGroup(this, 'SidekiqLogGroup', {
 | ||||
|     //   logGroupName: `/ecs/cp-docuseal-sidekiq-${envDescription}`,
 | ||||
|     //   retention: logs.RetentionDays.ONE_WEEK
 | ||||
|     // });
 | ||||
|     // sidekiqLogGroup.applyRemovalPolicy(RemovalPolicy.DESTROY);
 | ||||
| 
 | ||||
|     // Import ECR Repository
 | ||||
|     const ecrRepository = ecr.Repository.fromRepositoryName( | ||||
|       this, | ||||
|       'ECRRepository', | ||||
|       'cp-docuseal' | ||||
|     ); | ||||
| 
 | ||||
|     // Task Definition
 | ||||
|     const taskDefinition = new ecs.Ec2TaskDefinition(this, 'TaskDefinition', { | ||||
|       family: `cp-docuseal-task-${envDescription}`, | ||||
|       networkMode: ecs.NetworkMode.HOST | ||||
|     }); | ||||
| 
 | ||||
|     // Base environment variables
 | ||||
|     const containerEnvironment = { | ||||
|       NODE_ENV: environment, | ||||
|       PORT: '3001', | ||||
|       RAILS_ENV: environment | ||||
|     }; | ||||
| 
 | ||||
|     // Add environment-specific variables
 | ||||
|     if (environment === 'staging') { // || environment === 'production') {
 | ||||
|       // For staging and production, we'll use Secrets Manager
 | ||||
|       containerEnvironment.AWS_REGION = this.region; | ||||
|       // Map production environment to prod for secret naming
 | ||||
|       const secretEnvironment = environment; // === 'production' ? 'prod' : environment;
 | ||||
|       containerEnvironment.DB_SECRETS_NAME = `${secretEnvironment}/db_creds`; | ||||
| 
 | ||||
|       // set DB name
 | ||||
|       containerEnvironment.DB_NAME = `cpdocuseal${stagingNumber ? `${stagingNumber}` : ''}`; | ||||
|     } | ||||
| 
 | ||||
|     // Check if we need multi-container setup (staging and production)
 | ||||
|     const isMultiContainer = environment === 'staging'; // || environment === 'production';
 | ||||
| 
 | ||||
|     if (isMultiContainer) { | ||||
|       // API Container Definition
 | ||||
|       const apiContainerConfig = { | ||||
|         image: ecs.ContainerImage.fromEcrRepository(ecrRepository, imageTag), | ||||
|         cpu: ecsConfig.apiCpu, | ||||
|         memoryLimitMiB: ecsConfig.apiMemory, | ||||
|         essential: true, | ||||
|         logging: ecs.LogDrivers.awsLogs({ | ||||
|           streamPrefix: 'api', | ||||
|           logGroup: apiLogGroup | ||||
|         }), | ||||
|         environment: containerEnvironment, | ||||
|         healthCheck: { | ||||
|           command: ['CMD-SHELL', 'curl -f http://localhost:3001/up || exit 1'], | ||||
|           interval: Duration.seconds(30), | ||||
|           timeout: Duration.seconds(5), | ||||
|           retries: 3, | ||||
|           startPeriod: Duration.seconds(60) | ||||
|         } | ||||
|       }; | ||||
| 
 | ||||
|       // Set the appropriate startup script for staging and production
 | ||||
|       if (environment === 'staging') { | ||||
|         apiContainerConfig.command = ['./bin/start_staging', 'api']; | ||||
|       } | ||||
|       // } else if (environment === 'production') {
 | ||||
|       //   apiContainerConfig.command = ['./bin/start_production', 'api'];
 | ||||
|       // }
 | ||||
| 
 | ||||
|       const apiContainer = taskDefinition.addContainer('APIContainer', apiContainerConfig); | ||||
|        | ||||
|       // Add port mapping for HOST network mode
 | ||||
|       apiContainer.addPortMappings({ | ||||
|         containerPort: 3001, | ||||
|         protocol: ecs.Protocol.TCP | ||||
|       }); | ||||
| 
 | ||||
|       // Sidekiq Container Definition
 | ||||
|       // const sidekiqContainerConfig = {
 | ||||
|       //   image: ecs.ContainerImage.fromEcrRepository(ecrRepository, imageTag),
 | ||||
|       //   cpu: ecsConfig.sidekiqCpu,
 | ||||
|       //   memoryLimitMiB: ecsConfig.sidekiqMemory,
 | ||||
|       //   essential: true,
 | ||||
|       //   logging: ecs.LogDrivers.awsLogs({
 | ||||
|       //     streamPrefix: 'sidekiq',
 | ||||
|       //     logGroup: sidekiqLogGroup
 | ||||
|       //   }),
 | ||||
|       //   environment: containerEnvironment,
 | ||||
|       // };
 | ||||
| 
 | ||||
|       // Set the appropriate startup script for staging and production
 | ||||
|       // if (environment === 'staging') {
 | ||||
|       //   sidekiqContainerConfig.command = ['./bin/start_staging', 'sidekiq'];
 | ||||
|       // } else if (environment === 'production') {
 | ||||
|       //   sidekiqContainerConfig.command = ['./bin/start_production', 'sidekiq'];
 | ||||
|       // }
 | ||||
| 
 | ||||
|       // const sidekiqContainer = taskDefinition.addContainer('SidekiqContainer', sidekiqContainerConfig);
 | ||||
| 
 | ||||
|       // // Make Sidekiq container depend on API container
 | ||||
|       // sidekiqContainer.addContainerDependencies({
 | ||||
|       //   container: apiContainer,
 | ||||
|       //   condition: ecs.ContainerDependencyCondition.HEALTHY
 | ||||
|       // });
 | ||||
| 
 | ||||
|     } else { | ||||
|       // Single container setup for dev environment
 | ||||
|       const containerConfig = { | ||||
|         image: ecs.ContainerImage.fromEcrRepository(ecrRepository, imageTag), | ||||
|         cpu: ecsConfig.cpu, | ||||
|         memoryLimitMiB: ecsConfig.memory, | ||||
|         essential: true, | ||||
|         logging: ecs.LogDrivers.awsLogs({ | ||||
|           streamPrefix: 'ecs', | ||||
|           logGroup: apiLogGroup | ||||
|         }), | ||||
|         environment: containerEnvironment | ||||
|       }; | ||||
| 
 | ||||
|       const container = taskDefinition.addContainer('CPDocusealContainer', containerConfig); | ||||
|        | ||||
|       // Add port mapping for HOST network mode
 | ||||
|       container.addPortMappings({ | ||||
|         containerPort: 3001, | ||||
|         protocol: ecs.Protocol.TCP | ||||
|       }); | ||||
|     } | ||||
| 
 | ||||
|     // ECS Service
 | ||||
|     const service = new ecs.Ec2Service(this, 'ECSService', { | ||||
|       cluster, | ||||
|       taskDefinition, | ||||
|       serviceName: `cp-docuseal-service-${envDescription}`, | ||||
|       desiredCount: ecsConfig.instanceCount, | ||||
|       deploymentConfiguration: { | ||||
|         maximumPercent: 200, | ||||
|         minimumHealthyPercent: 50 | ||||
|       }, | ||||
|       enableExecuteCommand: true // For debugging
 | ||||
|       // vpcSubnets and securityGroups removed - HOST network mode uses EC2 instance network configuration
 | ||||
|     }); | ||||
| 
 | ||||
|     // Attach the service to the target group
 | ||||
|     service.attachToApplicationTargetGroup(targetGroup); | ||||
| 
 | ||||
|     // Task Role for CloudWatch logging and ECR access
 | ||||
|     taskDefinition.taskRole.addManagedPolicy( | ||||
|       iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonECSTaskExecutionRolePolicy') | ||||
|     ); | ||||
| 
 | ||||
|     // Add Secrets Manager permissions for staging and production environments
 | ||||
|     if (environment === 'staging') { // || environment === 'production') {
 | ||||
|       // Map production environment to prod for secret naming
 | ||||
|       const secretEnvironment = environment; // === 'production' ? 'prod' : environment;
 | ||||
|       const secretsManagerPolicy = new iam.PolicyStatement({ | ||||
|         effect: iam.Effect.ALLOW, | ||||
|         actions: [ | ||||
|           'secretsmanager:GetSecretValue', | ||||
|           'secretsmanager:DescribeSecret' | ||||
|         ], | ||||
|         resources: [ | ||||
|           `arn:aws:secretsmanager:${this.region}:${this.account}:secret:${secretEnvironment}/db_creds*`, | ||||
|           // `arn:aws:secretsmanager:${this.region}:${this.account}:secret:integration_station/encryption_key*`
 | ||||
|         ] | ||||
|       }); | ||||
| 
 | ||||
|       taskDefinition.taskRole.addToPolicy(secretsManagerPolicy); | ||||
|     } | ||||
| 
 | ||||
|     // Output important values
 | ||||
|     this.albDnsName = alb.loadBalancerDnsName; | ||||
|     this.clusterName = cluster.clusterName; | ||||
|     this.serviceName = service.serviceName; | ||||
| 
 | ||||
|     // Output Route53 record name for environments that create DNS records
 | ||||
|     if (hostedZoneDomain) { | ||||
|       if (environment === 'staging' && stagingNumber) { | ||||
|         this.route53RecordName = `cpd.cpstaging${stagingNumber}.name`; | ||||
|       // } else if (environment === 'production') {
 | ||||
|       //   this.route53RecordName = 'cpd.careerplug.com';
 | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| module.exports = { CPDocusealStack };  | ||||
| @ -0,0 +1,468 @@ | ||||
| { | ||||
|   "name": "cdk_deploy", | ||||
|   "version": "0.1.0", | ||||
|   "lockfileVersion": 3, | ||||
|   "requires": true, | ||||
|   "packages": { | ||||
|     "": { | ||||
|       "name": "cdk_deploy", | ||||
|       "version": "0.1.0", | ||||
|       "dependencies": { | ||||
|         "aws-cdk-lib": "^2.205.0", | ||||
|         "cdk-nag": "^2.36.22", | ||||
|         "constructs": "^10.3.0" | ||||
|       }, | ||||
|       "bin": { | ||||
|         "cdk_deploy": "bin/cdk_deploy.js" | ||||
|       }, | ||||
|       "devDependencies": { | ||||
|         "aws-cdk": "2.1021.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@aws-cdk/asset-awscli-v1": { | ||||
|       "version": "2.2.242", | ||||
|       "resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.242.tgz", | ||||
|       "integrity": "sha512-4c1bAy2ISzcdKXYS1k4HYZsNrgiwbiDzj36ybwFVxEWZXVAP0dimQTCaB9fxu7sWzEjw3d+eaw6Fon+QTfTIpQ==", | ||||
|       "license": "Apache-2.0" | ||||
|     }, | ||||
|     "node_modules/@aws-cdk/asset-node-proxy-agent-v6": { | ||||
|       "version": "2.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/@aws-cdk/asset-node-proxy-agent-v6/-/asset-node-proxy-agent-v6-2.1.0.tgz", | ||||
|       "integrity": "sha512-7bY3J8GCVxLupn/kNmpPc5VJz8grx+4RKfnnJiO1LG+uxkZfANZG3RMHhE+qQxxwkyQ9/MfPtTpf748UhR425A==", | ||||
|       "license": "Apache-2.0" | ||||
|     }, | ||||
|     "node_modules/@aws-cdk/cloud-assembly-schema": { | ||||
|       "version": "45.2.0", | ||||
|       "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-45.2.0.tgz", | ||||
|       "integrity": "sha512-5TTUkGHQ+nfuUGwKA8/Yraxb+JdNUh4np24qk/VHXmrCMq+M6HfmGWfhcg/QlHA2S5P3YIamfYHdQAB4uSNLAg==", | ||||
|       "bundleDependencies": [ | ||||
|         "jsonschema", | ||||
|         "semver" | ||||
|       ], | ||||
|       "license": "Apache-2.0", | ||||
|       "dependencies": { | ||||
|         "jsonschema": "~1.4.1", | ||||
|         "semver": "^7.7.2" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">= 18.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@aws-cdk/cloud-assembly-schema/node_modules/jsonschema": { | ||||
|       "version": "1.4.1", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": "*" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@aws-cdk/cloud-assembly-schema/node_modules/semver": { | ||||
|       "version": "7.7.2", | ||||
|       "inBundle": true, | ||||
|       "license": "ISC", | ||||
|       "bin": { | ||||
|         "semver": "bin/semver.js" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=10" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk": { | ||||
|       "version": "2.1021.0", | ||||
|       "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1021.0.tgz", | ||||
|       "integrity": "sha512-kE557b4N9UFWax+7km3R6D56o4tGhpzOks/lRDugaoC8su3mocLCXJhb954b/IRl0ipnbZnY/Sftq+RQ/sxivg==", | ||||
|       "dev": true, | ||||
|       "license": "Apache-2.0", | ||||
|       "bin": { | ||||
|         "cdk": "bin/cdk" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">= 18.0.0" | ||||
|       }, | ||||
|       "optionalDependencies": { | ||||
|         "fsevents": "2.3.2" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib": { | ||||
|       "version": "2.205.0", | ||||
|       "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.205.0.tgz", | ||||
|       "integrity": "sha512-GZHy/F8jql+1aFlgIhGQuLl9zHvceHL0VRuBgaYngwWrflHc+ZN3eCEtfzCblA2bXmi4NbLljpSUBIGBVx2EEQ==", | ||||
|       "bundleDependencies": [ | ||||
|         "@balena/dockerignore", | ||||
|         "case", | ||||
|         "fs-extra", | ||||
|         "ignore", | ||||
|         "jsonschema", | ||||
|         "minimatch", | ||||
|         "punycode", | ||||
|         "semver", | ||||
|         "table", | ||||
|         "yaml", | ||||
|         "mime-types" | ||||
|       ], | ||||
|       "license": "Apache-2.0", | ||||
|       "dependencies": { | ||||
|         "@aws-cdk/asset-awscli-v1": "2.2.242", | ||||
|         "@aws-cdk/asset-node-proxy-agent-v6": "^2.1.0", | ||||
|         "@aws-cdk/cloud-assembly-schema": "^45.0.0", | ||||
|         "@balena/dockerignore": "^1.0.2", | ||||
|         "case": "1.6.3", | ||||
|         "fs-extra": "^11.3.0", | ||||
|         "ignore": "^5.3.2", | ||||
|         "jsonschema": "^1.5.0", | ||||
|         "mime-types": "^2.1.35", | ||||
|         "minimatch": "^3.1.2", | ||||
|         "punycode": "^2.3.1", | ||||
|         "semver": "^7.7.2", | ||||
|         "table": "^6.9.0", | ||||
|         "yaml": "1.10.2" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">= 14.15.0" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "constructs": "^10.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/@balena/dockerignore": { | ||||
|       "version": "1.0.2", | ||||
|       "inBundle": true, | ||||
|       "license": "Apache-2.0" | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/ajv": { | ||||
|       "version": "8.17.1", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "fast-deep-equal": "^3.1.3", | ||||
|         "fast-uri": "^3.0.1", | ||||
|         "json-schema-traverse": "^1.0.0", | ||||
|         "require-from-string": "^2.0.2" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "github", | ||||
|         "url": "https://github.com/sponsors/epoberezkin" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/ansi-regex": { | ||||
|       "version": "5.0.1", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">=8" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/ansi-styles": { | ||||
|       "version": "4.3.0", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "color-convert": "^2.0.1" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=8" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "url": "https://github.com/chalk/ansi-styles?sponsor=1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/astral-regex": { | ||||
|       "version": "2.0.0", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">=8" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/balanced-match": { | ||||
|       "version": "1.0.2", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/brace-expansion": { | ||||
|       "version": "1.1.12", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "balanced-match": "^1.0.0", | ||||
|         "concat-map": "0.0.1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/case": { | ||||
|       "version": "1.6.3", | ||||
|       "inBundle": true, | ||||
|       "license": "(MIT OR GPL-3.0-or-later)", | ||||
|       "engines": { | ||||
|         "node": ">= 0.8.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/color-convert": { | ||||
|       "version": "2.0.1", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "color-name": "~1.1.4" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=7.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/color-name": { | ||||
|       "version": "1.1.4", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/concat-map": { | ||||
|       "version": "0.0.1", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/emoji-regex": { | ||||
|       "version": "8.0.0", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/fast-deep-equal": { | ||||
|       "version": "3.1.3", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/fast-uri": { | ||||
|       "version": "3.0.6", | ||||
|       "funding": [ | ||||
|         { | ||||
|           "type": "github", | ||||
|           "url": "https://github.com/sponsors/fastify" | ||||
|         }, | ||||
|         { | ||||
|           "type": "opencollective", | ||||
|           "url": "https://opencollective.com/fastify" | ||||
|         } | ||||
|       ], | ||||
|       "inBundle": true, | ||||
|       "license": "BSD-3-Clause" | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/fs-extra": { | ||||
|       "version": "11.3.0", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "graceful-fs": "^4.2.0", | ||||
|         "jsonfile": "^6.0.1", | ||||
|         "universalify": "^2.0.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=14.14" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/graceful-fs": { | ||||
|       "version": "4.2.11", | ||||
|       "inBundle": true, | ||||
|       "license": "ISC" | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/ignore": { | ||||
|       "version": "5.3.2", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">= 4" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/is-fullwidth-code-point": { | ||||
|       "version": "3.0.0", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">=8" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/json-schema-traverse": { | ||||
|       "version": "1.0.0", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/jsonfile": { | ||||
|       "version": "6.1.0", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "universalify": "^2.0.0" | ||||
|       }, | ||||
|       "optionalDependencies": { | ||||
|         "graceful-fs": "^4.1.6" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/jsonschema": { | ||||
|       "version": "1.5.0", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": "*" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/lodash.truncate": { | ||||
|       "version": "4.4.2", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/mime-db": { | ||||
|       "version": "1.52.0", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">= 0.6" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/mime-types": { | ||||
|       "version": "2.1.35", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "mime-db": "1.52.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">= 0.6" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/minimatch": { | ||||
|       "version": "3.1.2", | ||||
|       "inBundle": true, | ||||
|       "license": "ISC", | ||||
|       "dependencies": { | ||||
|         "brace-expansion": "^1.1.7" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": "*" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/punycode": { | ||||
|       "version": "2.3.1", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">=6" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/require-from-string": { | ||||
|       "version": "2.0.2", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">=0.10.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/semver": { | ||||
|       "version": "7.7.2", | ||||
|       "inBundle": true, | ||||
|       "license": "ISC", | ||||
|       "bin": { | ||||
|         "semver": "bin/semver.js" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=10" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/slice-ansi": { | ||||
|       "version": "4.0.0", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "ansi-styles": "^4.0.0", | ||||
|         "astral-regex": "^2.0.0", | ||||
|         "is-fullwidth-code-point": "^3.0.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=10" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "url": "https://github.com/chalk/slice-ansi?sponsor=1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/string-width": { | ||||
|       "version": "4.2.3", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "emoji-regex": "^8.0.0", | ||||
|         "is-fullwidth-code-point": "^3.0.0", | ||||
|         "strip-ansi": "^6.0.1" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=8" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/strip-ansi": { | ||||
|       "version": "6.0.1", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "ansi-regex": "^5.0.1" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=8" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/table": { | ||||
|       "version": "6.9.0", | ||||
|       "inBundle": true, | ||||
|       "license": "BSD-3-Clause", | ||||
|       "dependencies": { | ||||
|         "ajv": "^8.0.1", | ||||
|         "lodash.truncate": "^4.4.2", | ||||
|         "slice-ansi": "^4.0.0", | ||||
|         "string-width": "^4.2.3", | ||||
|         "strip-ansi": "^6.0.1" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=10.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/universalify": { | ||||
|       "version": "2.0.1", | ||||
|       "inBundle": true, | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">= 10.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aws-cdk-lib/node_modules/yaml": { | ||||
|       "version": "1.10.2", | ||||
|       "inBundle": true, | ||||
|       "license": "ISC", | ||||
|       "engines": { | ||||
|         "node": ">= 6" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/cdk-nag": { | ||||
|       "version": "2.36.40", | ||||
|       "resolved": "https://registry.npmjs.org/cdk-nag/-/cdk-nag-2.36.40.tgz", | ||||
|       "integrity": "sha512-8ZmVuGMAfwJcz88uGBj0plGi7qNN4jTmlj/td7jzNcaBoPx4ZGq/hresTTY8uvg26apjxgSZgZswzLoWGyMfOg==", | ||||
|       "license": "Apache-2.0", | ||||
|       "peerDependencies": { | ||||
|         "aws-cdk-lib": "^2.156.0", | ||||
|         "constructs": "^10.0.5" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/constructs": { | ||||
|       "version": "10.4.2", | ||||
|       "resolved": "https://registry.npmjs.org/constructs/-/constructs-10.4.2.tgz", | ||||
|       "integrity": "sha512-wsNxBlAott2qg8Zv87q3eYZYgheb9lchtBfjHzzLHtXbttwSrHPs1NNQbBrmbb1YZvYg2+Vh0Dor76w4mFxJkA==", | ||||
|       "license": "Apache-2.0" | ||||
|     }, | ||||
|     "node_modules/fsevents": { | ||||
|       "version": "2.3.2", | ||||
|       "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", | ||||
|       "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", | ||||
|       "dev": true, | ||||
|       "hasInstallScript": true, | ||||
|       "license": "MIT", | ||||
|       "optional": true, | ||||
|       "os": [ | ||||
|         "darwin" | ||||
|       ], | ||||
|       "engines": { | ||||
|         "node": "^8.16.0 || ^10.6.0 || >=11.0.0" | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,34 @@ | ||||
| { | ||||
|   "name": "cdk_deploy", | ||||
|   "version": "0.1.0", | ||||
|   "bin": { | ||||
|     "cdk_deploy": "bin/cdk_deploy.js" | ||||
|   }, | ||||
|   "scripts": { | ||||
|     "cdk": "cdk", | ||||
|     "deploy:dev": "cdk deploy CPDocusealStack-dev --profile default", | ||||
|     "deploy:staging": "cdk deploy CPDocusealStack-staging --profile default", | ||||
|     "deploy:prod": "cdk deploy CPDocusealStack-production --profile default", | ||||
|     "destroy:dev": "cdk destroy CPDocusealStack-dev --profile default", | ||||
|     "destroy:staging": "cdk destroy CPDocusealStack-staging --profile default", | ||||
|     "destroy:prod": "cdk destroy CPDocusealStack-production --profile default", | ||||
|     "synth": "cdk synth", | ||||
|     "diff": "cdk diff", | ||||
|     "bootstrap": "cdk bootstrap" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "aws-cdk": "2.1021.0" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "aws-cdk-lib": "^2.205.0", | ||||
|     "cdk-nag": "^2.36.22", | ||||
|     "constructs": "^10.3.0" | ||||
|   }, | ||||
|   "keywords": [ | ||||
|     "aws", | ||||
|     "cdk", | ||||
|     "infrastructure", | ||||
|     "ecs", | ||||
|     "alb" | ||||
|   ] | ||||
| } | ||||
| @ -0,0 +1,39 @@ | ||||
| sudo yum install -y ec2-instance-connect | ||||
| cat >/home/ec2-user/.bashrc <<'EOF' | ||||
|  # .bashrc | ||||
| 
 | ||||
|   # Source global definitions | ||||
|   if [ -f /etc/bashrc ]; then | ||||
|           . /etc/bashrc | ||||
|   fi | ||||
| 
 | ||||
|   # User specific aliases and functions | ||||
|   function setContainer { | ||||
|     CONTAINER_ID=`sudo docker ps | grep "rails/bin" | awk '{ print $1; }' | head -1` | ||||
|   } | ||||
|   function execDocker { | ||||
|     setContainer | ||||
|     sudo docker exec -u rails -i -t $CONTAINER_ID $@ | ||||
|   } | ||||
|   function copy_from { | ||||
|     setContainer | ||||
|     sudo docker cp "$CONTAINER_ID:/rails/$1" "$2" | ||||
|   } | ||||
|   function copy_to { | ||||
|     setContainer | ||||
|     sudo docker cp "$1" "$CONTAINER_ID:/rails/$2" | ||||
|     sudo docker exec -u root -t $CONTAINER_ID /bin/sh -c 'chown rails:rails /rails/$2' | ||||
|   } | ||||
| 
 | ||||
|   function dangerConsole { | ||||
|     echo | ||||
|     echo "********** Accessing the WRITE & READ console **********" | ||||
|     echo "********** THIS IS DANGEROUS AND CHANGES YOU MAKE WILL IMPACT THE DATABASE **********" | ||||
|     echo | ||||
|     sleep 3 | ||||
|     execDocker bin/rails console | ||||
|   } | ||||
| 
 | ||||
|   alias console='dangerConsole' | ||||
|   alias shell='execDocker /bin/bash' | ||||
| EOF | ||||
					Loading…
					
					
				
		Reference in new issue