Skip to content

Basic AWS Qumulo Cluster Example

This example demonstrates the minimal configuration required to deploy a Qumulo cluster on AWS in a single availability zone.

Prerequisites

  • AWS account with permissions to create IAM roles, EC2 instances, S3 buckets, and security groups
  • Existing VPC and subnet
  • Terraform >= 1.0
  • ec2:ModifyInstanceAttribute and s3:GetBucketPolicy on the deploying credentials, for every cluster: the provider lifts deletion protection from an instance or bucket immediately before terminating or deleting it, whether or not deletion_protection was ever set
  • Using deletion_protection additionally requires ec2:DescribeInstanceAttribute, so refresh can report the live protection state (s3:PutBucketPolicy is already required)

VPC Prerequisites

Your VPC must meet two requirements before deploying a cluster:

  • S3 gateway VPC endpoint: Attach an S3 gateway endpoint to the route table serving the subnet. The provider does not create this (cross-account VPCs may lack permission), and deployment will fail without it.
  • Outbound internet access: Cluster nodes and the provisioner instance must reach the public internet for image downloads and cluster registration. Use a NAT Gateway in a private subnet (recommended). An Internet Gateway in a public subnet also works but reduces network isolation.

Deploying into a VPC owned by another AWS account?

For RAM-shared subnets (where the VPC lives in a different AWS account than the one running Terraform), see AWS Cross-Account VPC for the additional setup and the cluster_security_group_id / provisioner_security_group_id Bring-your-own pattern.

Usage

  1. Edit main.tf with your values (look for <-- Replace comments in the Full Configuration below)

  2. Initialize and deploy:

    terraform init -upgrade
    terraform plan
    terraform apply
    

Configuration

This example creates:

  • A 3-node Qumulo cluster in a single AZ
  • m6idn.2xlarge storage-optimized instances
  • HOT storage tier
  • Basic security group created by the provider (all outbound + internode + allow_cidrs ingress)

Node Count

Valid node counts are:

  • 1 (single node for testing)
  • 3-24 (cluster mode)

Note: 2-node clusters are not supported because they cannot form a majority quorum. 4-node clusters are supported only in single-AZ deployments (a single subnet).

Single-AZ vs Multi-AZ

This example uses a single subnet (single-AZ). The subnet_ids count decides the deployment shape:

  • Single-AZ: 1 subnet (this example).
  • Multi-AZ: 3 or more subnets, each in a distinct availability zone.
  • 2 subnets is not supported because it cannot form a majority quorum.
  • Floating IPs (floating_ip_count) and node_count = 4 are single-AZ only.

Floating IPs

floating_ip_count requests ENI secondary private IPv4 addresses. floating_ip_count_ipv6 instead gives the cluster an IPv6 floating pool on the node ENIs:

resource "qumulo_filesystem_aws" "cluster" {
  # ... core attributes ...
  cluster_version        = "7.9.2.1"
  floating_ip_count      = 0                           # IPv4 pool disabled
  floating_ip_count_ipv6 = 6                           # subnet must be dualstack
  allow_cidrs            = ["10.0.0.0/16", "2600:1f14:abc::/56"]
}

floating_ip_count_ipv6 requires cluster_version 7.9.2.1 or later and an IPv6-enabled (dualstack) subnet. Nodes keep their IPv4 primary addresses regardless of the floating pool's address family. Core builds before 7.9.2.1 accept IPv6 floating ranges in network config, but their AWS floating-IP mover only handles IPv4, so v6 floats never fail over between nodes.

The two pools are mutually exclusive: Qumulo Core does not yet support simultaneous IPv4 and IPv6 floating IPs on AWS, so exactly one of the counts may be non-zero. A cluster's pool also cannot be migrated from one family to the other in place (that would drop every client on the current pool) — pick the family at create time. Resizing the pool the cluster already has, including clearing it to 0, is fully supported.

Outputs

After deployment, you'll get:

  • cluster_name: Name of the Qumulo cluster
  • cluster_uuid: UUID of the Qumulo cluster
  • deployment_unique_name: Unique deployment identifier
  • endpoint_ips: Client-facing IPs. Floating IPs if configured, otherwise primary IPs.
  • primary_ips: Per-node primary IPs. Use these directly when no floating IPs are configured, or for per-node access.
  • endpoints: Connection endpoints for various protocols (web UI, API, NFS, SMB)

Supported Instance Types

The provider accepts a curated allow list of EC2 instance types. Set instance_type to any of the values below:

Family Supported sizes
m6idn xlarge, 2xlarge, 4xlarge, 8xlarge, 12xlarge, 16xlarge, 24xlarge, 32xlarge
m6i xlarge, 2xlarge, 4xlarge, 8xlarge, 12xlarge, 16xlarge
m7i xlarge, 2xlarge, 4xlarge, 8xlarge, 12xlarge, 16xlarge, 24xlarge, 48xlarge
i3en xlarge, 2xlarge, 3xlarge, 6xlarge, 12xlarge, 24xlarge
i4i xlarge, 2xlarge, 4xlarge, 8xlarge, 12xlarge, 16xlarge, 24xlarge, 32xlarge
i7i xlarge, 2xlarge, 4xlarge, 8xlarge, 12xlarge, 16xlarge, 24xlarge
i7ie xlarge, 2xlarge, 3xlarge, 6xlarge, 12xlarge, 18xlarge, 24xlarge, 48xlarge

Any type outside this list fails plan validation.

EBS read cache (m6i and m7i): These families have no local NVMe storage, so the provider provisions the read cache as EBS volumes — one 1 TiB gp3 volume per read-cache slot (1 on the smallest sizes, up to 24 on m7i.48xlarge) at 12,500 IOPS and 525 MB/s each, alongside the usual write-cache and DKV volumes. This requires Qumulo Core 7.4.3 or later; older cluster_version values fail at plan time. Budget for the extra EBS cost: roughly $145/month per read-cache volume at these provisioned rates.

Troubleshooting

  1. S3 gateway endpoint missing: Cluster creation fails early if the subnet's route table has no S3 gateway endpoint. Add one in the VPC console under Endpoints > Create endpoint > com.amazonaws..s3 (type: Gateway), and associate it with the subnet's route table.
  2. Outbound unreachable: If the subnet has no internet route (NAT Gateway preferred, or Internet Gateway), the provisioner cannot download the installer. Check the route table and confirm a 0.0.0.0/0 route to an internet-capable target.
  3. Invalid instance type: The provider accepts a specific allow list of instance families (including m6idn, m6i, m7i, i3en, i4i, i7i, i7ie). Families outside the allow list will fail validation. See Supported Instance Types for the full list.
  4. Two-subnet deployment rejected: Use 1 subnet (single-AZ) or 3+ subnets (multi-AZ). 2 is never valid.
  5. GovCloud or ISO regions: Set region = "us-gov-west-1" (or any other GovCloud or ISO region). The provider automatically derives the partition from the region prefix: us-gov-* maps to aws-us-gov, us-isob-* to aws-iso-b, us-iso-* to aws-iso, everything else to aws. No separate partition attribute is needed.
  6. Debug logs: Run TF_LOG=DEBUG terraform apply for detailed output.

Full Configuration

# Example: Basic AWS Qumulo Cluster (single-AZ)
# Edit the values below directly, then run: terraform init -upgrade && terraform apply

terraform {
  required_version = ">= 1.0"
  required_providers {
    qumulo = {
      source  = "qumulo-terraform-registry.s3.us-east-1.amazonaws.com/qumulo/qumulo"
      version = "~> 1.0"
    }
  }
}

provider "qumulo" {
  aws {
    # Standard AWS credential chain applies (env vars, shared config, SSO,
    # instance profile). No credentials block is required here.
    # profile   = "my-profile"   # optional, overrides AWS_PROFILE
  }
}

resource "qumulo_filesystem_aws" "cluster" {
  provider = qumulo

  # =============================================================================
  # All attributes (alphabetical order).
  # Uncomment any attribute to use it. Required attributes are not commented.
  # =============================================================================

  # # Additional security group IDs to attach to cluster nodes.
  # # Use for adding custom ingress rules beyond those the provider creates.
  # additional_security_group_ids = ["sg-abc123"]

  # Administrator password for cluster access (8-128 characters).
  # Sensitive and write-only -- not stored in Terraform state.
  admin_password = "YourSecurePassword123!" # <-- Replace

  # CIDR blocks allowed to access the cluster (required, at least one).
  # Example: ["10.0.0.0/8", "172.16.0.0/12"]
  allow_cidrs = ["0.0.0.0/0"]

  # # AMI ID for cluster nodes. If omitted, the default Qumulo AMI (Ubuntu 24.04) is used.
  # # Supports Ubuntu and RHEL 8, 9, and 10 AMIs.
  # ami_id = "ami-0123456789abcdef0"

  # Cluster storage product type (immutable after creation).
  # HOT: Optimized for frequently accessed data.
  # COLD: Optimized for archival/infrequently accessed data.
  cluster_product_type = "HOT"

  # # S3 storage class backing persistent storage (immutable after creation).
  # # HOT: STANDARD or INTELLIGENT_TIERING (default).
  # # COLD: STANDARD_IA or GLACIER_IR (default).
  # storage_class = "STANDARD"

  # # Qumulo software version. Defaults to latest. Immutable after creation.
  # cluster_version = "7.5.0"

  # # EC2 key pair name for SSH access to cluster nodes.
  # ec2_key_pair = "my-keypair"

  # # Number of floating IPs. Must be 0, or between 3 and 100.
  # # Requires networking_mode = "host_managed" AND single-AZ deployment.
  # floating_ip_count = 3

  # EC2 instance type for cluster nodes.
  # Supported families include m6idn, m6i, i3en, i4i, i7i, i7ie. Families outside the allow list fail validation.
  # See the "Supported Instance Types" section of this page for the full list.
  instance_type = "m6idn.2xlarge"

  # # KMS key ID for encrypting cluster data (immutable after creation).
  # kms_key_id = "arn:aws:kms:us-east-1:123456789012:key/abcd-ef01-..."

  # qfsd cluster name, shown in the Qumulo UI (2-15 chars, case preserved).
  cluster_name = "qumulo"

  # Prefix for the AWS resources this cluster creates (2-15 lowercase chars).
  deployment_name = "qumulo"

  # # Networking mode. Default "host_managed" preserves EC2 IPs across reboots.
  # # Use "qumulo_managed" only when instructed by Qumulo support.
  # networking_mode = "host_managed"

  # # Qumulo Nexus registration key for remote support.
  # # Obtain from https://nexus.qumulo.com/user/registration-key
  # nexus_registration_key = "your-nexus-key"

  # Number of nodes in the cluster.
  # Valid values: 1 (single node), or 3-24 (4 nodes: single-AZ only).
  # Note: 2 is not a valid node count.
  node_count = 3

  # # IAM permissions boundary ARN applied to cluster roles.
  # permissions_boundary_arn = "arn:aws:iam::123456789012:policy/boundary"

  # # AMI ID for the provisioner instance. Defaults to the Qumulo provisioner AMI.
  # provisioner_ami_id = "ami-0123456789abcdef0"

  # # EC2 instance type for the provisioner VM (used during deploy operations).
  # provisioner_instance_type = "t3.medium"

  # AWS region for deployment.
  region = "us-east-1" # <-- Replace with your region

  # # Soft capacity limit in TB (50 to 50000).
  # # Can be increased to add storage, but cannot be decreased.
  # soft_capacity_limit_tb = 1000

  # Subnet IDs for cluster nodes.
  # Use 1 subnet for single-AZ (this example) or 3+ subnets (one per AZ) for multi-AZ.
  # 2 subnets is not valid (cannot form a majority quorum).
  subnet_ids = ["subnet-0123456789abcdef0"] # <-- Replace with your subnet ID

  # # Tags to apply to all AWS resources created for this cluster.
  # tags = {
  #   Environment = "Development"
  #   ManagedBy   = "Terraform"
  # }

  # # VPC ID. Derived from subnet_ids if omitted.
  # vpc_id = "vpc-0123456789abcdef0"

  deletion_protection = true # recommended: guard the cluster's EC2 instances and S3 buckets

  timeouts {
    create = "90m"
    delete = "30m"
  }
}

output "cluster_name" {
  description = "Name of the Qumulo cluster"
  value       = qumulo_filesystem_aws.cluster.cluster_name
}

output "cluster_uuid" {
  description = "UUID of the Qumulo cluster"
  value       = qumulo_filesystem_aws.cluster.cluster_uuid
}

output "deployment_unique_name" {
  description = "Unique deployment identifier"
  value       = qumulo_filesystem_aws.cluster.deployment_unique_name
}

output "endpoint_ips" {
  description = "Client-facing IPs. Floating IPs if configured, otherwise primary IPs."
  value       = qumulo_filesystem_aws.cluster.endpoint_ips
}

output "primary_ips" {
  description = "Per-node primary IPs. Use these directly when no floating IPs are configured, or for per-node access."
  value       = qumulo_filesystem_aws.cluster.primary_ips
}

output "endpoints" {
  description = "Connection endpoints for various protocols"
  value = {
    web_ui = "https://${try(qumulo_filesystem_aws.cluster.endpoint_ips[0], "pending")}"
    api    = "https://${try(qumulo_filesystem_aws.cluster.endpoint_ips[0], "pending")}:8000"
    nfs    = "${try(qumulo_filesystem_aws.cluster.endpoint_ips[0], "pending")}:/"
    smb    = "\\\\${try(qumulo_filesystem_aws.cluster.endpoint_ips[0], "pending")}\\share"
  }
}