Skip to main content

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

  1. Open the Amazon Neptune console
  2. In the navigation pane, choose Databases
  3. Select your Neptune cluster
  4. 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
  5. 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
  6. 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:

  1. In the Neptune console, select your cluster
  2. Check the DB cluster members section
  3. Confirm you see instances in at least two different Availability Zones
  4. 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

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.