import * as cdk from '@aws-cdk/core'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as rds from '@aws-cdk/aws-rds'; import * as secretmanager from '@aws-cdk/aws-secretsmanager'; export interface RdsStackProps extends cdk.NestedStackProps { readonly vpc: ec2.IVpc; } export class RdsStack extends cdk.NestedStack { public readonly credsSecretNamePrefix: string; public readonly credsAdminSecret: secretmanager.ISecret; public readonly credsReaderSecret: secretmanager.ISecret; public readonly credsWriterSecret: secretmanager.ISecret; public readonly dbServer: rds.DatabaseInstance; public readonly dbName: string; constructor(scope: cdk.Stack, id: string, props: RdsStackProps) { super(scope, id, props); const prefix = this.node.tryGetContext('PREFIX').toLowerCase(); this.credsSecretNamePrefix = `/${prefix}/rds/creds/`.toLowerCase(); const credsAdminSecretName = `${this.credsSecretNamePrefix}admin`; const credsReaderSecretName = `${this.credsSecretNamePrefix}reader`; const credsWriterSecretName = `${this.credsSecretNamePrefix}writer`; this.credsAdminSecret = new rds.DatabaseSecret(this, 'RdsCredentialsAdmin', { secretName: credsAdminSecretName, username: 'admin', }); this.dbName = `${prefix}Db`; this.dbServer = new rds.DatabaseInstance(this, 'RdsInstance', { databaseName: this.dbName, vpcSubnets: { onePerAz: true, subnetType: ec2.SubnetType.PRIVATE_ISOLATED, }, credentials: rds.Credentials.fromSecret(this.credsAdminSecret), vpc: props.vpc, port: 3306, allocatedStorage: 20, instanceIdentifier: prefix, engine: rds.DatabaseInstanceEngine.mysql({ version: rds.MysqlEngineVersion.VER_8_0_26, }), instanceType: ec2.InstanceType.of(ec2.InstanceClass.T2, ec2.InstanceSize.LARGE), }); // potentially allow connections to the RDS instance... this.credsReaderSecret = new rds.DatabaseSecret(this, 'RdsCredentialsReader', { secretName: credsReaderSecretName, username: 'reader', masterSecret: this.dbServer.secret, }); this.credsWriterSecret = new rds.DatabaseSecret(this, 'RdsCredentialsWriter', { secretName: credsWriterSecretName, username: 'writer', masterSecret: this.dbServer.secret, }); const readerUserSecretAttached = this.credsReaderSecret.attach(this.dbServer); this.dbServer.addRotationMultiUser('RdsCredentialsReaderRotation', { secret: readerUserSecretAttached, }); const writerUserSecretAttached = this.credsWriterSecret.attach(this.dbServer); this.dbServer.addRotationMultiUser('RdsCredentialsWriterRotation', { secret: writerUserSecretAttached, }); } }