Skip to content

OpenSearch domains should have at least three data nodes

An OpenSearch cluster with fewer than three data nodes or without zone awareness has a single point of failure at the AZ level. If the sole AZ, or one of two AZs hosting data nodes, goes down, the cluster loses quorum or becomes read-only, taking down search and analytics workloads with it.

Three data nodes across multiple AZs let the cluster redistribute shards automatically during an AZ failure. This is the minimum configuration AWS recommends for production OpenSearch clusters, and it's the threshold where fault tolerance becomes meaningful.

Retrofit consideration

Increasing instance_count on a running domain triggers a blue/green deployment. Enabling zone_awareness_enabled on an existing single-AZ cluster requires shard rebalancing across new AZs, which can temporarily increase cluster load and latency. Plan changes during a maintenance window.

Implementation

Choose the approach that matches how you manage Terraform.

If you use terraform-aws-modules/opensearch/aws, set the right module inputs for this control. You can later migrate to the compliance.tf module with minimal changes because it is compatible by design.

module "opensearch" {
  source  = "terraform-aws-modules/opensearch/aws"
  version = ">=2.0.0,<3.0.0"

  advanced_security_options = {
    enabled                        = true
    internal_user_database_enabled = true
    master_user_options = {
      master_user_name     = "admin"
      master_user_password = "P0fix-Test-2026!"
    }
  }
  auto_tune_options = {
    desired_state = "DISABLED"
  }
  domain_endpoint_options = {
    enforce_https       = true
    tls_security_policy = "Policy-Min-TLS-1-2-2019-07"
  }
  domain_name = "abc123"
  ebs_options = {
    ebs_enabled = true
    volume_size = 20
    volume_type = "gp3"
  }
  engine_version = "OpenSearch_2.11"

  cluster_config = {
    zone_awareness_enabled = true
  }
}

Use AWS provider resources directly. See docs for the resources involved: aws_opensearch_domain.

resource "aws_opensearch_domain" "this" {
  advanced_security_options {
    enabled                        = true
    internal_user_database_enabled = true

    master_user_options {
      master_user_name     = "admin"
      master_user_password = "ChangeMe123!"
    }
  }

  auto_tune_options {
    desired_state = "DISABLED"
  }

  cognito_options {
    enabled          = true
    identity_pool_id = "us-east-1:12345678-1234-1234-1234-123456789012"
    role_arn         = "arn:aws:iam::123456789012:role/example-role"
    user_pool_id     = "us-east-1_AbCdEfGhI"
  }

  domain_endpoint_options {
    enforce_https       = true
    tls_security_policy = "Policy-Min-TLS-1-2-2019-07"
  }

  domain_name = "pofix-abc123"

  ebs_options {
    ebs_enabled = true
    volume_size = 10
    volume_type = "gp3"
  }

  encrypt_at_rest {
    enabled = true
  }

  engine_version = "OpenSearch_2.11"

  log_publishing_options {
    cloudwatch_log_group_arn = local.es_log_group_arn
    log_type                 = "AUDIT_LOGS"
  }
  log_publishing_options {
    cloudwatch_log_group_arn = local.es_log_group_arn
    log_type                 = "ES_APPLICATION_LOGS"
  }
  log_publishing_options {
    cloudwatch_log_group_arn = local.es_log_group_arn
    log_type                 = "SEARCH_SLOW_LOGS"
  }
  log_publishing_options {
    cloudwatch_log_group_arn = local.es_log_group_arn
    log_type                 = "INDEX_SLOW_LOGS"
  }

  node_to_node_encryption {
    enabled = true
  }

  vpc_options {
    security_group_ids = ["sg-12345678"]
    subnet_ids         = ["subnet-12345678", "subnet-12345678"]
  }

  cluster_config {
    dedicated_master_enabled = false
    instance_count           = 4
    instance_type            = "t3.small.search"
    zone_awareness_enabled   = true
  }
}

What this control checks

In the aws_opensearch_domain resource, the cluster_config block must set instance_count to 3 or greater and zone_awareness_enabled to true. With zone_awareness_enabled = true, also configure the nested zone_awareness_config block with availability_zone_count set to 2 or 3 to control how many AZs the nodes span. A domain fails this control if instance_count is less than 3 or zone_awareness_enabled is false (or omitted, since it defaults to false). For three-AZ deployments, set availability_zone_count to 3 and instance_count to a multiple of 3 for even shard distribution.

Common pitfalls

  • Default instance_count is 1

    instance_count defaults to 1 when omitted from cluster_config. Any domain created without an explicit value fails this control immediately, including test clusters that later get promoted to production without a Terraform review.

  • zone_awareness_enabled without zone_awareness_config

    Setting zone_awareness_enabled = true without a zone_awareness_config block defaults to 2 AZs. This passes the control but may not match your resilience target. If you later increase instance_count to 6 expecting 3-AZ distribution, you get 3 nodes per AZ across only 2 AZs instead of 2 per AZ across 3.

  • Uneven instance_count across AZs

    If instance_count is not evenly divisible by availability_zone_count, OpenSearch distributes nodes unevenly. Five nodes across 3 AZs places them 2-2-1, which means losing the AZ with 1 node is less impactful than losing one with 2. The control passes, but shard allocation becomes unbalanced.

  • Dedicated master nodes do not count as data nodes

    Setting dedicated_master_enabled = true and dedicated_master_count = 3 does not satisfy this control. The check evaluates instance_count, which covers data nodes only. You need both dedicated masters and at least 3 data nodes.

Audit evidence

AWS Config rule evaluation results showing each OpenSearch domain as compliant, or a Security Hub findings export filtered to this control, are the most portable form of audit evidence. Console screenshots of the cluster configuration page showing data node count (3+) and the Zone Awareness or Multi-AZ with Standby setting are also acceptable for point-in-time checks. For continuous compliance, a CloudWatch dashboard or Config conformance pack report showing sustained compliance over the audit period is stronger than point-in-time screenshots.

Framework-specific interpretation

Tool mappings

Use these identifiers to cross-reference this control across tools, reports, and evidence.

  • Compliance.tf Control: opensearch_domain_data_node_fault_tolerance

  • AWS Config Managed Rule: OPENSEARCH_DATA_NODE_FAULT_TOLERANCE

  • Powerpipe Controls: aws_compliance.control.es_domain_data_nodes_min_3, aws_compliance.control.opensearch_domain_data_node_fault_tolerance

  • Prowler Check: opensearch_service_domains_fault_tolerant_data_nodes

  • AWS Security Hub Controls: ES.6, Opensearch.6

Last reviewed: 2026-03-09