DynamoDB Accelerator (DAX) Cluster Encryption at Rest
Overview
This check verifies that Amazon DynamoDB Accelerator (DAX) clusters have server-side encryption at rest enabled. DAX is an in-memory caching service for DynamoDB that stores cached data on disk. Without encryption, this cached data is vulnerable to unauthorized access.
Risk
Unencrypted DAX clusters expose your cached DynamoDB data if:
- Storage infrastructure is compromised
- Administrative accounts are breached
- Storage media is lost or retired improperly
- Unauthorized backups or snapshots are taken
Attackers with low-level storage access could extract and analyze cached data offline, leading to data breaches and compliance violations.
Remediation Steps
Prerequisites
- Access to the AWS Console with permissions to manage DAX clusters
- An IAM role that grants DAX access to DynamoDB
- VPC with appropriate subnet group configured for DAX
Required IAM permissions
To create and manage DAX clusters, you need these permissions:
dax:CreateClusterdax:DescribeClustersdax:DeleteClusteriam:PassRole(for the DAX service role)ec2:DescribeSubnetsec2:DescribeSecurityGroups
Important Note
DAX cluster encryption cannot be changed after the cluster is created. If you have an unencrypted cluster, you must:
- Create a new cluster with encryption enabled
- Update your application to use the new cluster endpoint
- Delete the old unencrypted cluster
AWS Console Method
Step 1: Create a new encrypted DAX cluster
- Open the DynamoDB console
- In the left navigation, under DAX, click Clusters
- Click Create cluster
- Enter a Cluster name (e.g.,
my-encrypted-dax-cluster) - Select a Node type (e.g.,
dax.r5.large) - Choose the Cluster size (number of nodes)
- Under Encryption, ensure Enable encryption is checked (this is the default)
- Select your IAM service role for DynamoDB access
- Configure Subnet group and Security groups for your VPC
- Click Create cluster
Step 2: Update your application
- Wait for the new cluster status to show Available
- Copy the new cluster endpoint from the cluster details page
- Update your application configuration to use the new encrypted cluster endpoint
- Test your application thoroughly
Step 3: Delete the old unencrypted cluster
- Once your application is fully migrated, go back to DAX Clusters
- Select the old unencrypted cluster
- Click Delete
- Confirm the deletion
AWS CLI (optional)
Create a new encrypted DAX cluster:
aws dax create-cluster \
--cluster-name my-encrypted-dax-cluster \
--node-type dax.r5.large \
--replication-factor 3 \
--iam-role-arn arn:aws:iam::<account-id>:role/DAXServiceRole \
--subnet-group-name my-dax-subnet-group \
--security-group-ids sg-xxxxxxxxx \
--sse-specification Enabled=true \
--region us-east-1
List existing DAX clusters and check encryption status:
aws dax describe-clusters \
--region us-east-1 \
--query 'Clusters[*].{ClusterName:ClusterName,SSEDescription:SSEDescription}'
Describe a specific cluster to verify encryption:
aws dax describe-clusters \
--cluster-names my-encrypted-dax-cluster \
--region us-east-1 \
--query 'Clusters[0].{ClusterName:ClusterName,Status:Status,SSEDescription:SSEDescription}'
Replace:
<account-id>with your 12-digit AWS account IDmy-dax-subnet-groupwith your DAX subnet group namesg-xxxxxxxxxwith your security group ID
Delete an unencrypted cluster (after migration):
aws dax delete-cluster \
--cluster-name old-unencrypted-cluster \
--region us-east-1
CloudFormation (optional)
AWSTemplateFormatVersion: '2010-09-09'
Description: DynamoDB Accelerator (DAX) cluster with encryption at rest enabled
Parameters:
ClusterName:
Type: String
Description: Name of the DAX cluster
Default: encrypted-dax-cluster
NodeType:
Type: String
Description: The compute and memory capacity of the nodes
Default: dax.r5.large
AllowedValues:
- dax.r5.large
- dax.r5.xlarge
- dax.r5.2xlarge
- dax.r5.4xlarge
- dax.r5.8xlarge
- dax.r5.12xlarge
- dax.r5.16xlarge
- dax.r5.24xlarge
- dax.t3.small
- dax.t3.medium
ReplicationFactor:
Type: Number
Description: Number of nodes in the cluster (1-10)
Default: 3
MinValue: 1
MaxValue: 10
SubnetIds:
Type: List<AWS::EC2::Subnet::Id>
Description: Subnet IDs for the DAX subnet group
VpcSecurityGroupIds:
Type: List<AWS::EC2::SecurityGroup::Id>
Description: Security group IDs for the DAX cluster
Resources:
DAXSubnetGroup:
Type: AWS::DAX::SubnetGroup
Properties:
SubnetGroupName: !Sub '${ClusterName}-subnet-group'
Description: Subnet group for DAX cluster
SubnetIds: !Ref SubnetIds
DAXServiceRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub '${ClusterName}-service-role'
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: dax.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonDynamoDBReadOnlyAccess
DAXCluster:
Type: AWS::DAX::Cluster
Properties:
ClusterName: !Ref ClusterName
Description: Encrypted DAX cluster for DynamoDB caching
NodeType: !Ref NodeType
ReplicationFactor: !Ref ReplicationFactor
IAMRoleARN: !GetAtt DAXServiceRole.Arn
SubnetGroupName: !Ref DAXSubnetGroup
SecurityGroupIds: !Ref VpcSecurityGroupIds
SSESpecification:
SSEEnabled: true
Outputs:
ClusterArn:
Description: ARN of the DAX cluster
Value: !GetAtt DAXCluster.Arn
ClusterEndpoint:
Description: Cluster endpoint for DAX
Value: !GetAtt DAXCluster.ClusterDiscoveryEndpoint
ClusterName:
Description: Name of the DAX cluster
Value: !Ref DAXCluster
Deploy with:
aws cloudformation deploy \
--template-file dax-cluster.yaml \
--stack-name encrypted-dax-cluster \
--capabilities CAPABILITY_NAMED_IAM \
--parameter-overrides \
ClusterName=my-encrypted-dax \
NodeType=dax.r5.large \
ReplicationFactor=3 \
SubnetIds=subnet-xxxxxxxx,subnet-yyyyyyyy \
VpcSecurityGroupIds=sg-xxxxxxxxx \
--region us-east-1
Terraform (optional)
# variables.tf
variable "cluster_name" {
description = "Name of the DAX cluster"
type = string
default = "encrypted-dax-cluster"
}
variable "node_type" {
description = "The compute and memory capacity of the nodes"
type = string
default = "dax.r5.large"
}
variable "replication_factor" {
description = "Number of nodes in the cluster (1-10)"
type = number
default = 3
}
variable "subnet_ids" {
description = "List of subnet IDs for the DAX subnet group"
type = list(string)
}
variable "security_group_ids" {
description = "List of security group IDs for the DAX cluster"
type = list(string)
}
# main.tf
data "aws_caller_identity" "current" {}
resource "aws_iam_role" "dax" {
name = "${var.cluster_name}-service-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Service = "dax.amazonaws.com"
}
Action = "sts:AssumeRole"
}
]
})
}
resource "aws_iam_role_policy_attachment" "dax_dynamodb" {
role = aws_iam_role.dax.name
policy_arn = "arn:aws:iam::aws:policy/AmazonDynamoDBReadOnlyAccess"
}
resource "aws_dax_subnet_group" "main" {
name = "${var.cluster_name}-subnet-group"
subnet_ids = var.subnet_ids
}
resource "aws_dax_cluster" "main" {
cluster_name = var.cluster_name
iam_role_arn = aws_iam_role.dax.arn
node_type = var.node_type
replication_factor = var.replication_factor
subnet_group_name = aws_dax_subnet_group.main.name
security_group_ids = var.security_group_ids
server_side_encryption {
enabled = true
}
tags = {
Environment = "production"
Encryption = "enabled"
}
}
# outputs.tf
output "cluster_arn" {
description = "ARN of the DAX cluster"
value = aws_dax_cluster.main.arn
}
output "cluster_address" {
description = "DNS name of the DAX cluster"
value = aws_dax_cluster.main.cluster_address
}
output "configuration_endpoint" {
description = "Configuration endpoint for the DAX cluster"
value = aws_dax_cluster.main.configuration_endpoint
}
Deploy with:
terraform init
terraform apply \
-var="cluster_name=my-encrypted-dax" \
-var="node_type=dax.r5.large" \
-var="replication_factor=3" \
-var='subnet_ids=["subnet-xxxxxxxx","subnet-yyyyyyyy"]' \
-var='security_group_ids=["sg-xxxxxxxxx"]'
Verification
After creating your encrypted DAX cluster, verify the encryption:
- Go to the DynamoDB console
- In the left navigation, under DAX, click Clusters
- Click on your cluster name
- In the General section, confirm Encryption shows Enabled
CLI verification
aws dax describe-clusters \
--cluster-names my-encrypted-dax-cluster \
--region us-east-1 \
--query 'Clusters[0].{ClusterName:ClusterName,SSEDescription:SSEDescription}'
Expected output:
{
"ClusterName": "my-encrypted-dax-cluster",
"SSEDescription": {
"Status": "ENABLED"
}
}
Re-run the Prowler check:
prowler aws --checks dynamodb_accelerator_cluster_encryption_enabled
Additional Resources
- DAX Encryption at Rest Documentation
- DAX Developer Guide
- DAX Cluster Management
- IAM Policies for DAX Access
Notes
- Encryption cannot be modified: Once a DAX cluster is created, you cannot enable or disable encryption. You must create a new cluster with the desired encryption setting.
- No additional cost: Server-side encryption for DAX uses AWS-managed keys at no additional charge.
- Encryption in transit: Consider also enabling encryption in transit by setting
--cluster-endpoint-encryption-type TLSwhen creating the cluster for complete data protection. - Performance impact: Encryption at rest has minimal performance impact as it uses hardware-accelerated encryption.
- Node types: Encryption at rest is supported on all DAX node types.
- Subnet requirements: DAX clusters must be deployed in a VPC. Ensure your subnet group spans multiple Availability Zones for high availability.
- IAM role: The DAX service role needs permissions to access DynamoDB tables. Use least-privilege access by limiting which tables DAX can read from.