diff --git a/packages/@aws-cdk/aws-secretsmanager/README.md b/packages/@aws-cdk/aws-secretsmanager/README.md index 76efe357b9467..540cc9a7fa0be 100644 --- a/packages/@aws-cdk/aws-secretsmanager/README.md +++ b/packages/@aws-cdk/aws-secretsmanager/README.md @@ -1,5 +1,4 @@ ## AWS Secrets Manager Construct Library - --- @@ -15,35 +14,15 @@ import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; ``` ### Create a new Secret in a Stack - In order to have SecretsManager generate a new secret value automatically, you can get started with the following: -```ts -// Default secret -const secret = new secretsmanager.Secret(this, 'Secret'); - -// Using the default secret -new iam.User(this, 'User', { - password: secret.secretValue, -}); - -// Templated secret -const templatedSecret = new secretsmanager.Secret(this, 'TemplatedSecret', { - generateSecretString: { - secretStringTemplate: JSON.stringify({ username: 'user' }), - generateStringKey: 'password', - }, -}); - -// Using the templated secret -new iam.User(this, 'OtherUser', { - userName: templatedSecret.secretValueFromJson('username').toString(), - password: templatedSecret.secretValueFromJson('password'), -}); -``` +[example of creating a secret](test/integ.secret.lit.ts) -[see also this example of creating a secret](test/integ.secret.lit.ts) +The `Secret` construct does not allow specifying the `SecretString` property +of the `AWS::SecretsManager::Secret` resource (as this will almost always +lead to the secret being surfaced in plain text and possibly committed to +your source control). If you need to use a pre-existing secret, the recommended way is to manually provision the secret in *AWS SecretsManager* and use the `Secret.fromSecretArn` @@ -64,7 +43,7 @@ A secret can set `RemovalPolicy`. If it set to `RETAIN`, that removing a secret ### Grant permission to use the secret to a role -You must grant permission to a resource for that resource to be allowed to +You must grant permission to a resource for that resource to be allowed to use a secret. This can be achieved with the `Secret.grantRead` and/or `Secret.grantUpdate` method, depending on your need: @@ -76,22 +55,18 @@ secret.grantWrite(role); ``` If, as in the following example, your secret was created with a KMS key: - ```ts const key = new kms.Key(stack, 'KMS'); const secret = new secretsmanager.Secret(stack, 'Secret', { encryptionKey: key }); secret.grantRead(role); secret.grantWrite(role); ``` - then `Secret.grantRead` and `Secret.grantWrite` will also grant the role the relevant encrypt and decrypt permissions to the KMS key through the SecretsManager service principal. ### Rotating a Secret with a custom Lambda function - A rotation schedule can be added to a Secret using a custom Lambda function: - ```ts const fn = new lambda.Function(...); const secret = new secretsmanager.Secret(this, 'Secret'); @@ -101,13 +76,10 @@ secret.addRotationSchedule('RotationSchedule', { automaticallyAfter: Duration.days(15) }); ``` - See [Overview of the Lambda Rotation Function](https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets-lambda-function-overview.html) on how to implement a Lambda Rotation Function. ### Rotating database credentials - Define a `SecretRotation` to rotate database credentials: - ```ts new SecretRotation(this, 'SecretRotation', { application: SecretRotationApplication.MYSQL_ROTATION_SINGLE_USER, // MySQL single user scheme @@ -118,7 +90,6 @@ new SecretRotation(this, 'SecretRotation', { ``` The secret must be a JSON string with the following format: - ```json { "engine": "", @@ -132,7 +103,6 @@ The secret must be a JSON string with the following format: ``` For the multi user scheme, a `masterSecret` must be specified: - ```ts new SecretRotation(stack, 'SecretRotation', { application: SecretRotationApplication.MYSQL_ROTATION_MULTI_USER, diff --git a/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts b/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts index e4438ec308b7b..4ca105f58d59a 100644 --- a/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts +++ b/packages/@aws-cdk/aws-secretsmanager/lib/secret.ts @@ -103,22 +103,6 @@ export interface SecretProps { */ readonly secretName?: string; - /** - * Secret value (WARNING). - * - * **WARNING:** *It is **highly** encouraged to leave this field undefined and allow SecretsManager to create the secret value. - * The secret string -- if provided -- will be included in the output of the cdk as part of synthesis, - * and will appear in the CloudFormation template in the console*. - * - * Specifies text data that you want to encrypt and store in this new version of the secret. - * May be a simple string value, or a string representation of a JSON structure. - * - * Only one of `secretString` and `generateSecretString` can be provided. - * - * @default - SecretsManager generates a new secret value. - */ - readonly secretString?: string; - /** * Policy to apply when the secret is removed from this stack. * @@ -282,26 +266,17 @@ export class Secret extends SecretBase { throw new Error('`secretStringTemplate` and `generateStringKey` must be specified together.'); } - if (props.generateSecretString && props.secretString) { - throw new Error('Cannot specify both `generateSecretString` and `secretString`.'); - } - const resource = new secretsmanager.CfnSecret(this, 'Resource', { description: props.description, kmsKeyId: props.encryptionKey && props.encryptionKey.keyArn, - generateSecretString: props.generateSecretString || (props.secretString ? undefined : {}), + generateSecretString: props.generateSecretString || {}, name: this.physicalName, - secretString: props.secretString, }); if (props.removalPolicy) { resource.applyRemovalPolicy(props.removalPolicy); } - if (props.secretString) { - this.node.addWarning('Using a `secretString` value which will be visible in plaintext in the CloudFormation template and cdk output.'); - } - this.secretArn = this.getResourceArnAttribute(resource.ref, { service: 'secretsmanager', resource: 'secret', diff --git a/packages/@aws-cdk/aws-secretsmanager/package.json b/packages/@aws-cdk/aws-secretsmanager/package.json index b80ecfef3fbc3..ca00bf77825cb 100644 --- a/packages/@aws-cdk/aws-secretsmanager/package.json +++ b/packages/@aws-cdk/aws-secretsmanager/package.json @@ -64,7 +64,6 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@aws-cdk/cloud-assembly-schema": "0.0.0", "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-secretsmanager/test/test.secret.ts b/packages/@aws-cdk/aws-secretsmanager/test/test.secret.ts index e1c5bee53dd7e..0a295747e7e5f 100644 --- a/packages/@aws-cdk/aws-secretsmanager/test/test.secret.ts +++ b/packages/@aws-cdk/aws-secretsmanager/test/test.secret.ts @@ -2,7 +2,6 @@ import { expect, haveResource, haveResourceLike, ResourcePart } from '@aws-cdk/a import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as lambda from '@aws-cdk/aws-lambda'; -import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; import * as secretsmanager from '../lib'; @@ -575,41 +574,6 @@ export = { test.done(); }, - 'can provide a secret value directly'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - const secret = new secretsmanager.Secret(stack, 'Secret', { - secretString: 'mynotsosecretvalue', - }); - - // THEN - expect(stack).to(haveResource('AWS::SecretsManager::Secret', { - SecretString: 'mynotsosecretvalue', - })); - - test.equals(secret.node.metadata[0].type, cxschema.ArtifactMetadataEntryType.WARN); - test.equals(secret.node.metadata[0].data, 'Using a `secretString` value which will be visible in plaintext in the CloudFormation template and cdk output.'); - - test.done(); - }, - - 'throws when specifying secretString and generateStringKey'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // THEN - test.throws(() => new secretsmanager.Secret(stack, 'Secret', { - generateSecretString: { - excludeCharacters: '@', - }, - secretString: 'myexistingsecret', - }), /Cannot specify both `generateSecretString` and `secretString`./); - - test.done(); - }, - 'equivalence of SecretValue and Secret.fromSecretAttributes'(test: Test) { // GIVEN const stack = new cdk.Stack();