Description

Ensure that no Amazon ElastiCache cluster or node (Redis OSS, Valkey or Memcached) uses a cache subnet group that contains public subnets. A subnet is considered public when its route table has a default route (0.0.0.0/0) to an internet gateway. Cache subnet groups should contain only private subnets.

Rationale

A cache placed in a public subnet sits in an Internet-routed network segment, so a misconfigured security group can expose it directly to the Internet. This can lead to unauthorized reads and key dumps, cache poisoning or key tampering, scanning and denial-of-service attacks, and can give an attacker a path to move further into the VPC. Caches should be placed only in private subnets, with security groups that allow only the required ports from trusted sources. For access from outside the VPC, use VPC peering, VPN or AWS PrivateLink.

Impact

  • Keeps cache nodes out of Internet-routed subnets

  • Public subnets that are not used by any node can be removed from the subnet group without downtime

  • A node that is already running in a public subnet cannot be moved; the cache must be recreated in a private subnet group (for Redis OSS and Valkey, from a backup), which requires changing the endpoint used by applications

Default Value

There is no default subnet type for ElastiCache. The subnets used are those of the cache subnet group selected when the cluster is created.

Pre-Requisites

  • IAM permissions: elasticache:DescribeCacheClusters, elasticache:DescribeCacheSubnetGroups, elasticache:ModifyCacheSubnetGroup, elasticache:CreateCacheSubnetGroup, ec2:DescribeSubnets and ec2:DescribeRouteTables

  • Private subnets (without a default route to an internet gateway) in the cache's VPC, in the Availability Zones the cache uses

  • If the cache must be recreated, a recent backup and a maintenance window to switch application endpoints

Remediation

Test Plan

Console:

  1. Sign in to the AWS Management Console at https://console.aws.amazon.com.

  2. Open the Amazon ElastiCache console and select Subnet groups.

  3. Open each subnet group used by a cache and note its subnets.

  4. Open the Amazon VPC console, select Subnets, select each noted subnet and open the Route table tab.

  5. Check whether the route table has a route with destination 0.0.0.0/0 and a target that starts with igw-.

  6. Repeat for each region in use.

  7. If any subnet group used by a cache contains such a subnet, follow the implementation steps.

CLI:

List the cache clusters and nodes with their subnet group:

aws elasticache describe-cache-clusters --region <REGION> --query "CacheClusters[].[CacheClusterId,Engine,ReplicationGroupId,CacheSubnetGroupName]" --output table

List the subnets of a cache subnet group:

aws elasticache describe-cache-subnet-groups --cache-subnet-group-name <CACHE_SUBNET_GROUP_NAME> --region <REGION> --query "CacheSubnetGroups[].[VpcId,Subnets[].SubnetIdentifier]"

Show the routes of the route table associated with each subnet:

aws ec2 describe-route-tables --region <REGION> --filters Name=association.subnet-id,Values=<SUBNET_ID> --query "RouteTables[].Routes[].[DestinationCidrBlock,GatewayId]" --output table

If no route table is returned, the subnet uses the VPC's main route table:

aws ec2 describe-route-tables --region <REGION> --filters Name=vpc-id,Values=<VPC_ID> Name=association.main,Values=true --query "RouteTables[].Routes[].[DestinationCidrBlock,GatewayId]" --output table

A cluster or node fails if any subnet in its cache subnet group has a route with destination 0.0.0.0/0 and a gateway ID that starts with igw-.

Implementation Steps

Console:

  1. Sign in to the AWS Management Console at https://console.aws.amazon.com.

  2. Open the Amazon ElastiCache console and select Subnet groups.

  3. Select the subnet group used by the cache and choose Edit.

  4. Remove the public subnets, add private subnets in the same Availability Zones if needed, and save the changes. A subnet that currently hosts a cache node cannot be removed.

  5. If a cache node is running in a public subnet:

    • create a new subnet group that contains only private subnets,

    • create a new cache in that subnet group (for Redis OSS or Valkey, restore it from a backup of the existing cache),

    • update applications to use the new cache endpoint, then delete the old cache.

  6. Repeat for each affected cache in each region in use.

CLI:

The subnet group of an existing cache cannot be changed with modify-cache-cluster, so instead replace the subnets of the subnet group with private subnets (the list must still include every subnet that currently hosts a node):

aws elasticache modify-cache-subnet-group --cache-subnet-group-name <CACHE_SUBNET_GROUP_NAME> --subnet-ids <PRIVATE_SUBNET_ID_1> <PRIVATE_SUBNET_ID_2> --region <REGION>

If the cache must be recreated, create a subnet group that contains only private subnets:

aws elasticache create-cache-subnet-group --cache-subnet-group-name <NEW_CACHE_SUBNET_GROUP_NAME> --cache-subnet-group-description "Private subnets for ElastiCache" --subnet-ids <PRIVATE_SUBNET_ID_1> <PRIVATE_SUBNET_ID_2> --region <REGION>

Backout Plan

Before making changes, save the current subnet group configuration:

aws elasticache describe-cache-subnet-groups --cache-subnet-group-name <CACHE_SUBNET_GROUP_NAME> --region <REGION> > cache-subnet-group-backup.json

To roll back:

  1. Sign in to the AWS Management Console at https://console.aws.amazon.com.

  2. Open the Amazon ElastiCache console and select Subnet groups.

  3. Select the subnet group, choose Edit and add back the original subnets from the saved backup.

  4. Save the changes.

  5. If a new cache was created, point applications back to the original cache endpoint (keep the original cache until the new one is verified).

CLI:

aws elasticache modify-cache-subnet-group --cache-subnet-group-name <CACHE_SUBNET_GROUP_NAME> --subnet-ids <ORIGINAL_SUBNET_ID_1> <ORIGINAL_SUBNET_ID_2> --region <REGION>

Note: rolling back allows cache nodes to be placed in Internet-routed subnets again.

Reference