Neptune Cluster Storage Encrypted at Rest
Overview
This check verifies that your Amazon Neptune database clusters have encryption at rest enabled. Neptune is a graph database service, and like other databases, the data it stores should be protected from unauthorized access even if someone gains access to the underlying storage.
Risk
When Neptune storage is not encrypted, your data is more vulnerable:
- Data exposure: Anyone who gains access to the underlying storage volumes or snapshots can read your data directly.
- Snapshot leaks: If an unencrypted snapshot is accidentally shared or made public, all data in it is exposed.
- Compliance violations: Many regulations (PCI-DSS, ISO 27001, KISA-ISMS-P) require encryption at rest for sensitive data.
Severity: High
Remediation Steps
Prerequisites
- AWS account access with permissions to create/modify Neptune clusters
- A VPC with appropriate subnets for Neptune
- (Recommended) A KMS key if you want to use customer-managed encryption
Important: You cannot enable encryption on an existing unencrypted Neptune cluster. You must create a new encrypted cluster and migrate your data.
AWS Console Method
To create a new encrypted Neptune cluster:
- Open the Amazon Neptune console.
- Click Databases in the left navigation.
- Click Create database.
- Under Engine options, select your preferred Neptune engine version.
- Under Settings, enter a DB cluster identifier (e.g.,
my-encrypted-neptune). - Scroll to Encryption section.
- Check the box for Enable encryption.
- For Master key, choose:
- (default) aws/rds for AWS-managed encryption, or
- Select a Customer managed key for better control and auditability.
- Configure remaining settings (instance size, VPC, security groups) as needed.
- Click Create database.
To migrate data from an unencrypted cluster:
- Create an encrypted cluster following the steps above.
- Use the Neptune bulk loader or export/import tools to migrate data.
- Update your application connection strings to point to the new cluster.
- After verifying the migration, delete the old unencrypted cluster.
AWS CLI (optional)
Check if existing clusters are encrypted:
aws neptune describe-db-clusters \
--region us-east-1 \
--query "DBClusters[*].{ClusterID:DBClusterIdentifier,Encrypted:StorageEncrypted,KmsKeyId:KmsKeyId}" \
--output table
Create a new encrypted Neptune cluster with AWS-managed key:
aws neptune create-db-cluster \
--region us-east-1 \
--db-cluster-identifier my-encrypted-neptune-cluster \
--engine neptune \
--storage-encrypted \
--db-subnet-group-name <your-subnet-group> \
--vpc-security-group-ids <your-security-group-id>
Create a new encrypted Neptune cluster with a Customer Managed Key (CMK):
aws neptune create-db-cluster \
--region us-east-1 \
--db-cluster-identifier my-encrypted-neptune-cluster \
--engine neptune \
--storage-encrypted \
--kms-key-id arn:aws:kms:us-east-1:123456789012:key/your-kms-key-id \
--db-subnet-group-name <your-subnet-group> \
--vpc-security-group-ids <your-security-group-id>
Add an instance to the cluster:
aws neptune create-db-instance \
--region us-east-1 \
--db-instance-identifier my-encrypted-neptune-instance-1 \
--db-instance-class db.r5.large \
--engine neptune \
--db-cluster-identifier my-encrypted-neptune-cluster
CloudFormation (optional)
AWSTemplateFormatVersion: '2010-09-09'
Description: Encrypted Neptune DB Cluster
Parameters:
DBClusterIdentifier:
Type: String
Description: Identifier for the Neptune DB cluster
Default: my-encrypted-neptune-cluster
DBSubnetGroupName:
Type: String
Description: Name of the DB subnet group
VPCSecurityGroupId:
Type: AWS::EC2::SecurityGroup::Id
Description: Security group for Neptune cluster
KMSKeyArn:
Type: String
Description: ARN of the KMS key for encryption (leave empty for AWS-managed key)
Default: ''
Conditions:
UseCustomerManagedKey: !Not [!Equals [!Ref KMSKeyArn, '']]
Resources:
NeptuneDBCluster:
Type: AWS::Neptune::DBCluster
Properties:
DBClusterIdentifier: !Ref DBClusterIdentifier
DBSubnetGroupName: !Ref DBSubnetGroupName
VpcSecurityGroupIds:
- !Ref VPCSecurityGroupId
StorageEncrypted: true
KmsKeyId: !If [UseCustomerManagedKey, !Ref KMSKeyArn, !Ref 'AWS::NoValue']
DeletionProtection: true
BackupRetentionPeriod: 7
Tags:
- Key: Environment
Value: Production
NeptuneDBInstance:
Type: AWS::Neptune::DBInstance
Properties:
DBClusterIdentifier: !Ref NeptuneDBCluster
DBInstanceClass: db.r5.large
DBInstanceIdentifier: !Sub '${DBClusterIdentifier}-instance-1'
Outputs:
ClusterEndpoint:
Description: Neptune cluster endpoint
Value: !GetAtt NeptuneDBCluster.Endpoint
ClusterReadEndpoint:
Description: Neptune cluster read endpoint
Value: !GetAtt NeptuneDBCluster.ReadEndpoint
Deploy the stack:
aws cloudformation create-stack \
--region us-east-1 \
--stack-name encrypted-neptune-stack \
--template-body file://template.yaml \
--parameters \
ParameterKey=DBSubnetGroupName,ParameterValue=<your-subnet-group> \
ParameterKey=VPCSecurityGroupId,ParameterValue=<your-security-group-id> \
ParameterKey=KMSKeyArn,ParameterValue=arn:aws:kms:us-east-1:123456789012:key/your-key-id
Terraform (optional)
variable "cluster_identifier" {
description = "Identifier for the Neptune cluster"
type = string
default = "my-encrypted-neptune-cluster"
}
variable "subnet_ids" {
description = "List of subnet IDs for the Neptune subnet group"
type = list(string)
}
variable "vpc_security_group_ids" {
description = "List of VPC security group IDs"
type = list(string)
}
variable "kms_key_arn" {
description = "ARN of the KMS key for encryption (optional, uses AWS-managed key if not specified)"
type = string
default = null
}
resource "aws_neptune_subnet_group" "main" {
name = "${var.cluster_identifier}-subnet-group"
subnet_ids = var.subnet_ids
tags = {
Name = "${var.cluster_identifier}-subnet-group"
}
}
resource "aws_neptune_cluster" "encrypted" {
cluster_identifier = var.cluster_identifier
engine = "neptune"
neptune_subnet_group_name = aws_neptune_subnet_group.main.name
vpc_security_group_ids = var.vpc_security_group_ids
storage_encrypted = true
kms_key_arn = var.kms_key_arn
backup_retention_period = 7
deletion_protection = true
skip_final_snapshot = false
final_snapshot_identifier = "${var.cluster_identifier}-final-snapshot"
apply_immediately = false
tags = {
Environment = "Production"
}
}
resource "aws_neptune_cluster_instance" "main" {
count = 1
cluster_identifier = aws_neptune_cluster.encrypted.id
instance_class = "db.r5.large"
identifier = "${var.cluster_identifier}-instance-${count.index + 1}"
neptune_subnet_group_name = aws_neptune_subnet_group.main.name
tags = {
Name = "${var.cluster_identifier}-instance-${count.index + 1}"
}
}
output "cluster_endpoint" {
description = "Neptune cluster endpoint"
value = aws_neptune_cluster.encrypted.endpoint
}
output "cluster_reader_endpoint" {
description = "Neptune cluster reader endpoint"
value = aws_neptune_cluster.encrypted.reader_endpoint
}
Verification
After creating your encrypted cluster:
- Open the Neptune console.
- Click Databases and select your cluster.
- On the Configuration tab, verify that Encryption shows Enabled.
- If using a CMK, verify the KMS key ARN matches your expected key.
CLI verification
aws neptune describe-db-clusters \
--region us-east-1 \
--db-cluster-identifier my-encrypted-neptune-cluster \
--query "DBClusters[0].{Encrypted:StorageEncrypted,KmsKeyId:KmsKeyId}"
Expected output:
{
"Encrypted": true,
"KmsKeyId": "arn:aws:kms:us-east-1:123456789012:key/your-kms-key-id"
}
Additional Resources
- AWS Neptune Encryption at Rest Documentation
- AWS Neptune Security Hub Controls
- AWS KMS Best Practices
- Prowler Check Documentation
Notes
- Encryption cannot be enabled on existing clusters: You must create a new encrypted cluster and migrate data. Plan for downtime or use a blue-green deployment strategy.
- Snapshots inherit encryption: Snapshots of encrypted clusters are automatically encrypted with the same key.
- Cross-region considerations: If you copy snapshots to another region, ensure the KMS key is available in that region or use a different key.
- Customer-managed keys (CMK): Using a CMK gives you control over key rotation, access policies, and audit logging. This is recommended for production workloads.
- Performance impact: Encryption at rest has minimal performance impact as it uses hardware-accelerated AES-256 encryption.
Compliance Frameworks
This check helps satisfy requirements in:
- C5 (Cloud Computing Compliance Criteria Catalogue)
- ISO 27001 (Information Security Management)
- KISA-ISMS-P (Korea Information Security Management System)
- PCI-DSS (Payment Card Industry Data Security Standard)