Skip to content

Commit cc6e66b

Browse files
committed
wip
1 parent 19245b4 commit cc6e66b

File tree

2 files changed

+387
-14
lines changed

2 files changed

+387
-14
lines changed
Lines changed: 370 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,383 @@
1-
# Amazon ElastiCache Construct Library
1+
# ElastiCache CDK Construct Library
22

3+
This module has constructs for [Amazon ElastiCache](https://docs.aws.amazon.com/AmazonElastiCache/latest/dg/WhatIs.html).
34

4-
This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project.
5+
* The `ServerlessCache` construct facilitates the creation and management of serverless cache.
6+
* The `User` and `UserGroup` constructs facilitate the creation and management of users for the cache.
57

6-
```ts nofixture
7-
import * as elasticache from 'aws-cdk-lib/aws-elasticache';
8+
## Serverless Cache
9+
10+
Amazon ElastiCache Serverless is a serverless option that automatically scales cache capacity based on application traffic patterns. You can create a serverless cache using the `ServerlessCache` construct:
11+
12+
```ts
13+
const vpc = new ec2.Vpc(this, 'VPC');
14+
15+
const cache = new elasticache.ServerlessCache(this, 'MyServerlessCache', {
16+
vpc,
17+
});
18+
```
19+
20+
### Connecting to serverless cache
21+
22+
To control who can access the serverless cache by the security groups, use the `.connections` attribute.
23+
24+
The serverless cache has a default port `6379`.
25+
26+
This example allows an EC2 instance to connect to the serverless cache:
27+
28+
```ts
29+
declare const serverlessCache: elasticache.ServerlessCache;
30+
declare const instance: ec2.Instance;
31+
32+
// allow the EC2 instance to connect to serverless cache on default port 6379
33+
serverlessCache.connections.allowDefaultPortFrom(instance);
34+
```
35+
36+
### Cache usage limits
37+
38+
You can choose to configure a maximum usage on both cache data storage and ECPU/second for your cache to control cache costs.
39+
Doing so will ensure that your cache usage never exceeds the configured maximum.
40+
41+
For more infomation, see [Setting scaling limits to manage costs](https://docs.aws.amazon.com/AmazonElastiCache/latest/dg/Scaling.html#Pre-Scaling).
42+
43+
```ts
44+
declare const vpc: ec2.Vpc;
45+
46+
const serverlessCache = new elasticache.ServerlessCache(this, 'ServerlessCache', {
47+
engine: elasticache.CacheEngine.VALKEY_DEFAULT,
48+
vpc,
49+
cacheUsageLimits: {
50+
// cache data storage limits (GB)
51+
dataStorageMinimumSize: Size.gibibytes(2), // minimum: 1GB
52+
dataStorageMaximumSize: Size.gibibytes(3), // maximum: 5000GB
53+
// rate limits (ECPU/second)
54+
requestRateLimitMinimum: 1000, // minimum: 1000
55+
requestRateLimitMaximum: 10000, // maximum: 15000000
56+
},
57+
});
58+
```
59+
60+
### Backups and restore
61+
62+
You can enable automatic backups for serverless cache.
63+
When automatic backups are enabled, ElastiCache creates a backup of the cache on a daily basis.
64+
65+
Also you can set the backup window for any time when it's most convenient.
66+
If you don't specify a backup window, ElastiCache assigns one automatically.
67+
68+
For more information, see [Scheduling automatic backups](https://docs.aws.amazon.com/AmazonElastiCache/latest/dg/backups-automatic.html).
69+
70+
To enable automatic backups, set the `backupRetentionLimit` property. You can also specify the snapshot creation time by setting `backupTime` property:
71+
72+
```ts
73+
declare const vpc: ec2.Vpc;
74+
75+
const serverlessCache = new elasticache.ServerlessCache(this, 'ServerlessCache', {
76+
backup: {
77+
// enable automatic backups and set the retention period to 6 days
78+
backupRetentionLimit: 6,
79+
// set the backup window to 12:00 AM UTC
80+
backupTime: events.Schedule.cron({
81+
hour: '5',
82+
minute: '0',
83+
}),
84+
},
85+
vpc,
86+
});
87+
```
88+
89+
You can create a final backup by setting `backupNameBeforeDeletion` property.
90+
91+
```ts
92+
declare const vpc: ec2.Vpc;
93+
94+
const serverlessCache = new elasticache.ServerlessCache(this, 'ServerlessCache', {
95+
engine: elasticache.CacheEngine.VALKEY_DEFAULT,
96+
backup: {
97+
// set a backup name before deleting a cache
98+
backupNameBeforeDeletion: "my-final-backup-name",
99+
},
100+
vpc,
101+
});
102+
```
103+
104+
You can restore from backups by setting snapshot ARNs to `backupArnsToRestore` property:
105+
106+
```ts
107+
declare const vpc: ec2.Vpc;
108+
109+
const serverlessCache = new elasticache.ServerlessCache(this, 'ServerlessCache', {
110+
engine: elasticache.CacheEngine.VALKEY_DEFAULT,
111+
backup: {
112+
// set the backup(s) to restore
113+
backupArnsToRestore: ['arn:aws:elasticache:us-east-1:123456789012:serverlesscachesnapshot:my-final-backup-name'],
114+
},
115+
vpc,
116+
});
117+
```
118+
119+
### Customer Managed Key for encryption at rest
120+
121+
ElastiCache supports symmetric Customer Managed key (CMK) for encryption at rest.
122+
123+
For more information, see [Using customer managed keys from AWS KMS](https://docs.aws.amazon.com/AmazonElastiCache/latest/dg/at-rest-encryption.html#using-customer-managed-keys-for-elasticache-security).
124+
125+
To use CMK, set your CMK to the `kmsKey` property:
126+
127+
```ts
128+
import { Key } from 'aws-cdk-lib/aws-kms';
129+
130+
declare const kmsKey: Key;
131+
declare const vpc: ec2.Vpc;
132+
133+
const serverlessCache = new elasticache.ServerlessCache(this, 'ServerlessCache', {
134+
engine: elasticache.CacheEngine.VALKEY_DEFAULT,
135+
serverlessCacheName: 'my-serverless-cache',
136+
vpc,
137+
// set Customer Managed Key
138+
kmsKey,
139+
});
140+
```
141+
142+
### Metrics
143+
144+
You can monitor your serverless cache using CloudWatch Metrics via the `metric` method.
145+
146+
For more information about serverless cache metrics, see [Serverless metrics and events for Valkey and Redis OSS](https://docs.aws.amazon.com/AmazonElastiCache/latest/dg/serverless-metrics-events-redis.html) and [Serverless metrics and events for Memcached](https://docs.aws.amazon.com/AmazonElastiCache/latest/dg/serverless-metrics-events.memcached.html).
147+
148+
```ts
149+
declare const serverlessCache: elasticache.ServerlessCache;
150+
151+
// The 5 minutes sum of the total number of successful read-only key lookups in the cache over 5 minutes.
152+
const cacheHits = serverlessCache.metricCacheHitCount();
153+
154+
// The 5 minutes average of the total number of bytes used by the data stored in your cache over 5 minutes.
155+
const bytesUsedForCache = serverlessCache.metricDataStored();
156+
157+
// The 5 minutes average of the total number of ElastiCacheProcessingUnits (ECPUs) consumed by the requests executed on your cache.
158+
const elastiCacheProcessingUnits = serverlessCache.metricECPUsConsumed();
159+
160+
// Create an alarm for ECPUs.
161+
elastiCacheProcessingUnits.createAlarm(this, 'ElastiCacheProcessingUnitsAlarm', {
162+
threshold: 50,
163+
evaluationPeriods: 1,
164+
});
165+
```
166+
167+
### Import an existing serverless cache
168+
169+
To import an existing ServerlessCache, use the `ServerlessCache.fromServerlessCacheAttributes` method:
170+
171+
```ts
172+
declare const securityGroup: ec2.SecurityGroup;
173+
174+
const importedServerlessCache = elasticache.ServerlessCache.fromServerlessCacheAttributes(this, 'ImportedServerlessCache', {
175+
serverlessCacheName: 'my-serverless-cache',
176+
securityGroups: [securityGroup],
177+
});
178+
```
179+
180+
## User and User Group
181+
182+
Setup required properties and create:
183+
184+
```ts
185+
const newDefaultUser = new elasticache.NoPasswordUser(this, 'NoPasswordUser', {
186+
userId: 'default',
187+
accessControl: elasticache.AccessControl.fromAccessString("on ~* +@all"),
188+
})
189+
190+
const userGroup = new elasticache.UserGroup(this, 'UserGroup', {
191+
users: [newDefaultUser],
192+
});
8193
```
9194

10-
<!--BEGIN CFNONLY DISCLAIMER-->
195+
### RBAC
11196

12-
There are no official hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. Here are some suggestions on how to proceed:
197+
In Valkey 7.2 and onward and Redis OSS 6.0 onward you can use a feature called Role-Based Access Control (RBAC). RBAC is also the only way to control access to serverless caches.
13198

14-
- Search [Construct Hub for ElastiCache construct libraries](https://constructs.dev/search?q=elasticache)
15-
- Use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, in the same way you would use [the CloudFormation AWS::ElastiCache resources](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_ElastiCache.html) directly.
199+
RBAC enables you to control cache access through user groups. These user groups are designed as a way to organize access to caches.
16200

201+
For more information, see [Role-Based Access Control (RBAC)](https://docs.aws.amazon.com/AmazonElastiCache/latest/dg/Clusters.RBAC.html).
17202

18-
<!--BEGIN CFNONLY DISCLAIMER-->
203+
To enable RBAC for ElastiCache with Valkey or Redis OSS, you take the following steps:
19204

20-
There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet.
21-
However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly.
205+
* Create users.
206+
* Create a user group and add users to the user group.
207+
* Assign the user group to a cache.
22208

23-
For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::ElastiCache](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_ElastiCache.html).
209+
### Create users
24210

25-
(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and submit an RFC if you are interested in contributing to this construct library.)
211+
First, you need to create users by using `IamUser`, `PasswordUser` or `NoPasswordRequiredUser` construct.
26212

27-
<!--END CFNONLY DISCLAIMER-->
213+
With RBAC, you create users and assign them specific permissions by using `accessString` property.
214+
215+
For more information, see [Specifying Permissions Using an Access String](https://docs.aws.amazon.com/AmazonElastiCache/latest/dg/Clusters.RBAC.html#Access-string).
216+
217+
You can create an IAM-enabled user by using `IamUser` construct:
218+
219+
```ts
220+
const user = new elasticache.IamUser(this, 'User', {
221+
// set user id
222+
userId: 'my-user',
223+
224+
// set username
225+
userName: 'my-user',
226+
227+
// set access string
228+
accessControl: elasticache.AccessControl.fromAccessString("on ~* +@all"),
229+
});
230+
```
231+
232+
> NOTE: You can't set username in `IamUser` construct because IAM-enabled users must have matching user id and username. For more information, see [Limitations](https://docs.aws.amazon.com/AmazonElastiCache/latest/dg/auth-iam.html). The construct automatically sets the username to be the same as the user id.
233+
234+
If you want to create a password authenticated user, use `PasswordUser` construct:
235+
236+
```ts
237+
const user = new elasticache.PasswordUser(this, 'User', {
238+
// set user id
239+
userId: 'my-user-id',
240+
241+
// set access string
242+
accessControl: elasticache.AccessControl.fromAccessString("on ~* +@all"),
243+
244+
// set username
245+
userName: 'my-user-name',
246+
247+
// set up to two passwords
248+
passwords: [
249+
SecretValue.unsafePlainText('adminUserPassword123'),
250+
SecretValue.unsafePlainText('anotherAdminUserPassword123'),
251+
],
252+
});
253+
```
254+
255+
You can also create a no password required user by using `NoPasswordRequiredUser` construct:
256+
257+
```ts
258+
const user = new elasticache.NoPasswordUser(this, 'User', {
259+
// set user id
260+
userId: 'my-user-id',
261+
262+
// set access string
263+
accessControl: elasticache.AccessControl.fromAccessString("on ~* +@all"),
264+
265+
// set username
266+
userName: 'my-user-name',
267+
});
268+
```
269+
270+
### Default user
271+
272+
ElastiCache automatically creates a default user with both a user ID and username set to `default`. This default user cannot be modified or deleted. The user is created as a no password authentication user.
273+
274+
This user is intended for compatibility with the default behavior of previous Redis OSS versions and has an access string that permits it to call all commands and access all keys.
275+
276+
To use this automatically created default user in CDK, you can import it using `NoPasswordRequiredUser.fromUserAttributes` method. For more information on import methods, see the [Import an existing user and user group](#import-an-existing-user-and-user-group) section.
277+
278+
To add proper access control to a cache, replace the default user with a new one that is either disabled by setting the `accessString` to `off -@all` or secured with a strong password.
279+
280+
To change the default user, create a new default user with the username set to `default`. You can then swap it with the original default user.
281+
282+
For more information, see [Applying RBAC to a Cache for ElastiCache with Valkey or Redis OSS](https://docs.aws.amazon.com/AmazonElastiCache/latest/dg/Clusters.RBAC.html#rbac-using).
283+
284+
If you want to create a new default user, `userName` must be `default` and `userId` must not be `default` by using `NoPasswordRequiredUser` or `PasswordUser`:
285+
286+
```ts
287+
// use the original `default` user by using import method
288+
const defaultUser = elasticache.NoPasswordUser.fromUserAttributes(this, 'DefaultUser', {
289+
// userId and userName must be 'default'
290+
userId: 'default',
291+
});
292+
293+
// create a new default user
294+
const newDefaultUser = new elasticache.NoPasswordUser(this, 'NewDefaultUser', {
295+
// new default user id must not be 'default'
296+
userId: 'new-default',
297+
// default username must be 'default'
298+
userName: 'default',
299+
// set access string
300+
accessControl: elasticache.AccessControl.fromAccessString("on ~* +@all"),
301+
});
302+
```
303+
304+
> NOTE: You can't create a new default user using `IamUser` because an IAM-enabled user's username and user ID cannot be different.
305+
306+
### Add users to the user group
307+
308+
Next, use the `UserGroup` construct to create a user group and add users to it.
309+
Ensure that you include either the original default user or a new default user:
310+
311+
```ts
312+
declare const newDefaultUser: elasticache.IUserBase;
313+
declare const user: elasticache.IUserBase;
314+
declare const anotherUser: elasticache.IUserBase;
315+
316+
const userGroup = new elasticache.UserGroup(this, 'UserGroup', {
317+
// add users including default user
318+
users: [newDefaultUser, user],
319+
});
320+
321+
// you can also add a user by using addUser method
322+
userGroup.addUser(anotherUser);
323+
```
324+
325+
### Assign user group
326+
327+
Finally, assign a user group to cache:
328+
329+
```ts
330+
declare const vpc: ec2.Vpc;
331+
declare const userGroup: elasticache.UserGroup;
332+
333+
const serverlessCache = new elasticache.ServerlessCache(this, 'ServerlessCache', {
334+
engine: elasticache.CacheEngine.VALKEY_DEFAULT,
335+
serverlessCacheName: 'my-serverless-cache',
336+
vpc,
337+
// assign User Group
338+
userGroup,
339+
});
340+
341+
```
342+
343+
### Grant permissions to IAM-enabled users
344+
345+
If you create IAM-enabled users, `"elasticache:Connect"` action must be allowed for the users and cache.
346+
347+
> NOTE: You don't need grant permissions to no password required users or password authentication users.
348+
349+
For more information, see [Authenticating with IAM](https://docs.aws.amazon.com/AmazonElastiCache/latest/dg/auth-iam.html).
350+
351+
To grant permissions, you can use the `grantConnect` method in `IamUser` and `ServerlessCache` constructs:
352+
353+
```ts
354+
declare const user: elasticache.IamUser;
355+
declare const serverlessCache: elasticache.ServerlessCache;
356+
declare const role: iam.Role;
357+
358+
// grant "elasticache:Connect" action permissions to role
359+
user.grantConnect(role);
360+
serverlessCache.grantConnect(role);
361+
```
362+
363+
### Import an existing user and user group
364+
365+
You can import an existing user and user group by using import methods:
366+
367+
```ts
368+
const stack = new Stack();
369+
370+
const importedIamUser = elasticache.IamUser.fromUserId(this, 'ImportedIamUser', 'my-iam-user-id');
371+
372+
const importedPasswordUser = elasticache.PasswordUser.fromUserAttributes(stack, 'ImportedPasswordUser', {
373+
userId: 'my-password-user-id',
374+
});
375+
376+
const importedNoPasswordRequiredUser = elasticache.NoPasswordUser.fromUserAttributes(stack, 'ImportedNoPasswordUser', {
377+
userId: 'my-no-password-user-id',
378+
});
379+
380+
const importedUserGroup = elasticache.UserGroup.fromUserGroupAttributes(this, 'ImportedUserGroup', {
381+
userGroupName: 'my-user-group-id'
382+
});
383+
```

0 commit comments

Comments
 (0)