diff --git a/packages/@aws-cdk/aws-redshift/README.md b/packages/@aws-cdk/aws-redshift/README.md index ce33c3d2f1d02..8f42386085396 100644 --- a/packages/@aws-cdk/aws-redshift/README.md +++ b/packages/@aws-cdk/aws-redshift/README.md @@ -60,24 +60,6 @@ The endpoint to access your database cluster will be available as the `.clusterE cluster.clusterEndpoint.socketAddress; // "HOSTNAME:PORT" ``` -## Rotating credentials - -When the master password is generated and stored in AWS Secrets Manager, it can be rotated automatically: - -```ts fixture=cluster -cluster.addRotationSingleUser(); // Will rotate automatically after 30 days -``` - -The multi user rotation scheme is also available: - -```ts fixture=cluster -import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; - -cluster.addRotationMultiUser('MyUser', { - secret: secretsmanager.Secret.fromSecretNameV2(this, 'Imported Secret', 'my-secret'), -}); -``` - ## Database Resources This module allows for the creation of non-CloudFormation database resources such as users @@ -273,3 +255,24 @@ call to `grant` but the user does not have the specified permission. Note that this does not occur when duplicate privileges are granted within the same application, as such privileges are de-duplicated before any SQL query is submitted. + +## Rotating credentials + +When the master password is generated and stored in AWS Secrets Manager, it can be rotated automatically: + +```ts fixture=cluster +cluster.addRotationSingleUser(); // Will rotate automatically after 30 days +``` + +The multi user rotation scheme is also available: + +```ts fixture=cluster + +const user = new User(this, 'User', { + cluster: cluster, + databaseName: 'databaseName', +}); +cluster.addRotationMultiUser('MultiUserRotation', { + secret: user.secret, +}); +``` diff --git a/packages/@aws-cdk/aws-redshift/lib/user.ts b/packages/@aws-cdk/aws-redshift/lib/user.ts index 3b5c8d0829ef8..15ce396190cac 100644 --- a/packages/@aws-cdk/aws-redshift/lib/user.ts +++ b/packages/@aws-cdk/aws-redshift/lib/user.ts @@ -1,4 +1,5 @@ import * as kms from '@aws-cdk/aws-kms'; +import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; import * as cdk from '@aws-cdk/core'; import { Construct } from 'constructs'; import { ICluster } from './cluster'; @@ -137,6 +138,12 @@ export class User extends UserBase { readonly databaseName: string; protected databaseProps: DatabaseOptions; + /** + * The Secrets Manager secret of the user. + * @attribute + */ + public readonly secret: secretsmanager.ISecret; + private resource: DatabaseQuery; constructor(scope: Construct, id: string, props: UserProps) { @@ -165,6 +172,7 @@ export class User extends UserBase { attachedSecret.grantRead(this.resource); this.username = this.resource.getAttString('username'); + this.secret = secret; } /** diff --git a/packages/@aws-cdk/aws-redshift/test/user.test.ts b/packages/@aws-cdk/aws-redshift/test/user.test.ts index 39b31345c7e33..79144d5c37cd3 100644 --- a/packages/@aws-cdk/aws-redshift/test/user.test.ts +++ b/packages/@aws-cdk/aws-redshift/test/user.test.ts @@ -90,6 +90,14 @@ describe('cluster user', () => { }); }); + it('secret property is exposed', () => { + const user = new redshift.User(stack, 'User', databaseOptions); + + expect(stack.resolve(user.secret.secretArn)).toStrictEqual({ + Ref: 'UserSecretE2C04A69', + }); + }); + it('uses username when provided', () => { const username = 'username';