Skip to content

Commit 6bda4e5

Browse files
fix(rds): add clusterResourceIdentifier property to database cluster (#23605)
**Summary** - Exposed the [`DBClusterResourceId`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-rds-dbcluster.html#aws-resource-rds-dbcluster-return-values) on the database cluster as `clusterResourceIdentifier`. - This is needed to [create an IAM policy for IAM database access](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/UsingWithRDS.IAMDBAuth.IAMPolicy.html).
1 parent d7a1c34 commit 6bda4e5

File tree

10 files changed

+292
-34
lines changed

10 files changed

+292
-34
lines changed

packages/@aws-cdk/aws-rds/lib/cluster-ref.ts

+16
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ export interface IDatabaseCluster extends IResource, ec2.IConnectable, secretsma
1414
*/
1515
readonly clusterIdentifier: string;
1616

17+
/**
18+
* The immutable identifier for the cluster; for example: cluster-ABCD1234EFGH5678IJKL90MNOP.
19+
*
20+
* This AWS Region-unique identifier is used in things like IAM authentication policies.
21+
*/
22+
readonly clusterResourceIdentifier: string;
23+
1724
/**
1825
* Identifiers of the replicas
1926
*/
@@ -57,6 +64,15 @@ export interface DatabaseClusterAttributes {
5764
*/
5865
readonly clusterIdentifier: string;
5966

67+
/**
68+
* The immutable identifier for the cluster; for example: cluster-ABCD1234EFGH5678IJKL90MNOP.
69+
*
70+
* This AWS Region-unique identifier is used to grant access to the cluster.
71+
*
72+
* @default none
73+
*/
74+
readonly clusterResourceIdentifier?: string;
75+
6076
/**
6177
* The database port
6278
*

packages/@aws-cdk/aws-rds/lib/cluster.ts

+20
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,13 @@ export abstract class DatabaseClusterBase extends Resource implements IDatabaseC
321321
*/
322322
public abstract readonly clusterIdentifier: string;
323323

324+
/**
325+
* The immutable identifier for the cluster; for example: cluster-ABCD1234EFGH5678IJKL90MNOP.
326+
*
327+
* This AWS Region-unique identifier is used in things like IAM authentication policies.
328+
*/
329+
public abstract readonly clusterResourceIdentifier: string;
330+
324331
/**
325332
* Identifiers of the replicas
326333
*/
@@ -557,6 +564,7 @@ class ImportedDatabaseCluster extends DatabaseClusterBase implements IDatabaseCl
557564
public readonly connections: ec2.Connections;
558565
public readonly engine?: IClusterEngine;
559566

567+
private readonly _clusterResourceIdentifier?: string;
560568
private readonly _clusterEndpoint?: Endpoint;
561569
private readonly _clusterReadEndpoint?: Endpoint;
562570
private readonly _instanceIdentifiers?: string[];
@@ -566,6 +574,7 @@ class ImportedDatabaseCluster extends DatabaseClusterBase implements IDatabaseCl
566574
super(scope, id);
567575

568576
this.clusterIdentifier = attrs.clusterIdentifier;
577+
this._clusterResourceIdentifier = attrs.clusterResourceIdentifier;
569578

570579
const defaultPort = attrs.port ? ec2.Port.tcp(attrs.port) : undefined;
571580
this.connections = new ec2.Connections({
@@ -582,6 +591,13 @@ class ImportedDatabaseCluster extends DatabaseClusterBase implements IDatabaseCl
582591
: undefined;
583592
}
584593

594+
public get clusterResourceIdentifier() {
595+
if (!this._clusterResourceIdentifier) {
596+
throw new Error('Cannot access `clusterResourceIdentifier` of an imported cluster without a clusterResourceIdentifier');
597+
}
598+
return this._clusterResourceIdentifier;
599+
}
600+
585601
public get clusterEndpoint() {
586602
if (!this._clusterEndpoint) {
587603
throw new Error('Cannot access `clusterEndpoint` of an imported cluster without an endpoint address and port');
@@ -637,6 +653,7 @@ export class DatabaseCluster extends DatabaseClusterNew {
637653
}
638654

639655
public readonly clusterIdentifier: string;
656+
public readonly clusterResourceIdentifier: string;
640657
public readonly clusterEndpoint: Endpoint;
641658
public readonly clusterReadEndpoint: Endpoint;
642659
public readonly connections: ec2.Connections;
@@ -662,6 +679,7 @@ export class DatabaseCluster extends DatabaseClusterNew {
662679
});
663680

664681
this.clusterIdentifier = cluster.ref;
682+
this.clusterResourceIdentifier = cluster.attrDbClusterResourceId;
665683

666684
if (secret) {
667685
this.secret = secret.attach(this);
@@ -729,6 +747,7 @@ export interface DatabaseClusterFromSnapshotProps extends DatabaseClusterBasePro
729747
*/
730748
export class DatabaseClusterFromSnapshot extends DatabaseClusterNew {
731749
public readonly clusterIdentifier: string;
750+
public readonly clusterResourceIdentifier: string;
732751
public readonly clusterEndpoint: Endpoint;
733752
public readonly clusterReadEndpoint: Endpoint;
734753
public readonly connections: ec2.Connections;
@@ -774,6 +793,7 @@ export class DatabaseClusterFromSnapshot extends DatabaseClusterNew {
774793
});
775794

776795
this.clusterIdentifier = cluster.ref;
796+
this.clusterResourceIdentifier = cluster.attrDbClusterResourceId;
777797

778798
if (secret) {
779799
this.secret = secret.attach(this);

packages/@aws-cdk/aws-rds/test/cluster.test.ts

+5
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ describe('cluster', () => {
9797
VpcSecurityGroupIds: [{ 'Fn::GetAtt': ['DatabaseSecurityGroup5C91FDCB', 'GroupId'] }],
9898
});
9999

100+
expect(stack.resolve(cluster.clusterResourceIdentifier)).toEqual({ 'Fn::GetAtt': ['DatabaseB269D8BB', 'DBClusterResourceId'] });
100101
expect(cluster.instanceIdentifiers).toHaveLength(1);
101102
expect(stack.resolve(cluster.instanceIdentifiers[0])).toEqual({
102103
Ref: 'DatabaseInstance1844F58FD',
@@ -738,6 +739,7 @@ describe('cluster', () => {
738739
clusterIdentifier: 'identifier',
739740
});
740741

742+
expect(() => cluster.clusterResourceIdentifier).toThrow(/Cannot access `clusterResourceIdentifier` of an imported cluster/);
741743
expect(() => cluster.clusterEndpoint).toThrow(/Cannot access `clusterEndpoint` of an imported cluster/);
742744
expect(() => cluster.clusterReadEndpoint).toThrow(/Cannot access `clusterReadEndpoint` of an imported cluster/);
743745
expect(() => cluster.instanceIdentifiers).toThrow(/Cannot access `instanceIdentifiers` of an imported cluster/);
@@ -750,6 +752,7 @@ describe('cluster', () => {
750752
const cluster = DatabaseCluster.fromDatabaseClusterAttributes(stack, 'Database', {
751753
clusterEndpointAddress: 'addr',
752754
clusterIdentifier: 'identifier',
755+
clusterResourceIdentifier: 'identifier',
753756
instanceEndpointAddresses: ['instance-addr'],
754757
instanceIdentifiers: ['identifier'],
755758
port: 3306,
@@ -759,6 +762,7 @@ describe('cluster', () => {
759762
})],
760763
});
761764

765+
expect(cluster.clusterResourceIdentifier).toEqual('identifier');
762766
expect(cluster.clusterEndpoint.socketAddress).toEqual('addr:3306');
763767
expect(cluster.clusterReadEndpoint.socketAddress).toEqual('reader-address:3306');
764768
expect(cluster.instanceIdentifiers).toEqual(['identifier']);
@@ -2091,6 +2095,7 @@ describe('cluster', () => {
20912095

20922096
Template.fromStack(stack).resourceCountIs('AWS::RDS::DBInstance', 2);
20932097

2098+
expect(stack.resolve(cluster.clusterResourceIdentifier)).toEqual({ 'Fn::GetAtt': ['DatabaseB269D8BB', 'DBClusterResourceId'] });
20942099
expect(cluster.instanceIdentifiers).toHaveLength(2);
20952100
expect(stack.resolve(cluster.instanceIdentifiers[0])).toEqual({
20962101
Ref: 'DatabaseInstance1844F58FD',

packages/@aws-cdk/aws-rds/test/integ.cluster.js.snapshot/aws-cdk-rds-integ.assets.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
{
2-
"version": "20.0.0",
2+
"version": "29.0.0",
33
"files": {
4-
"0b11338b1fdbc41b36beb545451369de9d176a04762e559c87a3afbe35c7316d": {
4+
"b62ee60990b0a14a4b10381d4d26d42ce50c164305fa81b2d9729e116480af0f": {
55
"source": {
66
"path": "aws-cdk-rds-integ.template.json",
77
"packaging": "file"
88
},
99
"destinations": {
1010
"current_account-current_region": {
1111
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
12-
"objectKey": "0b11338b1fdbc41b36beb545451369de9d176a04762e559c87a3afbe35c7316d.json",
12+
"objectKey": "b62ee60990b0a14a4b10381d4d26d42ce50c164305fa81b2d9729e116480af0f.json",
1313
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
1414
}
1515
}

packages/@aws-cdk/aws-rds/test/integ.cluster.js.snapshot/aws-cdk-rds-integ.template.json

+65-1
Original file line numberDiff line numberDiff line change
@@ -495,14 +495,14 @@
495495
"DatabaseB269D8BB": {
496496
"Type": "AWS::RDS::DBCluster",
497497
"Properties": {
498-
"Engine": "aurora",
499498
"CopyTagsToSnapshot": true,
500499
"DBClusterParameterGroupName": {
501500
"Ref": "ParamsA8366201"
502501
},
503502
"DBSubnetGroupName": {
504503
"Ref": "DatabaseSubnets56F17B9A"
505504
},
505+
"Engine": "aurora",
506506
"KmsKeyId": {
507507
"Fn::GetAtt": [
508508
"DbSecurity381C2C15",
@@ -567,6 +567,70 @@
567567
],
568568
"UpdateReplacePolicy": "Delete",
569569
"DeletionPolicy": "Delete"
570+
},
571+
"ClusterIamAccess93AC3DF3": {
572+
"Type": "AWS::IAM::Role",
573+
"Properties": {
574+
"AssumeRolePolicyDocument": {
575+
"Statement": [
576+
{
577+
"Action": "sts:AssumeRole",
578+
"Effect": "Allow",
579+
"Principal": {
580+
"Service": "ecs-tasks.amazonaws.com"
581+
}
582+
}
583+
],
584+
"Version": "2012-10-17"
585+
}
586+
}
587+
},
588+
"ClusterIamAccessDefaultPolicyA088E4DA": {
589+
"Type": "AWS::IAM::Policy",
590+
"Properties": {
591+
"PolicyDocument": {
592+
"Statement": [
593+
{
594+
"Action": "rds-db:connect",
595+
"Effect": "Allow",
596+
"Resource": {
597+
"Fn::Join": [
598+
"",
599+
[
600+
"arn:",
601+
{
602+
"Ref": "AWS::Partition"
603+
},
604+
":rds-db:",
605+
{
606+
"Ref": "AWS::Region"
607+
},
608+
":",
609+
{
610+
"Ref": "AWS::AccountId"
611+
},
612+
":dbuser:",
613+
{
614+
"Fn::GetAtt": [
615+
"DatabaseB269D8BB",
616+
"DBClusterResourceId"
617+
]
618+
},
619+
"/db_user"
620+
]
621+
]
622+
}
623+
}
624+
],
625+
"Version": "2012-10-17"
626+
},
627+
"PolicyName": "ClusterIamAccessDefaultPolicyA088E4DA",
628+
"Roles": [
629+
{
630+
"Ref": "ClusterIamAccess93AC3DF3"
631+
}
632+
]
633+
}
570634
}
571635
},
572636
"Parameters": {
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"version":"20.0.0"}
1+
{"version":"29.0.0"}

packages/@aws-cdk/aws-rds/test/integ.cluster.js.snapshot/integ.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "20.0.0",
2+
"version": "29.0.0",
33
"testCases": {
44
"integ.cluster": {
55
"stacks": [

packages/@aws-cdk/aws-rds/test/integ.cluster.js.snapshot/manifest.json

+20-8
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
{
2-
"version": "20.0.0",
2+
"version": "29.0.0",
33
"artifacts": {
4-
"Tree": {
5-
"type": "cdk:tree",
6-
"properties": {
7-
"file": "tree.json"
8-
}
9-
},
104
"aws-cdk-rds-integ.assets": {
115
"type": "cdk:asset-manifest",
126
"properties": {
@@ -23,7 +17,7 @@
2317
"validateOnSynth": false,
2418
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}",
2519
"cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}",
26-
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/0b11338b1fdbc41b36beb545451369de9d176a04762e559c87a3afbe35c7316d.json",
20+
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/b62ee60990b0a14a4b10381d4d26d42ce50c164305fa81b2d9729e116480af0f.json",
2721
"requiresBootstrapStackVersion": 6,
2822
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version",
2923
"additionalDependencies": [
@@ -225,6 +219,18 @@
225219
"data": "DatabaseInstance2AA380DEE"
226220
}
227221
],
222+
"/aws-cdk-rds-integ/ClusterIamAccess/Resource": [
223+
{
224+
"type": "aws:cdk:logicalId",
225+
"data": "ClusterIamAccess93AC3DF3"
226+
}
227+
],
228+
"/aws-cdk-rds-integ/ClusterIamAccess/DefaultPolicy/Resource": [
229+
{
230+
"type": "aws:cdk:logicalId",
231+
"data": "ClusterIamAccessDefaultPolicyA088E4DA"
232+
}
233+
],
228234
"/aws-cdk-rds-integ/BootstrapVersion": [
229235
{
230236
"type": "aws:cdk:logicalId",
@@ -239,6 +245,12 @@
239245
]
240246
},
241247
"displayName": "aws-cdk-rds-integ"
248+
},
249+
"Tree": {
250+
"type": "cdk:tree",
251+
"properties": {
252+
"file": "tree.json"
253+
}
242254
}
243255
}
244256
}

0 commit comments

Comments
 (0)