Neptune Cluster Has Multi-AZ Enabled
Overview
This check verifies that your Amazon Neptune DB clusters have Multi-AZ deployment enabled. Multi-AZ means your cluster has read-replica instances distributed across multiple Availability Zones, providing automatic failover capability if the primary instance fails.
Risk
Running a Neptune cluster in a single Availability Zone creates a single point of failure:
- Downtime during AZ outages: If the AZ hosting your cluster experiences issues, your database becomes unavailable until the primary instance is rebuilt
- Longer recovery times: Manual recovery is required without read replicas, increasing the risk of configuration errors
- Compliance impact: Single-AZ deployments may not meet availability requirements for ISO27001 or KISA-ISMS-P frameworks
Remediation Steps
Prerequisites
- AWS Console access with permissions to modify Neptune clusters
- A DB subnet group that spans at least two Availability Zones
AWS Console Method
- Open the Amazon Neptune console
- In the navigation pane, choose Databases
- Select your Neptune cluster
- Review the cluster members:
- If you only see one instance (the primary), you need to add read replicas
- If replicas exist but are all in the same AZ as the primary, you need replicas in different AZs
- To add a read replica:
- Choose Actions > Add reader
- For Availability Zone, select a different AZ than your primary instance
- Choose an appropriate DB instance class (match your primary for failover consistency)
- Configure other settings as needed
- Choose Add reader
- Repeat step 5 to add another replica in a third AZ for additional redundancy
AWS CLI (optional)
Check current cluster configuration:
aws neptune describe-db-clusters \
--db-cluster-identifier <your-cluster-id> \
--region us-east-1 \
--query 'DBClusters[0].{ClusterID:DBClusterIdentifier,Members:DBClusterMembers}'
Add a read replica in a different Availability Zone:
aws neptune create-db-instance \
--db-instance-identifier <your-cluster-id>-replica-1 \
--db-cluster-identifier <your-cluster-id> \
--db-instance-class db.r5.large \
--engine neptune \
--availability-zone us-east-1b \
--region us-east-1
Add a second read replica in a third AZ:
aws neptune create-db-instance \
--db-instance-identifier <your-cluster-id>-replica-2 \
--db-cluster-identifier <your-cluster-id> \
--db-instance-class db.r5.large \
--engine neptune \
--availability-zone us-east-1c \
--region us-east-1
Set promotion tier (optional):
The --promotion-tier parameter (0-15) determines failover priority. Lower values have higher priority.
CloudFormation (optional)
This template creates a Neptune cluster with a primary instance and two read replicas across three Availability Zones:
AWSTemplateFormatVersion: '2010-09-09'
Description: Neptune Multi-AZ Cluster with Read Replicas
Parameters:
DBClusterIdentifier:
Type: String
Description: Identifier for the Neptune DB cluster
Default: my-neptune-cluster
DBInstanceClass:
Type: String
Description: Instance class for Neptune instances
Default: db.r5.large
AllowedValues:
- db.r5.large
- db.r5.xlarge
- db.r5.2xlarge
- db.r5.4xlarge
- db.r5.8xlarge
- db.r5.12xlarge
VPCSecurityGroupId:
Type: AWS::EC2::SecurityGroup::Id
Description: Security group for Neptune cluster
DBSubnetGroupName:
Type: String
Description: DB subnet group name (must span multiple AZs)
Resources:
NeptuneDBCluster:
Type: AWS::Neptune::DBCluster
Properties:
DBClusterIdentifier: !Ref DBClusterIdentifier
DBSubnetGroupName: !Ref DBSubnetGroupName
VpcSecurityGroupIds:
- !Ref VPCSecurityGroupId
StorageEncrypted: true
DeletionProtection: true
BackupRetentionPeriod: 7
PreferredBackupWindow: "02:00-03:00"
PreferredMaintenanceWindow: "sun:04:00-sun:05:00"
NeptunePrimaryInstance:
Type: AWS::Neptune::DBInstance
Properties:
DBClusterIdentifier: !Ref NeptuneDBCluster
DBInstanceIdentifier: !Sub "${DBClusterIdentifier}-primary"
DBInstanceClass: !Ref DBInstanceClass
AvailabilityZone: us-east-1a
NeptuneReadReplica1:
Type: AWS::Neptune::DBInstance
Properties:
DBClusterIdentifier: !Ref NeptuneDBCluster
DBInstanceIdentifier: !Sub "${DBClusterIdentifier}-replica-1"
DBInstanceClass: !Ref DBInstanceClass
AvailabilityZone: us-east-1b
NeptuneReadReplica2:
Type: AWS::Neptune::DBInstance
Properties:
DBClusterIdentifier: !Ref NeptuneDBCluster
DBInstanceIdentifier: !Sub "${DBClusterIdentifier}-replica-2"
DBInstanceClass: !Ref DBInstanceClass
AvailabilityZone: us-east-1c
Outputs:
ClusterEndpoint:
Description: Neptune cluster endpoint for write operations
Value: !GetAtt NeptuneDBCluster.Endpoint
ClusterReadEndpoint:
Description: Neptune cluster reader endpoint for read operations
Value: !GetAtt NeptuneDBCluster.ReadEndpoint
ClusterPort:
Description: Neptune cluster port
Value: !GetAtt NeptuneDBCluster.Port
Terraform (optional)
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
variable "cluster_identifier" {
description = "Identifier for the Neptune cluster"
type = string
default = "my-neptune-cluster"
}
variable "instance_class" {
description = "Instance class for Neptune instances"
type = string
default = "db.r5.large"
}
variable "vpc_security_group_ids" {
description = "List of VPC security group IDs"
type = list(string)
}
variable "subnet_group_name" {
description = "Name of the DB subnet group"
type = string
}
# Neptune DB Cluster
resource "aws_neptune_cluster" "main" {
cluster_identifier = var.cluster_identifier
engine = "neptune"
neptune_subnet_group_name = var.subnet_group_name
vpc_security_group_ids = var.vpc_security_group_ids
storage_encrypted = true
deletion_protection = true
backup_retention_period = 7
preferred_backup_window = "02:00-03:00"
preferred_maintenance_window = "sun:04:00-sun:05:00"
skip_final_snapshot = false
final_snapshot_identifier = "${var.cluster_identifier}-final-snapshot"
tags = {
Name = var.cluster_identifier
}
}
# Primary Instance in AZ 1
resource "aws_neptune_cluster_instance" "primary" {
cluster_identifier = aws_neptune_cluster.main.id
identifier = "${var.cluster_identifier}-primary"
instance_class = var.instance_class
availability_zone = "us-east-1a"
promotion_tier = 0
tags = {
Name = "${var.cluster_identifier}-primary"
}
}
# Read Replica in AZ 2
resource "aws_neptune_cluster_instance" "replica_1" {
cluster_identifier = aws_neptune_cluster.main.id
identifier = "${var.cluster_identifier}-replica-1"
instance_class = var.instance_class
availability_zone = "us-east-1b"
promotion_tier = 1
tags = {
Name = "${var.cluster_identifier}-replica-1"
}
}
# Read Replica in AZ 3
resource "aws_neptune_cluster_instance" "replica_2" {
cluster_identifier = aws_neptune_cluster.main.id
identifier = "${var.cluster_identifier}-replica-2"
instance_class = var.instance_class
availability_zone = "us-east-1c"
promotion_tier = 2
tags = {
Name = "${var.cluster_identifier}-replica-2"
}
}
output "cluster_endpoint" {
description = "Neptune cluster endpoint for write operations"
value = aws_neptune_cluster.main.endpoint
}
output "cluster_reader_endpoint" {
description = "Neptune cluster reader endpoint for read operations"
value = aws_neptune_cluster.main.reader_endpoint
}
output "cluster_port" {
description = "Neptune cluster port"
value = aws_neptune_cluster.main.port
}
Verification
After adding read replicas, verify your Multi-AZ configuration:
- In the Neptune console, select your cluster
- Check the DB cluster members section
- Confirm you see instances in at least two different Availability Zones
- Verify all instances show Available status
CLI verification commands
# List all instances in the cluster with their AZs
aws neptune describe-db-instances \
--filters Name=db-cluster-id,Values=<your-cluster-id> \
--region us-east-1 \
--query 'DBInstances[*].{Instance:DBInstanceIdentifier,AZ:AvailabilityZone,Status:DBInstanceStatus}'
Expected output shows instances in different AZs:
[
{ "Instance": "my-cluster-primary", "AZ": "us-east-1a", "Status": "available" },
{ "Instance": "my-cluster-replica-1", "AZ": "us-east-1b", "Status": "available" },
{ "Instance": "my-cluster-replica-2", "AZ": "us-east-1c", "Status": "available" }
]
Additional Resources
- Amazon Neptune DB Clusters
- High Availability for Neptune
- Neptune Failover
- Prowler Neptune Check Documentation
Notes
- Cost consideration: Each read replica incurs additional compute costs. Plan your replica count based on availability requirements and budget.
- Instance sizing: AWS recommends using the same instance class for replicas as your primary to ensure consistent performance after failover.
- Replication lag: Read replicas typically have less than 100ms replication lag, but this can increase during heavy write workloads.
- Failover time: Automatic failover typically completes within 30 seconds to a few minutes, depending on database activity.
- Promotion tier: Set lower promotion tier values (0-15) for replicas you want to prioritize during failover.