-
Notifications
You must be signed in to change notification settings - Fork 4k
/
Copy pathuser.ts
186 lines (161 loc) · 5.27 KB
/
user.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
import * as kms from '@aws-cdk/aws-kms';
import * as cdk from '@aws-cdk/core';
import { Construct } from 'constructs';
import { ICluster } from './cluster';
import { DatabaseOptions } from './database-options';
import { DatabaseSecret } from './database-secret';
import { DatabaseQuery } from './private/database-query';
import { HandlerName } from './private/database-query-provider/handler-name';
import { UserHandlerProps } from './private/handler-props';
import { UserTablePrivileges } from './private/privileges';
import { ITable, TableAction } from './table';
// keep this import separate from other imports to reduce chance for merge conflicts with v2-main
// eslint-disable-next-line no-duplicate-imports, import/order
import { Construct as CoreConstruct } from '@aws-cdk/core';
/**
* Properties for configuring a Redshift user.
*/
export interface UserProps extends DatabaseOptions {
/**
* The name of the user.
*
* For valid values, see: https://docs.aws.amazon.com/redshift/latest/dg/r_names.html
*
* @default - a name is generated
*/
readonly username?: string;
/**
* KMS key to encrypt the generated secret.
*
* @default - the default AWS managed key is used
*/
readonly encryptionKey?: kms.IKey;
/**
* The policy to apply when this resource is removed from the application.
*
* @default cdk.RemovalPolicy.Destroy
*/
readonly removalPolicy?: cdk.RemovalPolicy;
}
/**
* Represents a user in a Redshift database.
*/
export interface IUser extends cdk.IConstruct {
/**
* The name of the user.
*/
readonly username: string;
/**
* The password of the user.
*/
readonly password: cdk.SecretValue;
/**
* The cluster where the table is located.
*/
readonly cluster: ICluster;
/**
* The name of the database where the table is located.
*/
readonly databaseName: string;
/**
* Grant this user privilege to access a table.
*/
addTablePrivileges(table: ITable, ...actions: TableAction[]): void;
}
/**
* A full specification of a Redshift user that can be used to import it fluently into the CDK application.
*/
export interface UserAttributes extends DatabaseOptions {
/**
* The name of the user.
*/
readonly username: string;
/**
* The password of the user.
*
* Do not put passwords in CDK code directly.
*/
readonly password: cdk.SecretValue;
}
abstract class UserBase extends CoreConstruct implements IUser {
abstract readonly username: string;
abstract readonly password: cdk.SecretValue;
abstract readonly cluster: ICluster;
abstract readonly databaseName: string;
/**
* The tables that user will have access to
*/
private privileges?: UserTablePrivileges;
protected abstract readonly databaseProps: DatabaseOptions;
addTablePrivileges(table: ITable, ...actions: TableAction[]): void {
if (!this.privileges) {
this.privileges = new UserTablePrivileges(this, 'TablePrivileges', {
...this.databaseProps,
user: this,
});
}
this.privileges.addPrivileges(table, ...actions);
}
}
/**
* A user in a Redshift cluster.
*/
export class User extends UserBase {
/**
* Specify a Redshift user using credentials that already exist.
*/
static fromUserAttributes(scope: Construct, id: string, attrs: UserAttributes): IUser {
return new class extends UserBase {
readonly username = attrs.username;
readonly password = attrs.password;
readonly cluster = attrs.cluster;
readonly databaseName = attrs.databaseName;
protected readonly databaseProps = attrs;
}(scope, id);
}
readonly username: string;
readonly password: cdk.SecretValue;
readonly cluster: ICluster;
readonly databaseName: string;
protected databaseProps: DatabaseOptions;
private resource: DatabaseQuery<UserHandlerProps>;
constructor(scope: Construct, id: string, props: UserProps) {
super(scope, id);
this.databaseProps = props;
this.cluster = props.cluster;
this.databaseName = props.databaseName;
const username = props.username ?? cdk.Names.uniqueId(this).toLowerCase();
const secret = new DatabaseSecret(this, 'Secret', {
username,
encryptionKey: props.encryptionKey,
});
const attachedSecret = secret.attach(props.cluster);
this.password = attachedSecret.secretValueFromJson('password');
this.resource = new DatabaseQuery<UserHandlerProps>(this, 'Resource', {
...this.databaseProps,
handler: HandlerName.User,
properties: {
username,
passwordSecretArn: attachedSecret.secretArn,
},
});
attachedSecret.grantRead(this.resource);
this.username = this.resource.getAttString('username');
}
/**
* Apply the given removal policy to this resource
*
* The Removal Policy controls what happens to this resource when it stops
* being managed by CloudFormation, either because you've removed it from the
* CDK application or because you've made a change that requires the resource
* to be replaced.
*
* The resource can be destroyed (`RemovalPolicy.DESTROY`), or left in your AWS
* account for data recovery and cleanup later (`RemovalPolicy.RETAIN`).
*
* This resource is destroyed by default.
*/
public applyRemovalPolicy(policy: cdk.RemovalPolicy): void {
this.resource.applyRemovalPolicy(policy);
}
}