in packages/constructs/L3/analytics/datawarehouse-l3-construct/lib/datawarehouse-l3-construct.ts [541:672]
private createClusterUsers(cluster: Cluster, warehouseKmsKey: MdaaKmsKey) {
this.props.databaseUsers?.forEach(databaseUser => {
//Redshift is going to force usernames to lower case.
//Need to make sure username matches between cluster and secret contents.
const username = databaseUser.userName.toLowerCase();
if (username != databaseUser.userName) {
console.log(`Modified configured username ${databaseUser.userName} to ${username} for Redshift compatability`);
}
const userProps: UserProps = {
cluster: cluster,
databaseName: databaseUser.dbName,
username: username,
adminUser: cluster.secret,
encryptionKey: warehouseKmsKey,
excludeCharacters: databaseUser.excludeCharacters,
};
const user = new User(this.scope, 'redshiftdbserviceuser-' + username, userProps);
new StringParameter(user, 'ssmsecret' + username, {
parameterName: this.props.naming.ssmPath(`datawarehouse/secret/${username}`, false),
stringValue: user.secret.secretName,
}); // This causes param collision with two warehouses in the same domain
new StringParameter(user, 'ssmsecretarn' + username, {
parameterName: this.props.naming.ssmPath(`datawarehouse/secretarn/${username}`, false),
stringValue: user.secret.secretArn,
}); // This causes param collision with two warehouses in the same domain
//Redshift DatabaseSecret construct does not currently set the masterarn on the secret string,
//which is required by the multi user rotation function
const cfnUserSecret = user.secret.node.defaultChild as CfnSecret;
const secretStringTemplateString = (cfnUserSecret.generateSecretString as CfnSecret.GenerateSecretStringProperty)
.secretStringTemplate;
const secretStringTemplate = secretStringTemplateString ? JSON.parse(secretStringTemplateString) : undefined;
const secretStringTemplateWithMasterArn = {
...secretStringTemplate,
masterarn: cluster.secret?.secretArn,
};
cfnUserSecret.addPropertyOverride(
'GenerateSecretString.SecretStringTemplate',
JSON.stringify(secretStringTemplateWithMasterArn),
);
if (databaseUser.secretRotationDays > 0) {
const multiUserRotationOptions: RotationMultiUserOptions = {
secret: user.secret,
automaticallyAfter: Duration.days(databaseUser.secretRotationDays),
};
cluster.addRotationMultiUser('multiuserrotation' + username, multiUserRotationOptions);
}
const secretAccessRoles = databaseUser.secretAccessRoles
? [
...this.props.roleHelper.resolveRoleRefsWithOrdinals(databaseUser.secretAccessRoles, 'SecretAccessRole'),
...this.props.roleHelper.resolveRoleRefsWithOrdinals(this.props.dataAdminRoleRefs, 'DataAdmin'),
]
: this.props.roleHelper.resolveRoleRefsWithOrdinals(this.props.dataAdminRoleRefs, 'DataAdmin');
this.assignSecretAcessPolicies(secretAccessRoles, warehouseKmsKey, user.secret);
this.scope.node.children.forEach(child => {
if (child.node.id.startsWith('Query Redshift Database') || child.node.id.startsWith('redshiftdbserviceuser-')) {
MdaaNagSuppressions.addCodeResourceSuppressions(
child,
[
{ id: 'AwsSolutions-IAM4', reason: 'Role is for Custom Resource Provider.' },
{
id: 'NIST.800.53.R5-IAMNoInlinePolicy',
reason: 'Role is for Custom Resource Provider. Inline policy automatically added.',
},
{
id: 'HIPAA.Security-IAMNoInlinePolicy',
reason: 'Role is for Custom Resource Provider. Inline policy automatically added.',
},
{
id: 'PCI.DSS.321-IAMNoInlinePolicy',
reason: 'Role is for Custom Resource Provider. Inline policy automatically added.',
},
{ id: 'AwsSolutions-IAM5', reason: 'Role is for Custom Resource Provider.' },
{ id: 'AwsSolutions-L1', reason: 'Role is for Custom Resource Provider.' },
{
id: 'NIST.800.53.R5-LambdaDLQ',
reason:
'Lambda Function is created by aws-redshift-alpha cdk module and error handling will be handled by CloudFormation',
},
{
id: 'NIST.800.53.R5-LambdaInsideVPC',
reason:
'Lambda Function is created by aws-redshift-alpha cdk module and will interact only with Redshift/SecretsManager',
},
{
id: 'NIST.800.53.R5-LambdaConcurrency',
reason:
'Lambda Function is created by aws-redshift-alpha cdk module and will only execute during stack deployement. Reserved concurrency not appropriate.',
},
{
id: 'HIPAA.Security-LambdaDLQ',
reason:
'Lambda Function is created by aws-redshift-alpha cdk module and error handling will be handled by CloudFormation',
},
{
id: 'PCI.DSS.321-LambdaDLQ',
reason:
'Lambda Function is created by aws-redshift-alpha cdk module and error handling will be handled by CloudFormation',
},
{
id: 'HIPAA.Security-LambdaInsideVPC',
reason:
'Lambda Function is created by aws-redshift-alpha cdk module and will interact only with Redshift/SecretsManager',
},
{
id: 'PCI.DSS.321-LambdaInsideVPC',
reason:
'Lambda Function is created by aws-redshift-alpha cdk module and will interact only with Redshift/SecretsManager',
},
{
id: 'HIPAA.Security-LambdaConcurrency',
reason:
'Lambda Function is created by aws-redshift-alpha cdk module and will only execute during stack deployement. Reserved concurrency not appropriate.',
},
{
id: 'PCI.DSS.321-LambdaConcurrency',
reason:
'Lambda Function is created by aws-redshift-alpha cdk module and will only execute during stack deployement. Reserved concurrency not appropriate.',
},
],
true,
);
}
});
});
}