DEV Community

Cover image for ElastiCache Serverless: L2 CDK Construct Released in open-constructs
Matsuda for AWS Community Builders

Posted on

ElastiCache Serverless: L2 CDK Construct Released in open-constructs

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
Enter fullscreen mode Exit fullscreen mode

Usage

Here's the general flow:

  1. Create User for RBAC
  2. Create UserGroup
  3. Create ServerlessCache
  4. Configure IAM policies (only if using IAM authentication)
  5. 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.

Access String Documentation

const user = IamUser(this, 'User', {
  userId: 'my-iam-user',
  accessString: 'on ~* +@all',
});
Enter fullscreen mode Exit fullscreen mode

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'),
  ],
});
Enter fullscreen mode Exit fullscreen mode

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',
});
Enter fullscreen mode Exit fullscreen mode

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.

RBAC Usage Documentation

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 is default)

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',
});
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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,
});
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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,
});
Enter fullscreen mode Exit fullscreen mode

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' });
Enter fullscreen mode Exit fullscreen mode

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)