Skip to content

Commit

Permalink
feat(rds): Add dbname parameter to RDS.DatabaseSecret construct (#24729)
Browse files Browse the repository at this point in the history
As explained under #24728, this PR adds the ability to define a custom database name in the Secrets Manager resource created by the DatabaseSecret construct under @aws-cdk/rds, so that when this secret is pulled by client code and used to set database connection parameters, it can connect to a database of its choosing, rather than using the default database created by the RDS cluster that the secret gets attached to.

Closes #24728.

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
hsohail94 authored Mar 30, 2023
1 parent 016e206 commit b9ce0ee
Show file tree
Hide file tree
Showing 12 changed files with 950 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-rds/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ declare const instance: rds.DatabaseInstance;
const myUserSecret = new rds.DatabaseSecret(this, 'MyUserSecret', {
username: 'myuser',
secretName: 'my-user-secret', // optional, defaults to a CloudFormation-generated name
dbname: 'mydb', //optional, defaults to the main database of the RDS cluster this secret gets attached to
masterSecret: instance.secret,
excludeCharacters: '{}[]()\'"/\\', // defaults to the set " %+~`#$&*()|[]{}:;<>?!'/@\"\\"
});
Expand Down
8 changes: 8 additions & 0 deletions packages/@aws-cdk/aws-rds/lib/database-secret.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ export interface DatabaseSecretProps {
*/
readonly username: string;

/**
* The database name, if not using the default one
*
* @default - whatever the secret generates after the attach method is run
*/
readonly dbname?: string;

/**
* A name for the secret.
*
Expand Down Expand Up @@ -79,6 +86,7 @@ export class DatabaseSecret extends secretsmanager.Secret {
passwordLength: 30, // Oracle password cannot have more than 30 characters
secretStringTemplate: JSON.stringify({
username: props.username,
dbname: props.dbname,
masterarn: props.masterSecret?.secretArn,
}),
generateStringKey: 'password',
Expand Down
36 changes: 36 additions & 0 deletions packages/@aws-cdk/aws-rds/test/database-secret.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,42 @@ describe('database secret', () => {
expect(getSecretLogicalId(dbSecret, stack)).toEqual('SecretA720EF05');
});

test('create a database secret with a database name and secret name', () => {
// GIVEN
const stack = new Stack();

// WHEN
const customDbSecret = new DatabaseSecret(stack, 'Secret', {
username: 'admin-username',
dbname: 'admindb',
secretName: 'admin-secret',
});

// THEN
Template.fromStack(stack).hasResourceProperties('AWS::SecretsManager::Secret', {
Description: {
'Fn::Join': [
'',
[
'Generated by the CDK for stack: ',
{
Ref: 'AWS::StackName',
},
],
],
},
Name: 'admin-secret',
GenerateSecretString: {
ExcludeCharacters: DEFAULT_PASSWORD_EXCLUDE_CHARS,
GenerateStringKey: 'password',
PasswordLength: 30,
SecretStringTemplate: '{"username":"admin-username","dbname":"admindb"}',
},
});

expect(getSecretLogicalId(customDbSecret, stack)).toEqual('SecretA720EF05');
});

test('with master secret', () => {
// GIVEN
const stack = new Stack();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"version": "31.0.0",
"files": {
"c5b5b61dbdfaaef8d13f4a204e19f2cc7e8b0f268b59a82d2f05abc5c1144015": {
"source": {
"path": "aws-cdk-rds-integ-secret-rotation.template.json",
"packaging": "file"
},
"destinations": {
"current_account-current_region": {
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
"objectKey": "c5b5b61dbdfaaef8d13f4a204e19f2cc7e8b0f268b59a82d2f05abc5c1144015.json",
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
}
}
}
},
"dockerImages": {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
{
"Transform": "AWS::SecretsManager-2020-07-23",
"Resources": {
"DbSecurity381C2C15": {
"Type": "AWS::KMS::Key",
"Properties": {
"KeyPolicy": {
"Statement": [
{
"Action": "kms:*",
"Effect": "Allow",
"Principal": {
"AWS": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":iam::",
{
"Ref": "AWS::AccountId"
},
":root"
]
]
}
},
"Resource": "*"
}
],
"Version": "2012-10-17"
}
},
"UpdateReplacePolicy": "Retain",
"DeletionPolicy": "Retain"
},
"testsecretF8BBC644": {
"Type": "AWS::SecretsManager::Secret",
"Properties": {
"Description": {
"Fn::Join": [
"",
[
"Generated by the CDK for stack: ",
{
"Ref": "AWS::StackName"
}
]
]
},
"GenerateSecretString": {
"ExcludeCharacters": " %+~`#$&*()|[]{}:;<>?!'/@\"\\",
"GenerateStringKey": "password",
"PasswordLength": 30,
"SecretStringTemplate": "{\"username\":\"admin\",\"dbname\":\"admindb\"}"
},
"Name": "admin-secret"
},
"UpdateReplacePolicy": "Delete",
"DeletionPolicy": "Delete"
},
"testsecretAttachment19AD251F": {
"Type": "AWS::SecretsManager::SecretTargetAttachment",
"Properties": {
"SecretId": {
"Ref": "testsecretF8BBC644"
},
"TargetId": {
"Ref": "DatabaseB269D8BB"
},
"TargetType": "AWS::RDS::DBCluster"
}
},
"testsecrettestscheduleEA0B5085": {
"Type": "AWS::SecretsManager::RotationSchedule",
"Properties": {
"SecretId": {
"Ref": "testsecretF8BBC644"
},
"HostedRotationLambda": {
"ExcludeCharacters": " %+~`#$&*()|[]{}:;<>?!'/@\"\\",
"RotationType": "MySQLSingleUser"
},
"RotationRules": {
"AutomaticallyAfterDays": 30
}
}
},
"testsecretPolicyA5D2F46F": {
"Type": "AWS::SecretsManager::ResourcePolicy",
"Properties": {
"ResourcePolicy": {
"Statement": [
{
"Action": "secretsmanager:DeleteSecret",
"Effect": "Deny",
"Principal": {
"AWS": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":iam::",
{
"Ref": "AWS::AccountId"
},
":root"
]
]
}
},
"Resource": "*"
},
{
"Action": [
"secretsmanager:DescribeSecret",
"secretsmanager:GetSecretValue"
],
"Effect": "Allow",
"Principal": {
"AWS": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":iam::",
{
"Ref": "AWS::AccountId"
},
":root"
]
]
},
"Service": "ecs-tasks.amazonaws.com"
},
"Resource": {
"Ref": "testsecretAttachment19AD251F"
}
}
],
"Version": "2012-10-17"
},
"SecretId": {
"Ref": "testsecretF8BBC644"
}
}
},
"DatabaseB269D8BB": {
"Type": "AWS::RDS::DBCluster",
"Properties": {
"CopyTagsToSnapshot": true,
"DBClusterParameterGroupName": "default.aurora-mysql5.7",
"EnableHttpEndpoint": true,
"Engine": "aurora-mysql",
"EngineMode": "serverless",
"KmsKeyId": {
"Fn::GetAtt": [
"DbSecurity381C2C15",
"Arn"
]
},
"MasterUsername": {
"Fn::Join": [
"",
[
"{{resolve:secretsmanager:",
{
"Ref": "testsecretF8BBC644"
},
":SecretString:username::}}"
]
]
},
"MasterUserPassword": {
"Fn::Join": [
"",
[
"{{resolve:secretsmanager:",
{
"Ref": "testsecretF8BBC644"
},
":SecretString:password::}}"
]
]
},
"StorageEncrypted": true,
"VpcSecurityGroupIds": []
},
"UpdateReplacePolicy": "Snapshot",
"DeletionPolicy": "Snapshot"
}
},
"Parameters": {
"BootstrapVersion": {
"Type": "AWS::SSM::Parameter::Value<String>",
"Default": "/cdk-bootstrap/hnb659fds/version",
"Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]"
}
},
"Rules": {
"CheckBootstrapVersion": {
"Assertions": [
{
"Assert": {
"Fn::Not": [
{
"Fn::Contains": [
[
"1",
"2",
"3",
"4",
"5"
],
{
"Ref": "BootstrapVersion"
}
]
}
]
},
"AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI."
}
]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"version":"31.0.0"}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"version": "31.0.0",
"files": {
"21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": {
"source": {
"path": "cdkrdsintegsecretrotationDefaultTestDeployAssert9780868B.template.json",
"packaging": "file"
},
"destinations": {
"current_account-current_region": {
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
"objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json",
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
}
}
}
},
"dockerImages": {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"Parameters": {
"BootstrapVersion": {
"Type": "AWS::SSM::Parameter::Value<String>",
"Default": "/cdk-bootstrap/hnb659fds/version",
"Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]"
}
},
"Rules": {
"CheckBootstrapVersion": {
"Assertions": [
{
"Assert": {
"Fn::Not": [
{
"Fn::Contains": [
[
"1",
"2",
"3",
"4",
"5"
],
{
"Ref": "BootstrapVersion"
}
]
}
]
},
"AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI."
}
]
}
}
}
Loading

0 comments on commit b9ce0ee

Please sign in to comment.