I contributed an L2 Construct for ElastiCache Serverless to open-constructs.
GitHub Repository: open-constructs/aws-cdk-library
I created this construct because ElastiCache Serverless seems likely to see increased demand, with features like Valkey support allowing usage from around $6 per month and Valkey 8.0 enabling faster scaling. It was also something I personally needed.
Get Started with Amazon ElastiCache for Valkey
Amazon ElastiCache version 8.0 for Valkey brings faster scaling and improved memory efficiency
In this article, I'll introduce how to use it.
Installing open-constructs
After creating your CDK project, simply run npm install
:
$ npx cdk init --language=typescript
$ npm install @open-constructs/aws-cdk
Usage
Here's the general flow:
- Create
User
for RBAC - Create
UserGroup
- Create
ServerlessCache
- Configure IAM policies (only if using IAM authentication)
- Other useful features (
connections
,metrics
)
Note that RBAC is only supported for Valkey
and Redis
. Therefore, steps 1 and 2 are not necessary when using Memcached
.
ElastiCache RBAC Documentation
The following examples assume using Valkey
.
1. Creating RBAC Users
First, create users for cache access control. There are three types: IAM authentication, password authentication, and no password authentication.
For IAM authentication users, use the IamUser
class. With IAM authentication, the user ID and username must match, so the Construct only allows setting the ID (the username is automatically set to the same value as the user ID).
The accessString
indicates permissions following Redis syntax. In this example, it allows all operations on all keys. Please refer to the documentation for details.
const user = IamUser(this, 'User', {
userId: 'my-iam-user',
accessString: 'on ~* +@all',
});
For password authentication users, use the PasswordUser
class. You can set up to two passwords, and the user ID and username can be set separately:
const user = PasswordUser(this, 'User', {
userId: 'my-user-id',
userName: 'my-user-name',
accessString: 'on ~* +@all',
passwords: [
cdk.SecretValue.unsafePlainText('strongPassword123'),
cdk.SecretValue.unsafePlainText('backupPassword456'),
],
});
For users without password authentication, use the NoPasswordRequiredUser
class. Note that this provides weaker security and should be used carefully:
const user = NoPasswordRequiredUser(this, 'User', {
userId: 'my-user-id',
userName: 'my-user-name',
accessString: 'on ~* +@all',
});
Important Note: The default User
This is perhaps the most complex aspect to understand.
ElastiCache requires that a user with the username default
must be included in the UserGroup
.
A user with the user ID default
is created by AWS by default (no password authentication, full permissions). This user cannot be edited or deleted.
Additionally, usernames must be unique within a region.
Therefore, you need to provide a user with the username default
and include it in the UserGroup
using one of these methods:
- Use the AWS-created default user (user ID and username are both
default
) - Create a new default user (user ID is not
default
, but username isdefault
)
To use the former in your Construct, import it using the import method. For the latter, create a new default user with the username set to default
. The latter approach is suitable if you want to customize the default user's permissions.
// Import the AWS-created default user
const defaultUser = NoPasswordRequiredUser.fromUserAttributes(this, 'DefaultUser', {
// Both user ID and username must be 'default'
userId: 'default',
userName: 'default',
});
// Create a new default user
const newDefaultUser = NoPasswordRequiredUser(this, 'NewDefaultUser', {
// User ID must not be 'default'
userId: 'new-default',
// Username must be 'default'
userName: 'default',
});
2. Creating UserGroup
Next, use the UserGroup
class to create a logical group of users that will be associated with the cache:
declare const newDefaultUser: User;
declare const user: User;
declare const anotherUser: User;
const userGroup = new UserGroup(this, 'UserGroup', {
// Register users. Must include a default user (username 'default')
users: [newDefaultUser, user],
});
// You can also add users using the addUser method
userGroup.addUser(anotherUser);
3. Creating ServerlessCache
Finally, use the ServerlessCache
class to create the cache and associate the user group:
declare const vpc: ec2.Vpc;
declare const userGroup: UserGroup;
const serverlessCache = new ServerlessCache(this, 'ServerlessCache', {
engine: Engine.VALKEY,
majorEngineVersion: MajorVersion.VER_8,
serverlessCacheName: 'my-serverless-cache',
vpc,
// Associate the user group
userGroup,
});
You can also configure CMK and snapshots. See the README
for all available properties.
open-constructs ElastiCache README
Note that at the time of writing, the CacheUsageLimits property is not supported due to limitations in the aws-cdk-lib
version used by open-constructs. I plan to add this property when it becomes available.
4. Configuring IAM Policies
If using IAM authentication users, you need to configure policies to allow connections:
IAM Authentication Documentation
The Construct provides a grantConnect
method for easy permission setup:
declare const user: IamUser;
declare const serverlessCache: ServerlessCache;
declare const role: iam.Role;
// Grant "elasticache:Connect" permission
user.grantConnect(role);
serverlessCache.grantConnect(role);
5. Other Useful Features
You can easily configure security groups using connections
:
declare const serverlessCache: ServerlessCache;
declare const instance: ec2.Instance;
// Allow connection from EC2 to cache on default port 6379
serverlessCache.connections.allowDefaultPortFrom(instance);
The Construct also makes it easy to create metrics and alarms. Dedicated methods are provided for BytesUsedForCache
and ElastiCacheProcessingUnits
metrics mentioned in the official documentation:
declare const serverlessCache: ServerlessCache;
// Get total bytes used for cache data (5-minute average)
const bytesUsedForCache = serverlessCache.metricBytesUsedForCache();
// Get total ElastiCacheProcessingUnits (ECPUs) consumed (5-minute average)
const elastiCacheProcessingUnits = serverlessCache.metricElastiCacheProcessingUnits();
// Create an alarm for ECPUs metric
elastiCacheProcessingUnits.createAlarm(this, 'ElastiCacheProcessingUnitsAlarm', {
threshold: 50,
evaluationPeriods: 1,
});
You can also define custom metrics using the metric
method. For available serverless cache metrics, refer to:
declare const serverlessCache: ServerlessCache;
// Define CacheHits metric - total number of successful read operations (5-minute average)
const cacheHits = serverlessCache.metric('CacheHits', { statistic: 'sum' });
Conclusion
Thanks to the thorough review by the reviewers, I believe this has become a user-friendly Construct. Please give it a try!
Top comments (0)