Created
May 28, 2020 12:53
-
-
Save billykong/a778613eb0ecf1ab59ff82b76bbf985b to your computer and use it in GitHub Desktop.
Revisions
-
billykong created this gist
May 28, 2020 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,99 @@ import { Vpc, Subnet, SubnetType, SecurityGroup, Peer, Port } from '@aws-cdk/aws-ec2'; import ecs = require('@aws-cdk/aws-ecs'); import ecs_patterns = require('@aws-cdk/aws-ecs-patterns'); import { CfnDBCluster, CfnDBSubnetGroup } from '@aws-cdk/aws-rds'; import secretsManager = require('@aws-cdk/aws-secretsmanager'); import ssm = require('@aws-cdk/aws-ssm'); import * as cdk from '@aws-cdk/core'; export class AwsCdkFargateRdsStackStack extends cdk.Stack { constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); const serviceName = 'my-service'; const databaseName = 'my_database' const databaseUsername = 'deployer' const stage = 'dev'; const vpc = new Vpc(this, 'MyVPC', { cidr: '10.0.0.0/16', subnetConfiguration: [ { name: 'elb_public_', subnetType: SubnetType.PUBLIC }, { name: 'ecs_private_', subnetType: SubnetType.PRIVATE }, { name: 'aurora_isolated_', subnetType: SubnetType.ISOLATED } ] }); const subnetIds: string[] = []; vpc.isolatedSubnets.forEach((subnet, index) => { subnetIds.push(subnet.subnetId); }); const dbSubnetGroup: CfnDBSubnetGroup = new CfnDBSubnetGroup(this, 'AuroraSubnetGroup', { dbSubnetGroupDescription: 'Subnet group to access aurora', dbSubnetGroupName: 'aurora-serverless-subnet-group', subnetIds }); const databaseCredentialsSecret = new secretsManager.Secret(this, 'DBCredentialsSecret', { secretName: `${serviceName}-${stage}-credentials`, generateSecretString: { secretStringTemplate: JSON.stringify({ username: databaseUsername, }), excludePunctuation: true, includeSpace: false, generateStringKey: 'password' } }); new ssm.StringParameter(this, 'DBCredentialsArn', { parameterName: `${serviceName}-${stage}-credentials-arn`, stringValue: databaseCredentialsSecret.secretArn, }); const dbClusterSecurityGroup = new SecurityGroup(this, 'DBClusterSecurityGroup', { vpc }); // A better security approach would be allow ingress from private subnet only // but I haven't been able to get the ipv4 cidr block of subnets in aws-cwk dbClusterSecurityGroup.addIngressRule(Peer.ipv4('10.0.0.0/16'), Port.tcp(5432)); const dbConfig = { dbClusterIdentifier: `${serviceName}-${stage}-cluster`, engineMode: 'serverless', engine: 'aurora-postgresql', engineVersion: '10.7', databaseName: databaseName, masterUsername: databaseCredentialsSecret.secretValueFromJson('username').toString(), masterUserPassword: databaseCredentialsSecret.secretValueFromJson('password').toString(), // Note: aurora serverless cluster can be accessed within its VPC only // https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless.html dbSubnetGroupName: dbSubnetGroup.dbSubnetGroupName, scalingConfiguration: { autoPause: true, maxCapacity: 2, minCapacity: 2, secondsUntilAutoPause: 3600, }, vpcSecurityGroupIds: [ dbClusterSecurityGroup.securityGroupId ] }; const rdsCluster = new CfnDBCluster(this, 'DBCluster', dbConfig); rdsCluster.addDependsOn(dbSubnetGroup) const cluster = new ecs.Cluster(this, 'Cluster', { vpc }); const loadBalancedService = new ecs_patterns.ApplicationLoadBalancedFargateService(this, "FargateService", { cluster, taskImageOptions: { image: ecs.ContainerImage.fromRegistry("billykong/express-database-checker"), environment: { DATABASE_HOST: rdsCluster.attrEndpointAddress, DATABASE_NAME: databaseName, // TODO: use secret instead of environment DATABASE_USERNAME: databaseCredentialsSecret.secretValueFromJson('username').toString(), DATABASE_PASSWORD: databaseCredentialsSecret.secretValueFromJson('password').toString(), } }, }); } }