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