Skip to main content

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:

  1. Open the Amazon Neptune console.
  2. Click Databases in the left navigation.
  3. Click Create database.
  4. Under Engine options, select your preferred Neptune engine version.
  5. Under Settings, enter a DB cluster identifier (e.g., my-encrypted-neptune).
  6. Scroll to Encryption section.
  7. Check the box for Enable encryption.
  8. For Master key, choose:
    • (default) aws/rds for AWS-managed encryption, or
    • Select a Customer managed key for better control and auditability.
  9. Configure remaining settings (instance size, VPC, security groups) as needed.
  10. Click Create database.

To migrate data from an unencrypted cluster:

  1. Create an encrypted cluster following the steps above.
  2. Use the Neptune bulk loader or export/import tools to migrate data.
  3. Update your application connection strings to point to the new cluster.
  4. 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:

  1. Open the Neptune console.
  2. Click Databases and select your cluster.
  3. On the Configuration tab, verify that Encryption shows Enabled.
  4. 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

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)