- Original Author(s):: @dbartholomae
- Tracking Issue: #456
- API Bar Raiser: @corymhall
The aws-elasticache
construct library allows you to create Amazon ElastiCache
data stores with just a few lines of code. As with most construct libraries,
you can also easily define permissions and metrics using a simple API.
The amount of effort needed to create these resources is about the same as doing it using the AWS console, sometimes even less due to easier set up of VPC connectivity.
feat(elasticache): RedisReplicationGroup L2
Amazon ElastiCache is a fully managed, in-memory caching service supporting flexible, real-time use cases. You can use ElastiCache for caching, which accelerates application and database performance, or as a primary data store for use cases that don't require durability like session stores, gaming leaderboards, streaming, and analytics. ElastiCache is compatible with Redis and Memcached.
This module is part of the AWS Cloud Development Kit project. It allows you to define ElastiCache Redis replication groups.
In order to define a RedisReplicationGroup
(Redis (cluster mode disabled)),
you must specify the vpc to run the instance in.
import * as elasticache from '@aws-cdk/aws-elasticache';
import * as ec2 from '@aws-cdk/aws-ec2';
const vpc = new ec2.Vpc(this, 'Vpc');
new elasticache.RedisReplicationGroup(this, "RedisReplicationGroup", {
engineVersion: elasticache.RedisEngineVersion.VER_6_2,
vpc,
});
The above example implicitly defines the following resources:
- A
SubnetGroup
for all private subnets of the Vpc. - A
SecurityGroup
in the Vpc. - A
ReplicationGroup
with the security group attached, one shard with a Redis engine version 6.2 of sizecache.t2.micro
.
A RedisClusterReplicationGroup
is similar to a RedisReplicationGroup
, but
with multiple shards. The documentation calls them "Redis (cluster mode enabled)".
The main difference is that a RedisClusterReplicationGroup
requires a
numNodeGroups
to be set to a value of 2 or higher. Only RedisClusterReplicationGroup
s
must have automaticFailoverEnabled
enabled and exposes a configurationEndpoint
,
but cannot have a snapshottingClusterId
set.
The following resources are used as L1 constructs in the L2 constructs proposed here, but will not be exposed as L2 constructs themselves:
- SubnetGroup: Created based on the given vpcs subnets
- ParameterGroup: Created based on the engineVersion and whether cluster-mode is enabled
This RFC does not yet cover:
- CacheCluster
- GlobalReplicationGroup
- SecurityGroup
- User
- UserGroup
ElastiCache provides metrics that enable you to monitor your clusters. You can access these metrics through CloudWatch. ElastiCache provides both host-level metrics (for example, CPU usage) and metrics that are specific to the cache engine software (for example, cache gets and cache misses). These metrics are measured and published for each Cache node in 60-second intervals.
CDK provides methods for accessing metrics with default configuration,
such as metricCPUUtilization
, and metricMemory
. CDK also provides a generic
metric
method that can be used to produce metric configurations for any metric
provided by Amazon ElastiCache for Redis.
While ElastiCache manages rights to change the ElastiCache infrastructure via
IAM, it does not implement read and write permission management the same way.
Instead, it mainly relies on ensuring network boundaries, with an optional
AUTH
token that can be required for each request. In newer versions, there is
also Role-Based Access Control and Access Control Lists as an option to
authenticate.
IAM roles, users or groups which need to manage the ElastiCache resources should be granted IAM permissions.
Any object that implements the IGrantable
interface (i.e., has an associated principal)
can be granted permissions to a RedisReplicationGroup
by calling:
grant(principal, ...actions)
- grants the principal permission to a custom set of actions
import * as iam from '@aws-cdk/aws-iam';
const lambdaRole = new iam.Role(this, 'Role', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
});
// Give the role permissions to describe cache clusters
replicationGroup.grant(lambdaRole, 'elasticache:DescribeCacheClusters');
Any object that implements the IConnectable
interface can be given access to
the primary endpoint of a Redis Replication Group via
import * as elasticache from '@aws-cdk/aws-elasticache';
declare const vpc: ec2.Vpc;
declare const loadBalancer: elbv2.ApplicationLoadBalancer;
const replicationGroup = new elasticache.RedisReplicationGroup(this, "RedisReplicationGroup", {
engineVersion: elasticache.RedisEngineVersion.VER_6_2,
vpc,
});
replicationGroup.allowPrimaryAccessFrom(loadBalancer);
Similarly, there are allowReaderAccessFrom
and (for RedisClusterReplicationGroup
)
allowConfigurationAccessFrom
. These give access to the respective endpoints
on their respective ports.
You can use a Secret to set an AuthToken and share it with other services:
import * as secretsmanager from '@aws-cdk/aws-secretsmanager';
import * as ecs from '@aws-cdk/aws-ecs';
import * as elasticache from '@aws-cdk/aws-elasticache';
declare const vpc: ec2.Vpc;
const authToken = new secretsmanager.Secret(this, 'Secret');
const replicationGroup = new elasticache.RedisReplicationGroup(this, "RedisReplicationGroup", {
engineVersion: elasticache.RedisEngineVersion.VER_6_2,
authToken: authToken.secretValue,
vpc,
});
const cluster = new ecs.Cluster(this, "MyCluster", {
vpc: vpc
});
new ecs_patterns.ApplicationLoadBalancedFargateService(this, "MyFargateService", {
cluster: cluster, // Required
taskImageOptions: {
image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"),
secrets: {
REDIS_AUTH_TOKEN: ecs.Secret.fromSecretsManager(authToken),
}
},
});
For security reasons, you cannot assign a string to the authToken prop.
See the documentation on SecretValue
for more details.
Ticking the box below indicates that the public API of this RFC has been
signed-off by the API bar raiser (the status/api-approved
label was applied to the
RFC pull request):
- Signed-off by API Bar Raiser @corymhall
We are launching the RedisReplicationGroup
L2 construct for the
Amazon ElastiCache CDK module (@aws-cdk/aws-elasticache
). This launch supports
Amazon ElastiCache Redis replication groups (distributed in-memory data store
or cache environment) within the CDK.
Setting up AWS ElastiCache with AWS CDK minimizes work needed to provide access to other services and manage distributed in-memory data store or cache environments in the cloud.
There is a community offer to support with implementation right now.
The tracking Github issue for the module is in the top 10 upvoted issues (+123) with previous approaches to implement an L2 that were abandoned.
Setting up a CacheCluster requires setting up separate SubnetGroups that could actually be fully automated away in CDK. Managing VPCs and SecurityGroups becomes significant easier compared to manual setup or setup with CloudFormation.
The API design is based on one customer implementation only, so it might be missing insights from other use cases.
There are currently not enough resources to implement the full design, only part of it. Implementing the rest of the design later on might lead to information loss between now and then.
-
IEndpoint
-- interface to manage addresses and portsinterface IEndpoint { address: string; port: number; }
-
IRedisReplicationGroup
-- interface for defined and imported ReplicationGroups (cluster mode disabled)interface IRedisReplicationGroup extends // Since RedisReplicationGroup will extend Resource cdk.IResource, // To open network conns between ElastiCache and services that should access it ec2.IConnectable { readonly primaryEndpoint: IEndpoint; readonly readerEndpoint: IEndpoint; allowReaderAccessFrom(peer: IConnectable, description?: string): void; allowPrimaryAccessFrom(peer: IConnectable, description?: string): void; grant(grantee: iam.IGrantable, ...actions: string[]): iam.Grant; metric(metricName: string, props?: cloudwatch.MetricOptions): cloudwatch.Metric; // Some canned metrics as well like `metricCPUUtilization` }
-
IRedisClusterReplicationGroup
-- interface for defined and imported ReplicationGroups (cluster mode enabled)interface IRedisClusterReplicationGroup extends IRedisReplicationGroup { readonly configurationEndpoint: IEndpoint; allowConfigurationAccessFrom(peer: IConnectable, description?: string): void; }
-
RedisReplicationGroupBase
-- abstract base ReplicationGroup class with some helper props/methodsclass CacheNodeType { // Cache Node types are derived from InstanceTypes by prepending `cache.` static fromInstanceType(instanceType: ec2.InstanceType): CacheNodeType {} } enum RedisEngineVersion { VER_6_2 = '6.2', // ... } interface RedisReplicationGroupBaseProps { engineVersion: RedisEngineVersion, // Used to define whether cluster mode is enabled or not numNodeGroups: number, authToken?: SecretValue, transitEncryptionEnabled?: boolean, kmsKey?: IKey, atRestEncryptionEnabled?: boolean, // This also automatically sets dataTieringEnabled cacheNodeType?: CacheNodeType, // By default derived from the node id in the stack replicationGroupDescription?: string, autoMinorVersionUpgrade?: boolean, multiAzEnabled?: boolean, notificationTopic?: ITopic, numCacheClusters?: number, port?: number, preferredCacheClusterAZs?: string[], replicasPerNodeGroup?: number, replicationGroupId?: string, // Names that are reserved to be implemented over time globalReplicationGroup: IGlobalReplicationGroup, logDeliveryConfigurations: ILogDeliveryConfiguration[], nodeGroupConfiguration: INodeGroupConfiguration, preferredMaintenanceWindow: IPreferredMaintenanceWindow, primaryClusterId: string, snapshot: ISnapshot, userGroups: UserGroup[] } abstract class RedisReplicationGroupBase implements IRedisReplicationGroup, // Since RedisReplicationGroup will extend Resource cdk.IResource, // To open network conns between ElastiCache and services that should access it ec2.IConnectable, // RedisReplicationGroup allows tagging cdk.ITaggable { public readonly clusterEnabled: boolean; constructor(protected readonly props: RedisReplicationGroupBaseProps = {}) {} grant(grantee: iam.IGrantable, ...actions: string[]): iam.Grant {}; allowPrimaryAccessFrom(peer: IConnectable, description = "Redis access"): void {}; allowReaderAccessFrom(peer: IConnectable, description?: string): void {}; metric(metricName: string, props?: cloudwatch.MetricOptions): cloudwatch.Metric {}; // Some canned metrics as well like `metricCPUUtilization` }
No other modules are affected.
No.
No problems or risks of implementing this feature as a whole, though the design outlined above may have drawbacks, as detailed below in "alternative solutions".
- Have fewer default parameters and more required parameters. This would make the resource harder to use but might prevent situations where the user is relying on defaults without understanding them. The choice of default parameters tries to minimize these risks.
- Implement
RedisReplicationGroup
andRedisClusterReplicationGroup
as a single construct. This is closer to the interface given by CloudFormation, but is less intuitive, as both the inputs and outputs differ between Redis (cluster mode enabled) and Redis (cluster mode disabled).
The first implementation will focus on Redis replication groups and related resources only, which will be tested with a beta customer.
There is no timeline for implementing the other resources, but the library should give structure so that other resources can be implemented with less effort than before when needed.
The implementation only covers Redis replication groups. The rest of the implementation needs to be handled later.