cdk/lib/registrations-db-proxy.ts (105 lines of code) (raw):

import type { GuStackProps } from '@guardian/cdk/lib/constructs/core'; import { AppIdentity, GuStack } from '@guardian/cdk/lib/constructs/core'; import { GuVpc, SubnetType } from '@guardian/cdk/lib/constructs/ec2'; import type { App } from 'aws-cdk-lib'; import { Arn, ArnFormat, CfnOutput } from 'aws-cdk-lib'; import { SecurityGroup } from 'aws-cdk-lib/aws-ec2'; import { DatabaseInstance, DatabaseInstanceEngine, DatabaseProxy, ProxyTarget, } from 'aws-cdk-lib/aws-rds'; import { Secret } from 'aws-cdk-lib/aws-secretsmanager'; interface DbProxyStackProps extends GuStackProps { appName: string; dbHost: string; dbName: string; dbInstanceId: string; dbSecurityGroupId: string; } export class RegistrationsDbProxy extends GuStack { constructor(scope: App, id: string, props: DbProxyStackProps) { super(scope, id, props); const vpc = GuVpc.fromIdParameter( this, AppIdentity.suffixText({ app: props.appName }, 'VPC'), ); const dbPort = 5432; const secretTemplate = { engine: 'postgres', host: props.dbHost, port: dbPort, dbname: props.dbName, dbInstanceIdentifier: props.dbInstanceId, }; const dbWorkerSecret = new Secret(this, 'RegistrationDbWorkerSecret', { secretName: `registrations-db-worker-secret-${props.stage}`, description: 'Secrets for accessing registration database from worker lambdas', generateSecretString: { secretStringTemplate: JSON.stringify({ username: 'worker_user', ...secretTemplate, }), generateStringKey: 'password', }, }); const dbCleanerSecret = new Secret(this, 'RegistrationDbCleanerSecret', { secretName: `registrations-db-cleaner-secret-${props.stage}`, description: 'Secrets for accessing registration database from cleaner lambdas', generateSecretString: { secretStringTemplate: JSON.stringify({ username: 'cleaner_user', ...secretTemplate, }), generateStringKey: 'password', }, }); const dbSecurityGroup = SecurityGroup.fromSecurityGroupId( this, 'registrations-db-security-group', props.dbSecurityGroupId, ); const registrationDb = DatabaseInstance.fromDatabaseInstanceAttributes( this, 'registrations-db', { instanceEndpointAddress: props.dbHost, instanceIdentifier: props.dbInstanceId, port: dbPort, securityGroups: [dbSecurityGroup], engine: DatabaseInstanceEngine.POSTGRES, }, ); const proxy = new DatabaseProxy(this, 'RegistrationsDbProxy', { dbProxyName: `registrations-db-proxy-cdk-${props.stage}`, proxyTarget: ProxyTarget.fromInstance(registrationDb), secrets: [dbWorkerSecret, dbCleanerSecret], vpc, iamAuth: false, maxConnectionsPercent: 90, securityGroups: [dbSecurityGroup], requireTLS: false, vpcSubnets: { subnets: GuVpc.subnetsFromParameter(this, { type: SubnetType.PRIVATE, app: props.appName, }), }, }); const proxyResourceId = Arn.split( proxy.dbProxyArn, ArnFormat.COLON_RESOURCE_NAME, ).resourceName; if (proxyResourceId != undefined) { const grantId = `arn:aws:rds-db:${this.region}:${this.account}:dbuser:${proxyResourceId}/*`; new CfnOutput(this, 'RegistrationsDbProxyId', { value: grantId, description: 'ID of RDS proxy to registrations database', exportName: `RegistrationsDbProxyId-${props.stage}`, }); } } }