Skip to content

Azure Government Cloud Example

This example demonstrates deploying a Qumulo cluster on Azure Government Cloud with FedRAMP-compliant settings.

Azure Government Cloud requires environment = "usgovernment" in the azure {} provider block:

provider "qumulo" {
  azure {
    subscription_id = "your-subscription-id"
    environment     = "usgovernment" # Required for Azure Government Cloud
  }
}

Prerequisites

  • Azure Government subscription with Contributor permissions
  • Enabling deletion_protection additionally requires Microsoft.Authorization/locks/*, carried by Owner, User Access Administrator, or a custom role (Contributor alone cannot manage management locks)
  • Existing virtual network and subnet in a government region
  • SSH public key for node access
  • Terraform >= 1.0

Subnet Service Endpoints Required

Your Virtual Network subnet must have the Microsoft.KeyVault and Microsoft.Storage service endpoints enabled before deploying a cluster. To verify, go to the Azure Portal, navigate to Virtual networks > your VNet > Settings > Service endpoints, and confirm both endpoints are added for the target subnet. Deployment will fail without these service endpoints.

Usage

  1. Edit main.tf with your values (look for <-- Replace comments)

  2. Configure Azure CLI for government cloud:

    az cloud set --name AzureUSGovernment
    az login
    

  3. Initialize and deploy:

    terraform init -upgrade
    terraform plan
    terraform apply
    

Government-Specific Settings

This example includes:

  • environment = "usgovernment" in the azure {} provider block
  • Government regions only (usgovvirginia, usgovtexas, usgoviowa, usgovarizona)
  • Multi-zone deployment for compliance
  • Mandatory CIDR restrictions (do not leave allow_cidrs empty)
  • Compliance-appropriate tagging (Agency, Classification, BackupRetention)

Available Regions

  • usgovvirginia - US Gov Virginia
  • usgovtexas - US Gov Texas
  • usgoviowa - US Gov Iowa
  • usgovarizona - US Gov Arizona

Outputs

After deployment, you'll get:

  • cluster_name: The name of your cluster
  • cluster_uuid: UUID of the Qumulo cluster
  • endpoint_ips: IP addresses for client connections (floating IPs if configured, otherwise primary IPs)
  • primary_ips: Per-node primary IPs, for per-node access
  • endpoints: Pre-formatted connection strings for web UI, API, NFS, and SMB
  • deployment_unique_name: Unique deployment identifier

Full Configuration

# Example: Azure Government Cloud Qumulo Cluster
# This example shows deployment to Azure Government Cloud with FedRAMP compliance settings.
# The resource group is automatically created if it doesn't exist.
# 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"
    }
  }
}

# Qumulo Provider configured for Azure Government Cloud
provider "qumulo" {
  azure {
    subscription_id = "your-subscription-id" # <-- Replace with your Azure Government subscription ID
    environment     = "usgovernment"         # Required for Azure Government Cloud
  }
}

variable "ssh_public_key_path" {
  description = "Path to SSH public key file for cluster node access"
  type        = string
  default     = "~/.ssh/id_rsa.pub"
}

# Qumulo cluster on Azure Government Cloud
# Note: The resource group is automatically created if it doesn't exist.
# If it exists, the provider will use it (location must match).
resource "qumulo_filesystem_azure" "cluster" {
  provider = qumulo

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

  # Admin password for cluster access.
  # 8-128 characters, must include 3+ of: uppercase, lowercase, digit, special character.
  # Immutable after creation - use Qumulo UI or CLI to change.
  # Note: Minimum 12 characters recommended for government compliance.
  admin_password = "YourSecureGovPassword123!"

  # CIDR blocks allowed to access the cluster.
  # Empty list means no IP-based restrictions (use with caution).
  # IMPORTANT: Required for government compliance - do not leave empty.
  allow_cidrs = ["10.0.0.0/8"]

  # Availability zones for node distribution.
  # Controls both node placement and VM disk storage type:
  # - With zones: Uses PremiumV2_LRS disks (better price/performance).
  # - Without zones: Uses Premium_LRS disks (required for zoneless regions).
  # Omit for single-zone or zoneless regions (e.g., northcentralus).
  # Example: ["1", "2", "3"] for multi-AZ high availability.
  availability_zones = ["1", "2", "3"]

  # # User-assigned managed identity for cluster nodes.
  # # When provided, RBAC roles must be pre-configured (not auto-created).
  # # Format: /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{name}
  # cluster_node_identity_id = "/subscriptions/xxx/resourceGroups/xxx/providers/Microsoft.ManagedIdentity/userAssignedIdentities/xxx"

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

  # Qumulo software version (pin to a tested version for GovCloud compliance).
  # Immutable after creation - use Qumulo UI or CLI to upgrade.
  cluster_version = "7.5.0" # Replace with your tested/approved version

  # # Custom managed image ID for cluster nodes.
  # # Use for hardened or pre-configured VMs.
  # # WARNING: Changes trigger cluster replacement!
  # # Format: /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Compute/images/{name}
  # # Create private endpoints in the cluster subnet.
  # # Set the matching private_link_appconfig_dns_zone_id,
  # # private_link_keyvault_dns_zone_id, or private_link_storage_dns_zone_id to also
  # # register them in an Azure Private DNS zone. Without a zone, read the computed
  # # appconfig_private_endpoint / keyvault_private_endpoint /
  # # storage_private_endpoints outputs and create the records yourself.
  # # create_keyvault_private_endpoint conflicts with key_vault_id.
  # # Each endpoint carries a per-hour Azure cost.
  # create_appconfig_private_endpoint = false
  # create_keyvault_private_endpoint  = false
  # create_storage_private_endpoint   = false

  # custom_image_id = "/subscriptions/xxx/resourceGroups/xxx/providers/Microsoft.Compute/images/xxx"

  # # Disable App Configuration public network access.
  # # When true, requires private_link_appconfig_dns_zone_id.
  # disable_appconfig_public_network_access = false

  # # Disable Key Vault public network access.
  # # When true, requires private_link_keyvault_dns_zone_id.
  # disable_keyvault_public_network_access = false

  # # Floating IP addresses for client access.
  # # Use for DNS round-robin or custom load balancing.
  # # When set, endpoint_ips output returns these instead of node IPs.
  # # Number of floating IPs for client access. The provider picks the
  # # addresses from the cluster subnet and reports them in floating_ips.
  # floating_ip_count = 3

  # # Customer-managed Key Vault resource ID.
  # # When provided, the provider uses this vault instead of creating one.
  # # Conflicts with disable_keyvault_public_network_access and private_link_keyvault_dns_zone_id.
  # # Immutable after creation. You own vault lifecycle, network, and access policies.
  # # The vault must permit access from the cluster subnet - the nodes read their
  # # storage SAS tokens from it. See "Customer-Managed Key Vault" in azure-production.md.
  # # Format: /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.KeyVault/vaults/{name}
  # key_vault_id = "/subscriptions/xxx/resourceGroups/xxx/providers/Microsoft.KeyVault/vaults/xxx"

  # Azure region for deployment.
  # Azure Government regions: usgovvirginia, usgovtexas, usgoviowa, usgovarizona
  location = "usgovvirginia" # <-- Azure Government region

  # # Azure Marketplace image for cluster nodes.
  # # Alternative to custom_image_id for standard enterprise images.
  # # WARNING: Changes trigger cluster replacement!
  # marketplace_image = [{
  #   publisher = "Canonical"
  #   offer     = "0001-com-ubuntu-server-jammy"
  #   sku       = "22_04-lts-gen2"
  #   version   = "latest"
  # }]

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

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

  # # Custom naming templates for Azure resources.
  # # vm_name must contain exactly one {node_id} placeholder.
  # # storage_account must contain exactly one {index} or {index:N} placeholder.
  # # {index} is the unpadded index. {index:N} zero-pads the index to width N, so
  # # {index:2} yields "01", "02", ... ({index:02} is equivalent -- the leading 0 is redundant).
  # # Changing either forces replacement of the affected resource.
  # naming = [{
  #   vm_name         = "myapp-{node_id}"
  #   storage_account = "myappstor{index:02}"
  # }]

  # # Network management mode.
  # # "host_managed" (default) for clusters created by this provider.
  # # "qumulo_managed" only for clusters originally created by azure-terraform-cnq.
  # # Immutable after creation. Mixing modes across nodes is prohibited.
  # networking_mode = "host_managed"

  # # Qumulo Nexus registration key for remote support.
  # # Obtain from https://nexus.qumulo.com/user/registration-key
  # # Only applied during initial cluster creation.
  # nexus_registration_key = "your-nexus-key"

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

  # # Enable ICMP ingress (ping) in network security group.
  # # Useful for network diagnostics.
  # nsg_allow_ingress_icmp = false

  # # Resource group containing persistent storage accounts and KeyVault.
  # # Required when migrating from the legacy azure-terraform-cnq module, where persistent
  # # storage lived in a separate resource group. Defaults to resource_group_name when omitted.
  # persistent_storage_resource_group = "rg-qumulo-persistent"

  # # Private DNS zone ID for App Configuration private endpoint.
  # # Required when disable_appconfig_public_network_access is true.
  # # Requires create_appconfig_private_endpoint = true.
  # # Format: /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/privateDnsZones/privatelink.azconfig.azure.us
  # private_link_appconfig_dns_zone_id = "/subscriptions/xxx/resourceGroups/xxx/providers/Microsoft.Network/privateDnsZones/privatelink.azconfig.azure.us"

  # # Private DNS zone ID for Key Vault private endpoint.
  # # Required when disable_keyvault_public_network_access is true.
  # # Requires create_keyvault_private_endpoint = true.
  # # Format: /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/privateDnsZones/privatelink.vaultcore.usgovcloudapi.net
  # private_link_keyvault_dns_zone_id = "/subscriptions/xxx/resourceGroups/xxx/providers/Microsoft.Network/privateDnsZones/privatelink.vaultcore.usgovcloudapi.net"

  # # Private DNS zone ID for the storage private endpoints.
  # # Requires create_storage_private_endpoint = true.
  # # Format: /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/privateDnsZones/privatelink.blob.core.usgovcloudapi.net
  # private_link_storage_dns_zone_id = "/subscriptions/xxx/resourceGroups/xxx/providers/Microsoft.Network/privateDnsZones/privatelink.blob.core.usgovcloudapi.net"

  # # Custom managed image ID for provisioner VM.
  # # Does NOT trigger cluster replacement when changed.
  # provisioner_custom_image_id = "/subscriptions/xxx/resourceGroups/xxx/providers/Microsoft.Compute/images/xxx"

  # # User-assigned managed identity for provisioner VM.
  # # When provided, RBAC roles must be pre-configured.
  # provisioner_identity_id = "/subscriptions/xxx/resourceGroups/xxx/providers/Microsoft.ManagedIdentity/userAssignedIdentities/xxx"

  # # Azure Marketplace image for provisioner VM.
  # # Does NOT trigger cluster replacement when changed.
  # provisioner_marketplace_image = [{
  #   publisher = "Canonical"
  #   offer     = "0001-com-ubuntu-server-jammy"
  #   sku       = "22_04-lts-gen2"
  #   version   = "latest"
  # }]

  # # VM size for the provisioner instance.
  # # Used during deployment operations only.
  # provisioner_vm_type = "Standard_B2s"

  # Azure resource group name.
  # The resource group is automatically created if it doesn't exist.
  # If it exists, the provider will use it (location must match).
  resource_group_name = "rg-qumulo-gov" # <-- Name your resource group

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

  # SSH public key for cluster node access.
  # Point to your public key file (e.g., ~/.ssh/id_rsa.pub).
  ssh_public_key = file(var.ssh_public_key_path)

  # Azure storage replication type for storage accounts only (does not affect VM disks).
  # LRS: Locally redundant (3 copies in single datacenter).
  # ZRS: Zone redundant (3 copies across availability zones) - RECOMMENDED for multi-AZ clusters.
  # Note: VM disk redundancy is controlled by availability_zones (see above).
  # Immutable after creation.
  storage_replication_type = "ZRS"

  # Full Azure resource ID of the subnet for cluster deployment.
  # The subnet must already exist before deploying the cluster.
  # Format: /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}
  subnet_id = "/subscriptions/your-subscription-id/resourceGroups/rg-network/providers/Microsoft.Network/virtualNetworks/vnet-main/subnets/subnet-qumulo"

  # Tags to apply to all Azure resources (including the resource group if created).
  # Government-compliant tags for compliance tracking.
  tags = {
    Environment         = "Production"
    Agency              = "Your-Agency-Name"
    Classification      = "CUI"
    ComplianceFramework = "FedRAMP"
    ManagedBy           = "Terraform"
    BackupRetention     = "7Years"
  }

  # Azure VM size for cluster nodes.
  # Only L-series storage-optimized VMs are supported.
  # Examples: Standard_L8s_v3, Standard_L16s_v3, Standard_L32s_v3
  vm_type = "Standard_L8s_v3"

  deletion_protection = true # recommended: guard the cluster's VMs and storage accounts

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

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

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

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

output "endpoint_ips" {
  description = "Client-facing IPs. Floating IPs if configured, otherwise primary IPs."
  value       = qumulo_filesystem_azure.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_azure.cluster.primary_ips
}

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