@@ -9,10 +9,11 @@ import * as cxapi from '@aws-cdk/cx-api';
9
9
import { Construct } from 'constructs' ;
10
10
import { IClusterEngine } from './cluster-engine' ;
11
11
import { DatabaseClusterAttributes , IDatabaseCluster } from './cluster-ref' ;
12
+ import { DatabaseSecret } from './database-secret' ;
12
13
import { Endpoint } from './endpoint' ;
13
14
import { IParameterGroup , ParameterGroup } from './parameter-group' ;
14
15
import { applyDefaultRotationOptions , defaultDeletionProtection , renderCredentials , setupS3ImportExport , helperRemovalPolicy , renderUnless } from './private/util' ;
15
- import { BackupProps , Credentials , InstanceProps , PerformanceInsightRetention , RotationSingleUserOptions , RotationMultiUserOptions } from './props' ;
16
+ import { BackupProps , Credentials , InstanceProps , PerformanceInsightRetention , RotationSingleUserOptions , RotationMultiUserOptions , SnapshotCredentials } from './props' ;
16
17
import { DatabaseProxy , DatabaseProxyOptions , ProxyTarget } from './proxy' ;
17
18
import { CfnDBCluster , CfnDBClusterProps , CfnDBInstance } from './rds.generated' ;
18
19
import { ISubnetGroup , SubnetGroup } from './subnet-group' ;
@@ -661,9 +662,27 @@ export interface DatabaseClusterFromSnapshotProps extends DatabaseClusterBasePro
661
662
/**
662
663
* Credentials for the administrative user
663
664
*
665
+ * Note - using this prop only works with `Credentials.fromPassword()` with the
666
+ * username of the snapshot, `Credentials.fromUsername()` with the username and
667
+ * password of the snapshot or `Credentials.fromSecret()` with a secret containing
668
+ * the username and password of the snapshot.
669
+ *
664
670
* @default - A username of 'admin' (or 'postgres' for PostgreSQL) and SecretsManager-generated password
671
+ * that **will not be applied** to the cluster, use `snapshotCredentials` for the correct behavior.
672
+ *
673
+ * @deprecated use `snapshotCredentials` which allows to generate a new password
665
674
*/
666
675
readonly credentials ?: Credentials ;
676
+
677
+ /**
678
+ * Master user credentials.
679
+ *
680
+ * Note - It is not possible to change the master username for a snapshot;
681
+ * however, it is possible to provide (or generate) a new password.
682
+ *
683
+ * @default - The existing username and password from the snapshot will be used.
684
+ */
685
+ readonly snapshotCredentials ?: SnapshotCredentials ;
667
686
}
668
687
669
688
/**
@@ -687,12 +706,34 @@ export class DatabaseClusterFromSnapshot extends DatabaseClusterNew {
687
706
constructor ( scope : Construct , id : string , props : DatabaseClusterFromSnapshotProps ) {
688
707
super ( scope , id , props ) ;
689
708
690
- const credentials = renderCredentials ( this , props . engine , props . credentials ) ;
691
- const secret = credentials . secret ;
709
+ if ( props . credentials && ! props . credentials . password && ! props . credentials . secret ) {
710
+ Annotations . of ( this ) . addWarning ( 'Use `snapshotCredentials` to modify password of a cluster created from a snapshot.' ) ;
711
+ }
712
+ if ( ! props . credentials && ! props . snapshotCredentials ) {
713
+ Annotations . of ( this ) . addWarning ( 'Generated credentials will not be applied to cluster. Use `snapshotCredentials` instead. `addRotationSingleUser()` and `addRotationMultiUser()` cannot be used on tbis cluster.' ) ;
714
+ }
715
+ const deprecatedCredentials = renderCredentials ( this , props . engine , props . credentials ) ;
716
+
717
+ let credentials = props . snapshotCredentials ;
718
+ let secret = credentials ?. secret ;
719
+ if ( ! secret && credentials ?. generatePassword ) {
720
+ if ( ! credentials . username ) {
721
+ throw new Error ( '`snapshotCredentials` `username` must be specified when `generatePassword` is set to true' ) ;
722
+ }
723
+
724
+ secret = new DatabaseSecret ( this , 'SnapshotSecret' , {
725
+ username : credentials . username ,
726
+ encryptionKey : credentials . encryptionKey ,
727
+ excludeCharacters : credentials . excludeCharacters ,
728
+ replaceOnPasswordCriteriaChanges : credentials . replaceOnPasswordCriteriaChanges ,
729
+ replicaRegions : credentials . replicaRegions ,
730
+ } ) ;
731
+ }
692
732
693
733
const cluster = new CfnDBCluster ( this , 'Resource' , {
694
734
...this . newCfnProps ,
695
735
snapshotIdentifier : props . snapshotIdentifier ,
736
+ masterUserPassword : secret ?. secretValueFromJson ( 'password' ) ?. unsafeUnwrap ( ) ?? credentials ?. password ?. unsafeUnwrap ( ) , // Safe usage
696
737
} ) ;
697
738
698
739
this . clusterIdentifier = cluster . ref ;
@@ -701,6 +742,13 @@ export class DatabaseClusterFromSnapshot extends DatabaseClusterNew {
701
742
this . secret = secret . attach ( this ) ;
702
743
}
703
744
745
+ if ( deprecatedCredentials . secret ) {
746
+ const deprecatedSecret = deprecatedCredentials . secret . attach ( this ) ;
747
+ if ( ! this . secret ) {
748
+ this . secret = deprecatedSecret ;
749
+ }
750
+ }
751
+
704
752
// create a number token that represents the port of the cluster
705
753
const portAttribute = Token . asNumber ( cluster . attrEndpointPort ) ;
706
754
this . clusterEndpoint = new Endpoint ( cluster . attrEndpointAddress , portAttribute ) ;
0 commit comments