{"id":48885662,"url":"https://github.com/azure/relational-infrastructure","last_synced_at":"2026-04-16T05:01:21.462Z","repository":{"id":347702531,"uuid":"914062965","full_name":"Azure/relational-infrastructure","owner":"Azure","description":"AzRI models Azure Terraform IaC like relational databases, cutting code sprawl with concise maps. Built on Azure Verified Modules, it reduces LoC by 55%, enabling 2-3x faster deployments.","archived":false,"fork":false,"pushed_at":"2026-04-14T14:33:23.000Z","size":5866,"stargazers_count":3,"open_issues_count":25,"forks_count":0,"subscribers_count":6,"default_branch":"main","last_synced_at":"2026-04-14T15:28:39.191Z","etag":null,"topics":["azapi","azure","azurerm","iac","infrastructure","infrastructure-as-code","relational-model","terraform"],"latest_commit_sha":null,"homepage":"","language":"HCL","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Azure.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":"SUPPORT.md","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-01-08T21:55:59.000Z","updated_at":"2026-04-14T14:33:44.000Z","dependencies_parsed_at":null,"dependency_job_id":"5d7da72c-a881-4897-bfac-83359806ecb5","html_url":"https://github.com/Azure/relational-infrastructure","commit_stats":null,"previous_names":["azure/relational-infrastructure"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Azure/relational-infrastructure","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Azure%2Frelational-infrastructure","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Azure%2Frelational-infrastructure/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Azure%2Frelational-infrastructure/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Azure%2Frelational-infrastructure/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Azure","download_url":"https://codeload.github.com/Azure/relational-infrastructure/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Azure%2Frelational-infrastructure/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31872036,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-15T15:24:51.572Z","status":"online","status_checked_at":"2026-04-16T02:00:06.042Z","response_time":69,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["azapi","azure","azurerm","iac","infrastructure","infrastructure-as-code","relational-model","terraform"],"created_at":"2026-04-16T05:00:59.737Z","updated_at":"2026-04-16T05:01:21.441Z","avatar_url":"https://github.com/Azure.png","language":"HCL","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003e [!WARNING]\n\u003e Azure Relational Infrastructure is currently in public preview. Use with caution.\n\n# Azure Relational Infrastructure (AzRI)\n\nAzure Relational Infrastructure (AzRI) simplifies Azure deployments by modeling infrastructure as code (IaC) like a relational database. In the 1970s, relational databases tamed chaotic data with structured tables, primary keys, and foreign keys, making data compact, queryable, and easy to update. Similarly, AzRI organizes Terraform resources into concise maps with clear relationships, slashing code sprawl and complexity. This relational approach mirrors database normalization, eliminating redundancy and simplifying modifications. Built on [Azure Verified Modules (AVM)](https://aka.ms/avm) and aligned with [Azure’s Well-Architected Framework](https://learn.microsoft.com/en-us/azure/well-architected/), AzRI ensures resilient, scalable Terraform deployments. Features like [lock groups](#lock-groups) enhance management, drawing on Microsoft and partner expertise. AzRI makes Azure IaC cleaner and more efficient, just as relational databases transformed data management.\n\n## Model Reference\n\n```mermaid\n---\ntitle: Infrastructure Map Model\n---\nerDiagram\n  Locations ||--o{ \"Resource Groups\" : \"\"\n  Locations ||--o{ \"Networks\" : \"\"\n  Locations ||--o{ \"Role-Based VM Sets\" : \"\"\n  Locations ||--o{ \"Key Vaults\" : \"\"\n  Locations ||--o{ \"Storage Accounts\" : \"\"\n  Subscriptions ||--o{ \"Key Vaults\" : \"\"\n  Subscriptions ||--o{ \"Resource Groups\" : \"\"\n  Subscriptions ||--o{ \"Networks\" : \"\"\n  Subscriptions ||--o{ \"Role-Based VM Sets\" : \"\"\n  Subscriptions ||--o{ \"Storage Accounts\" : \"\"\n  Subscriptions ||--o{ \"Private DNS Zones\" : \"\"\n  \"Shutdown Schedules\" ||--o{ \"Role-Based VM Sets\" : \"\"\n  \"Resource Groups\" ||--o{ \"Role-Based VM Sets\" : \"\"\n  \"Resource Groups\" ||--o{ \"Key Vaults\" : \"\"\n  \"Resource Groups\" ||--o{ \"Storage Accounts\" : \"\"\n  \"Resource Groups\" ||--o{ \"Private DNS Zones\" : \"\"\n  \"Private Endpoints\" }o--o{ \"Private DNS Zones\" : \"\"\n  \"Networks\" }o--o{ \"Private DNS Zones\" : \"\"\n  \"Subscriptions\" ||..|| \"Resource Groups\" : \"has a default\"\n  \"Subscriptions\" ||..|| \"Resource Groups\" : \"has a dedicated private link\"\n  \"Subscriptions\" ||--o{ \"Networks\" : \"\"\n  \"Subscriptions\" ||--o{ \"Role-Based VM Sets\" : \"\"\n  \"Subscriptions\" ||--o{ \"Key Vaults\" : \"\"\n  \"VM Extensions\" }o--o{ \"Role-Based VM Sets\" : \"\"\n  \"VM Scale Sets\" |o--o{ \"Role-Based VM Sets\" : \"\"\n  \"Networks\" ||..o{ \"Subnets\" : \"\"\n  \"Network Security Groups\" ||--o{ \"Network Security Rules\" : \"have\"\n  \"Networks\" }o--o{ \"Network Security Groups\" : \"via security_group_name\"\n  \"External Networks\" ||..o{ \"External Subnets\" : \"\"\n  \"Subnets\" ||..o{ \"Routes\" : \"\"\n  \"Routes\" ||--|| \"Networks\" : \"to\"\n  \"Routes\" ||--|| \"External Networks\" : \"to\"\n  \"Routes\" ||--|| \"Subnets\" : \"to\"\n  \"Routes\" ||--|| \"External Subnets\" : \"to\"\n  \"Ports\" }o--o{ \"Network Security Rules\" : \"to/from\"\n  \"Network Security Rules\" ||--o{ \"Networks\" : \"to/from\"\n  \"Network Security Rules\" ||--o{ \"Subnets\" : \"to/from\"\n  \"Network Security Rules\" ||--o{ \"External Networks\" : \"to/from\"\n  \"Network Security Rules\" ||--o{ \"External Subnets\" : \"to/from\"\n  \"Network Security Rules\" ||--o{ \"Role-Based VM Sets\" : \"to/from\"\n  \"Key Vaults\" ||..o{ \"Role-Based VM Sets\" : \"protect\"\n  \"Role-Based VM Sets\" ||..|{ \"Network Interfaces\" : \"have\"\n  \"Role-Based VM Sets\" ||--o| \"Load Balancers\" : \"have\"\n  \"Load Balancers\" }o--o{ \"Subnets\" : \"internal frontend on\"\n  \"Ports\" }o--o{ \"Load Balancers\" : \"probe/rules via\"\n  \"Role-Based VM Sets\" ||..|{ \"Data Disk Groups\" : \"have\"\n  \"Subnets\" ||--o{ \"Network Interfaces\" : \"contain\"\n  \"Role-Based VM Sets\" ||--o| \"Availability Zone Distribution Strategy\" : \"uses\"\n  \"Role-Based VM Sets\" ||--|| \"VM Set Specs\" : \"have\"\n  \"VM Set Specs\" ||..o{ \"Data Disk Group Specs\" : \"have\"\n  \"Data Disk Groups\" ||..|| \"Data Disk Group Specs\" : \"have\"\n  \"Resource Groups\" ||--o{ \"Networks\" : \"have\"\n  \"Key Vaults\" ||--o{ \"Private Endpoints\" : \"have\"\n  \"Subnets\" ||--o{ \"Private Endpoints\" : \"have\"\n  \"Networks\" ||..o{ \"Peerings\" : \"have\"\n  \"Peerings\" ||--|| \"Networks\" : \"peered to\"\n  \"Peerings\" ||--|| \"External Networks\" : \"peered to\"\n  \"Lock Groups\" ||--o{ \"Resource Groups\" : \"lock\"\n  \"Lock Groups\" ||--o{ \"Networks\" : \"lock\"\n  \"Lock Groups\" ||--o{ \"Key Vaults\" : \"lock\"\n  \"Lock Groups\" ||--o{ \"Role-Based VM Sets\" : \"lock\"\n  \"Lock Groups\" ||--o{ \"Data Disk Groups\" : \"lock\"\n  \"Lock Groups\" ||--o{ \"Network Interfaces\" : \"lock\"\n  \"Lock Groups\" ||--o{ \"Private Endpoints\" : \"lock\"\n  \"Lock Groups\" ||--o{ \"Storage Accounts\" : \"lock\"\n  \"Storage Accounts\" ||--o{ \"Blob Containers\" : \"have\"\n  \"Storage Accounts\" ||--o{ \"File Shares\" : \"have\"\n  \"Blob Containers\" ||--o{ \"Private Endpoints\" : \"have\"\n  \"File Shares\" ||--o{ \"Private Endpoints\" : \"have\"\n```\n\n\u003e [!NOTE]\n\u003e In the sections below:\n\u003e * 🔑 indicates a \"primary key\"; typically the \"one\" side of a one-to-many relationship\n\u003e * 🔗 indicates a \"foreign key\"; typically the \"many\" side of a one-to-many relationship\n\n### Locations\n\n\u003e Terraform variable: `var.locations`\n\nThe `locations` table defines the Azure regions where your infrastructure lives, like `eastus` or `westus`. It’s the starting point for placing resources geographically, ensuring they align with [Azure’s global regions](https://learn.microsoft.com/azure/reliability/regions-list) for availability and compliance. In the entity-relationship diagram (ERD), `locations` acts as a reference point, linking one-to-many with tables like networks or virtual machine sets to specify where they’re deployed.\n\n```hcl\nlocations = {\n  primary = \"eastus\"  # 🔑 \"primary\" location; must be a valid Azure region (see below)\n  alt     = \"westus\"  # 🔑 \"alt\" location; must be a valid Azure region (see below)\n}\n```\n\n\u003e [!TIP]\n\u003e **Powershell Users:** For a complete list of valid Azure locations, [install the Az Powershell module](https://learn.microsoft.com/powershell/azure/install-azure-powershell), then run the following command:\n\u003e ```powershell\n\u003e Get-AzLocation | Select-Object -Property Name | ForEach-Object { $_.Name }\n\u003e ```\n\n\u003e [!TIP]\n\u003e **Azure CLI/Bash Users:** For a complete list of valid Azure locations, [install the Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli), then run the following command:\n\u003e ```bash\n\u003e az account list-locations --query \"[].name\" -o tsv\n\u003e ```\n\n### Subscriptions\n\n\u003e Terraform variable: `var.subscriptions`\n\n\u003e [!IMPORTANT]\n\u003e Up to ten (10) subscriptions are supported.\n\nThe `subscriptions` table organizes your [Azure subscriptions](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-setup-guide/organize-resources#management-levels-and-hierarchy), acting as a control center for grouping resources across your environment. Each subscription connects to [resource groups](#resource-groups) and Terraform providers, setting the scope for your infrastructure. In the entity-relationship diagram (ERD), `subscriptions` serves as a central hub, with one-to-many links to tables like [`resource_groups`](#resource-groups) and [`networks`](#networks), ensuring resources stay aligned.\n\n```hcl\nsubscriptions = { \n  production = {                                                  # 🔑 \"production\" subscription\n    default_resource_group_name      = \"production\"               # 🔗 Links to var.resource_groups\n    private_link_resource_group_name = \"production_networks\"      # 🔗 Optional; links to var.resource_groups\n    subscription_id                  = \"00000000-0000...\"         # Azure subscription ID (must be a GUID)\n  }\n  non_production = {                                              # 🔑 \"non_production\" subscription\n    default_resource_group_name      = \"non_production\"           # 🔗 Links to var.resource_groups    \n    private_link_resource_group_name = \"non_production_networks\"  # 🔗 Optional; Links to var.resource_groups\n    subscription_id                  = \"10000000-0000...\"         # Azure subscription ID (must be a GUID)\n  }\n}\n```\n\n| Field | Description |\n|-------|-------------|\n| `default_resource_group_name` | Links to a key in [`var.resource_groups`](#resource-groups). Defines the primary resource group for the subscription. |\n| `private_link_resource_group_name` | Optional; if set, links to a key in [`var.resource_groups`](#resource-groups) for private link resources. Defaults to `default_resource_group_name` if unset. |\n| `subscription_id` | References a specific Azure subscription ID. Must be a GUID. |\n\n### Lock Groups\n\n\u003e Terraform variable: `var.lock_groups`\n\nThe `lock_groups` table groups Azure resources—like [VMs](#virtual-machine-sets), [networks](#networks), or [disks](#virtual-machine-data-disks)—into logical sets for coordinated [lock management](https://learn.microsoft.com/azure/azure-resource-manager/management/lock-resources) during maintenance, such as updating a region’s infrastructure or a compute tier. Resources in tables like [`var.virtual_machine_sets`](#virtual-machine-sets) or [`var.networks`](#networks) can list lock group keys in their `lock_groups` property to join one or more groups. Each group toggles locks (CanNotDelete or ReadOnly) for its members. \n\nThis is how lock groups work:\n\n* If the resource has no `lock_groups`, the resource is unlocked.\n* If any of the resource's `lock_groups` are unlocked, the resource is unlocked.\n* If all of a resource group's `lock_groups` are locked and any of the `lock_groups` are configured for `read_only`, a read-only lock is applied to the resource.\n* If all of a resource group's `lock_groups` are locked and none of the `lock_groups` are configured for `read_only`, a do-not-delete lock is applied to the resource.\n\nIn the ERD, `lock_groups` has a many-to-many relationship with resources, linked via `lock_groups` properties in other tables.\n\n```hcl\nlock_groups = {\n  production_lock = {      # 🔑 Primary key: \"production_lock\"\n    locked    = true       # Locks enabled\n    read_only = true       # ReadOnly lock\n  }\n  non_production_lock = {  # 🔑 Primary key: \"maintenance_lock\"\n    locked    = false      # Locks disabled\n    read_only = false      # CanNotDelete lock\n  }\n}\n```\n\n\u003e [!IMPORTANT]  \n\u003e When a resource belongs to multiple locked groups (via its `lock_groups` property), the most restrictive lock wins: a ReadOnly lock (`read_only = true`) takes precedence over a CanNotDelete lock (`read_only = false`).\n\n| Field | Description |\n|-------|-------------|\n| `locked` | Required; if `true`, applies locks to group resources; if `false`, removes them for maintenance. |\n| `read_only` | Optional; if `true`, applies ReadOnly locks (no changes); if `false`, applies CanNotDelete locks (allows updates). Defaults to `false`. ReadOnly wins if multiple locked groups apply. |\n\n### Resource Groups\n\n\u003e Terraform variable: `var.resource_groups`\n\nThe `resource_groups` table defines the [Azure resource groups](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-setup-guide/organize-resources#management-levels-and-hierarchy) that bundle related resources together in your environment. Each resource group ties to a subscription and, optionally, a location, organizing assets like networks or VMs. In the entity-relationship diagram (ERD), `resource_groups` links one-to-one with `subscriptions` and optionally to `locations`, acting as a container for other resources.\n\n```hcl\nresource_groups = {\n  production = {                         # 🔑 \"production\" resource group\n    subscription_name = \"production\"     # 🔗 Links to var.subscriptions\n    location_name     = \"primary\"        # 🔗 Optional; links to var.locations\n    name              = \"production\"     # Resource group name in Azure\n\n    lock_groups = [\n      \"production_lock\"                  # 🔗 Optional; links to var.lock_groups\n    ]\n  }\n  non_production = {                     # 🔑 \"non_production\" resource group\n    subscription_name = \"non_production\" # 🔗 Links to var.subscriptions\n    location_name     = \"alt\"            # 🔗 Optional; links to var.locations\n    name              = \"non-production\" # Resource group name in Azure\n\n    lock_groups = [\n      \"non_production_lock\"              # 🔗 Optional; links to var.lock_groups\n    ]\n  }\n}\n```\n\n| Field | Description |\n|-------|-------------|\n| `subscription_name` | Links to a key in [`var.subscriptions`](#subscriptions). Defines the subscription this resource group belongs to. |\n| `location_name` | Optional; if set, links to a key in [`var.locations`](#locations). Specifies the Azure region for the resource group. Defaults to the first location in `var.locations` if unset. |\n| `lock_groups` | Optional; if set, links to keys in [`var.lock_groups`](#lock-groups). Specifies the resource lock groups that this resource group belongs to. |\n| `name` | The name of the resource group as it appears in Azure, used to identify it. |\n\n### Maintenance Schedules\n\n\u003e Terraform variable: `var.maintenance_schedules`\n\n[The `maintenance_schedules` table defines when Azure applies platform updates](https://learn.microsoft.com/azure/virtual-machines/maintenance-configurations), like patches or upgrades, to your [virtual machines](#virtual-machine-sets). Each schedule specifies a start time, update period, and how often updates repeat (daily, weekly, or monthly). In the ERD, `maintenance_schedules` links one-to-one with [`subscriptions`](#subscriptions) and one-to-many with [`virtual_machine_sets`](#virtual-machine-sets), aligning update plans with your infrastructure.\n\n```hcl\nmaintenance_schedules = {\n  guest_updates = {                                # 🔑 Primary key: \"guest_updates\"\n    repeat_every = {                               # Updates every...\n      week = true                                  # week\n    }\n    start_date_time_utc = \"2025-01-05 22:00\"       # Window starts at 22:00\n    duration            = \"2:00\"                   # Updates take 2 hours\n  }\n  host_updates = {                                 # 🔑 Primary key: \"host_updates\"\n    repeat_every = {                               # Updates every...\n      days = 7                                     # 7 days\n    }\n    start_date_time_utc      = \"2025-01-06 23:00\"  # Window starts at 23:00\n    expiration_date_time_utc = \"2026-01-06 23:00\"  # Expires after 1 year\n    duration                 = \"1:30\"              # Updates take 90 minutes\n  }\n}\n```\n\n\u003e [!IMPORTANT]  \n\u003e [VMs](#virtual-machine-sets) must be running 15 minutes before the update start time. Schedule updates during low-traffic periods to avoid impact.\n\n| Field | Description |\n|-------|-------------|\n| `repeat_every` | Required; sets the update frequency: `day` (daily), `week` (weekly), `month` (monthly), `days` (every n days), `weeks` (every n weeks), or `months` (every n months). Only one option can be set. |\n| `start_date_time_utc` | Required; specifies the first update time in UTC, e.g., `2025-01-05 22:00`. |\n| `expiration_date_time_utc` | Optional; sets when the schedule ends, e.g., `2026-01-06 23:00`. Defaults to `null` (no expiration). |\n| `duration` | Optional; defines the update period in HH:MM format, e.g., `2:00` or `1:30`. Defaults to `1:30` (90 minutes). Minimum varies by scope (e.g., 1.5h for guest updates). |\n\n### Shutdown Schedules\n\n\u003e Terraform variable: `var.virtual_machine_shutdown_schedules`\n\nThe `virtual_machine_shutdown_schedules` table defines daily [shutdown schedules for Azure virtual machines](https://learn.microsoft.com/azure/virtual-machines/auto-shutdown-vm), helping to reduce costs by automatically powering off VMs during off-hours. Each schedule specifies a shutdown time, timezone, and optional notifications (e.g., email or webhook alerts before shutdown). Schedules link to [`virtual_machine_sets`](#virtual-machine-sets) via the `shutdown_schedule_name` field, allowing multiple VM sets to share the same schedule. In the ERD, `virtual_machine_shutdown_schedules` has a one-to-many relationship with [`virtual_machine_sets`](#virtual_machine-sets), enabling efficient management of shutdown policies across your infrastructure.\n\n```hcl\nvirtual_machine_shutdown_schedules = {\n  evening_shutdown = {                               # 🔑 \"evening_shutdown\" schedule\n    daily_recurrence_time = \"1800\"                   # Shutdown at 6:00 PM (24-hour format, no colon)\n    timezone              = \"Pacific Standard Time\"  # Timezone for the schedule\n    enabled               = true                     # Schedule is active\n\n    notification_settings = {\n      enabled         = true                        # Enable notifications\n      email           = \"admin@example.com\"         # Email for alerts\n      time_in_minutes = \"30\"                        # Notify 30 minutes before shutdown\n      webhook_url     = \"https://webhook.example.com\"  # Optional webhook for notifications\n    }\n\n    tags = {\n      purpose = \"cost_savings\"                      # Optional tags\n    }\n  }\n  weekend_shutdown = {                               # 🔑 \"weekend_shutdown\" schedule\n    daily_recurrence_time = \"2200\"                   # Shutdown at 10:00 PM\n    timezone              = \"Eastern Standard Time\"  # Timezone for the schedule\n    enabled               = false                    # Schedule is disabled\n  }\n}\n```\n\n| Field | Description |\n|-------|-------------|\n| `daily_recurrence_time` | Required; specifies the daily shutdown time in 24-hour format without a colon, e.g., `1800` for 6:00 PM. |\n| `timezone` | Required; sets the timezone for the schedule, e.g., `Pacific Standard Time`. Must be a valid Azure timezone string. |\n| `enabled` | Optional; if `true`, activates the schedule. Defaults to `true`. |\n| `notification_settings` | Optional; configures pre-shutdown notifications with `enabled` (defaults to `false`), `email` (optional), `time_in_minutes` (defaults to `\"30\"`), and `webhook_url` (optional). Defaults to `{ enabled = false }`. |\n| `tags` | Optional; applies key-value tags to the schedule, e.g., `{ purpose = \"cost_savings\" }`. Defaults to `null`. |\n\n\u003e [!NOTE]  \n\u003e Shutdown schedules are applied at the VM level and trigger daily based on the specified time and timezone. Notifications, if enabled, send alerts via email or webhook a set number of minutes before shutdown to allow for any necessary actions.\n\n### Virtual Machine Extensions\n\n\u003e Terraform variable: `var.virtual_machine_extensions`\n\nThe `virtual_machine_extensions` table sets up extensions for [Azure VMs](#virtual-machine-sets), adding capabilities like monitoring or management tools. It defines settings such as publisher, type, and versioning for consistent application across your environment. In the ERD, `virtual_machine_extensions` links one-to-many to [`virtual_machine_sets`](#virtual-machine-sets), letting multiple VM sets share the same extension config—like the [Azure Monitor Agent](https://learn.microsoft.com/en-us/azure/azure-monitor/agents/azure-monitor-agent-overview) for Windows shown below.\n\n```hcl\nvirtual_machine_extensions = {\n  azure_monitor = {  // 🔑 \"azure_monitor\" extension\n    name                       = \"AzureMonitorWindowsAgent\"\n    publisher                  = \"Microsoft.Azure.Monitor\"\n    type                       = \"AzureMonitorWindowsAgent\"\n    type_handler_version       = \"1.2\"\n    auto_upgrade_minor_version = true\n    automatic_upgrade_enabled  = true\n    settings                   = null\n  }\n}\n```\n\n| Field | Description |\n|-------|-------------|\n| `name` | Identifies the extension within the VM, e.g., `AzureMonitorWindowsAgent`. |\n| `publisher` | Specifies the extension’s provider, like `Microsoft.Azure.Monitor`. |\n| `type` | Defines the extension type, such as `AzureMonitorWindowsAgent`. |\n| `type_handler_version` | Sets the extension handler version, e.g., `1.2`. |\n| `auto_upgrade_minor_version` | Enables automatic minor version updates if `true`. |\n| `automatic_upgrade_enabled` | Activates automatic upgrades for the extension if `true`. |\n| `settings` | Optional; holds custom settings for the extension, or `null` if unused. |\n\n### Private DNS Zones\n\n\u003e Terraform variable: `var.private_dns_zones`\n\nThe `private_dns_zones` table provisions [Azure Private DNS Zones](https://learn.microsoft.com/azure/dns/private-dns-overview).\n\n* Private endpoints can refer to these zones by name when configuring DNS.\n* [Networks](#networks) can refer to these zones by name for both DNS registration and resolution.\n\n```hcl\nprivate_dns_zones = {\n  key_vault_private_endpoints = {                            # 🔑 \"key_vault_private_endpoints\" DNS zone\n    domain_name         = \"privatelink.vaultcore.azure.net\"  # Must be a valid domain name\n    resource_group_name = \"production\"                       # 🔗 Links to var.resource_groups\n    subscription_name   = \"production\"                       # 🔗 Links to var.subscriptions\n  }\n}\n```\n\n\u003e [!NOTE]\n\u003e [Private endpoints for Azure services require specific domain names.](https://learn.microsoft.com/azure/private-link/private-endpoint-dns) In the example provided above, `privatelink.vaultcore.azure.net` is the required domain name for Key Vault private endpoints.\n\n### Network Ports\n\n\u003e Terraform variable: `var.network_ports`\n\nThe `network_ports` table maps port names to port numbers. These ports are used when configuring [security rules](#security-rules).\n\nThe example below illustrates some commonly used ports.\n\n```hcl\nnetwork_ports = {\n  http  = \"80\"    # 🔑 \"http\" port\n  https = \"443\"   # 🔑 \"https\" port\n  rdp   = \"3389\"  # 🔑 \"rdp\" port\n  ssh   = \"22\"    # 🔑 \"ssh\" port\n}\n```\n\n### Network Security Rules\n\n\u003e Terraform variable: `var.network_security_rules`\n\nThe `network_security_rules` table names layer 4 network security rules that are applied to [network security groups](https://learn.microsoft.com/azure/virtual-network/network-security-groups-overview) defined in [`var.network_security_groups`](#network-security-groups). Security rules are associated with a network security group via its `security_rules` list, and the group is applied to subnets in [`var.networks`](#networks) using the `security_group_name` property.\n\nNetwork security rules are implemented using an easy-to-read fluent syntax that supports traffic filtering to/from:\n\n* Specific address spaces\n* Networks defined in [`networks`](#networks)\n* External networks defined in [`external_networks`](#external-networks)\n* Specific network subnets defined in [`networks`](#networks)\n* Specific external network subnets defined in [`external_networks`](#external-subnets)\n* Role-based VM sets defined in [`virtual_machine_sets`](#virtual-machine-sets)\n\nEach network security rule can specify optional inbound/outbound ports as defined in the [`network_ports`](#network-ports) table.\n\nEach rule can also specify a protocol (e.g., `Tcp`, `Udp`). By default, all protocols are included in the rule's scope.\n\n#### Example Rule: Deny all traffic to `main` network\n\n```hcl\nnetwork_security_rules = {\n  deny_all_to_network = {        # 🔑 Named security rule\n    deny = {\n      in = {\n        to = {\n          network = {            # ❌ Deny inbound to network...\n            name = \"main\"        # 🔗 Linked to var.networks or var.external_networks\n          }\n        }\n      }\n    }\n  }\n}\n```\n\n#### Example Rule: Allow all HTTP/S traffic from `alt` network to `production` subnet on `main` network\n\n```hcl\nnetwork_security_rules = {\n  allow_all_http_s_from_alt_to_main_production = {  # 🔑 Named security rule\n    port_names = [                                  # 🔗 Optional; links to `var.network_ports`\n      \"http\",\n      \"https\"\n    ]\n\n    allow = {\n      in = {                                        # ✅ Allow inbound...\n        from = {\n          network = {                               # From network...\n            name = \"alt\"                            # 🔗 Linked to var.networks or var.external_networks\n          }\n        }\n        to = {                \n          subnet = {                                # To subnet...\n            network_name = \"main\"                   # 🔗 Linked to var.networks or var.external_networks\n            subnet_name  = \"production\"             # 🔗 Subnet defined on linked network\n          }\n        }\n      }\n    }\n  }\n}\n```\n\n#### Example Rule: Allow all TCP traffic out from `10.100.0.0/16` space to `app` VM set\n\n```hcl\nnetwork_security_rules = {\n  allow_all_tcp_from_on_prem_to_app_vm_set = {  # 🔑 Named security rule\n    protocol = \"Tcp\"                            # Optional; Tcp protocol only\n\n    allow = {\n      out = {                                   # ✅ Allow outbound...\n        from = {\n          address_space = \"10.100.0.0/16\"       # From address space 10.100.0.0/16\n        }\n        to = {\n          vm_set = {                            # To role-based VM set\n            name = \"app\"                        # 🔗 Linked to var.virtual_machine_sets\n          }\n        }\n      }\n    }\n  }\n}\n```\n\n### Network Security Groups\n\n\u003e Terraform variable: `var.network_security_groups`\n\nThe `network_security_groups` table defines [Azure Network Security Groups (NSGs)](https://learn.microsoft.com/azure/virtual-network/network-security-groups-overview) that bundle one or more [security rules](#network-security-rules) together. An NSG is applied to a subnet by referencing it via the `security_group_name` property in [`var.networks`](#networks).\n\n```hcl\nnetwork_security_groups = {\n  main = {                           # 🔑 \"main\" network security group\n    location_name       = \"main\"     # 🔗 Links to var.locations\n    subscription_name   = \"main\"     # 🔗 Links to var.subscriptions\n    resource_group_name = \"main\"     # 🔗 Links to var.resource_groups\n\n    security_rules = [               # 🔗 Optional; links to var.network_security_rules\n      \"allow_from_on_prem_to_apps\",  # Rules are applied in the order they're defined here\n      \"deny_all_to_network\"\n    ]\n  }\n}\n```\n\n| Field | Description |\n|-------|-------------|\n| `location_name` | Links to a key in [`var.locations`](#locations), specifying the Azure region for the NSG. |\n| `subscription_name` | Links to a key in [`var.subscriptions`](#subscriptions), tying the NSG to a subscription. |\n| `resource_group_name` | Links to a key in [`var.resource_groups`](#resource-groups), defining the resource group for the NSG. |\n| `name` | Optional; names the NSG in Azure. Defaults to the map key if not set. |\n| `security_rules` | Optional; an ordered list of keys from [`var.network_security_rules`](#network-security-rules). Rules are applied in the order listed. Defaults to `[]`. |\n| `tags` | Optional; applies key-value tags to the NSG. Defaults to `{}`. |\n\n### Networks\n\n\u003e Terraform variable: `var.networks`\n\nThe `networks` table defines the virtual networks (VNets) in your Azure environment, distinct from external networks (e.g., on-premises or other clouds) covered in `var.external_networks`. It organizes VNets and their subnets, linking them to [subscriptions](#subscriptions), [locations](#locations), and [resource groups](#resource-groups). In the ERD, `networks` connects one-to-many with `subnets` and one-to-one with [`subscriptions`](#subscriptions), [`locations`](#locations), and [`resource_groups`](#resource-groups), anchoring your network topology.\n\n```hcl\nnetworks = {\n  main = {                                         # 🔑 \"main\" network\n    location_name       = \"primary\"                # 🔗 Links to var.locations\n    subscription_name   = \"production\"             # 🔗 Links to var.subscriptions\n    resource_group_name = \"production\"             # 🔗 Links to var.resource_groups\n    name                = \"main-vnet\"              # Optional; defaults to key 🔑 \"main\" if unset\n    address_space       = \"10.0.0.0/16\"            # Defines network address space in CIDR format\n\n    lock_groups = [\n      \"production_lock\"                            # 🔗 Optional; links to var.lock_groups\n    ]\n\n    private_dns_zones = {                          \n      registration_zone_name = \"registration_zone\" # 🔗 Optional; links to var.private_dns_zones \n                                                   # Only one registration zone is supported\n      resolution_zone_names = [                    # 🔗 Optional; links to var.private_dns_zones\n        \"resolution_zone\"                          # Multiple resolution zones are supported\n      ]\n    }\n\n    subnets = {\n      subnet_a = {                                 # 🔑 \"subnet_a\" subnet\n        name                = \"subnet-a\"           # Optional; defaults to key 🔑 \"subnet_a\" if unset\n        address_space       = \"10.0.0.0/24\"        # Defines \"subnet_a\" address space in CIDR format\n        security_group_name = \"main\"               # 🔗 Optional; links to var.network_security_groups\n      }\n\n      subnet_b = {                                 # 🔑 \"subnet_b\" subnet\n        name                = \"subnet-b\"           # Optional, defaults to key 🔑 \"subnet_b\" if unset\n        address_space       = \"10.0.1.0/24\"        # Defines \"subnet_a\" address space in CIDR format\n      }\n    }\n  }\n}\n```\n\n| Field | Description |\n|-------|-------------|\n| `location_name` | Links to a key in [`var.locations`](#locations), specifying the Azure region for the VNet. |\n| `subscription_name` | Links to a key in [`var.subscriptions`](#subscriptions), tying the VNet to a subscription. |\n| `resource_group_name` | Links to a key in [`var.resource_groups`](#resource-groups), defining the resource group for the VNet. |\n| `private_dns_zones` | Optional; if set, links to [`var.private_dns_zones`](#private-dns-zones). Specifies both registration and resolution DNS zones. |\n| `lock_groups` | Optional; if set, links to keys in [`var.lock_groups`](#lock-groups). Specifies the resource lock groups that this VNet belongs to. |\n| `name` | Optional; names the VNet in Azure, defaults to the map key (e.g., `main`) if not set. |\n| `address_space` | Defines the VNet’s IP address range, e.g., `10.0.0.0/16`. |\n| `subnets` | A nested map of subnets, each with a name (optional, defaults to key), `address_space` for its IP range, and an optional `security_group_name` linking to [var.network_security_groups](#network-security-groups) to apply an NSG to the subnet. |\n\n#### Peerings\n\n\u003e Terraform variable: `var.networks.peered_to`\n\nThe `peerings` section within the [`networks`](#networks) table sets up virtual network peerings, connecting [VNets within this model (`var.networks`)](#networks) or to [external networks (`var.external_networks`)](#external-networks). It enables traffic flow between networks, like linking a primary and alternate VNet. In the ERD, `peerings` represents a many-to-many relationship between [`networks`](#networks), or between [`networks`](#networks) and [`external_networks`](#external-networks), facilitating flexible network topologies.\n\n\u003e [!IMPORTANT]\n\u003e Network peerings are a one-way connection. Each `peered_to` entry establishes traffic flow from the source network to the target network only. For two-way communication, you must configure reciprocal peerings in both directions (e.g., `main` to `alt` and `alt` to `main`).\n\n```hcl\nnetworks = {\n  main = {         # 🔑 \"primary\" network\n                   # Other fields like location_name, subnets...\n    peered_to = [  # Multiple peerings can be declared\n      \"alt\"        # 🔗 Links to var.networks\n    ]\n  }\n  alt = {          # 🔑 \"alt\" network\n                   # Other fields like location_name, subnets...\n    peered_to = [  # Multiple peerings can be declared\n      \"main\"       # 🔗 Links to var.networks\n    ]\n  }\n}\n```\n\n| Field | Description |\n|-------|-------------|\n| `peered_to` | A list of network keys from [`var.networks`](#networks) or [`var.external_networks`](#external-networks) to peer with. For `external_networks`, a valid Azure `resource_id` is required. |\n\n#### Routes\n\n\u003e Terraform variable: `var.networks.subnets.route_traffic`\n\nThe `route_traffic` section is an optional map within each subnet of the [`networks`](#networks) table, defining custom routing rules for that subnet. Each route directs traffic to gateways, the Internet, appliances, or nowhere (dropped), with destinations as CIDR address spaces, networks, or networks and subnets declared in [`var.networks`](#networks) and [`var.external_networks`](#external-networks). In the ERD, `route_traffic` is a one-to-many child of `subnets`, linking to [`networks`](#networks) or `subnets` via `destined_for`. A route table is created per subnet only if `route_traffic` is defined.\n\n```hcl\nnetworks = {\n  main = {                                      # 🔑 \"main\" network\n    # Other fields...\n    subnets = {\n      subnet_a = {                              # 🔑 \"subnet_a\" subnet\n        address_space = \"10.0.0.0/24\"           # Subnet address space in CIDR format\n        route_traffic = {                       # Traffic routing rules\n          gateway_route = {                     # 🔑 \"gateway_route\" route\n            destined_for = {                    # When traffic is destined for...\n              address_space = \"192.168.1.0/24\"  # the \"192.168.1.0/24\" address space...\n            }\n            to_gateway = true                   # route to the default network gateway\n          }\n          internet_route = {                    # 🔑 \"internet_route\" route\n            destined_for = {                    # When traffic is destined for...\n              network = {                       # Network defined in var.networks or var.external_networks...\n                network_name = \"alt\"            # 🔗 linked to \"alt\" network in var.networks\n              }\n            }\n            to_internet = true                  # route to the Internet\n          }\n          appliance_route = {                   # 🔑 \"appliance_route\" route\n            destined_for = {                    # When traffic is destined for...\n              subnet = {                        # Subnet defined in var.networks or var.external_networks...\n                network_name = \"alt\"            # 🔗 linked to \"alt\" network in var.networks\n                subnet_name  = \"subnet_b\"       # 🔗 linked to \"subnet_b\" subnet in var.networks.subnets\n              }\n            }\n            to_appliance = {                    # route to a virtual appliance...\n              ip_address = \"192.168.1.1\"        # running at \"192.168.1.1\"\n            }\n          }\n          drop_route = {                        # 🔑 \"drop_route\" route\n            destined_for = {                    # When traffic is destined for...\n              address_space = \"0.0.0.0/0\"       # the Internet (0.0.0.0/0)...\n            }\n            to_nowhere = true                   # drop it\n          }\n        }\n      }\n    }\n  }\n  alt = {                                       # 🔑 \"alt\" network\n    # Other fields...\n    subnets = {\n      subnet_b = {                              # 🔑 \"subnet_b\" subnet\n        address_space = \"10.1.0.0/24\"           # Subnet address space in CIDR format\n      }\n    }\n  }\n}\n```\n\n\u003e [!IMPORTANT]  \n\u003e A dedicated route table is created for each subnet with `route_traffic` defined. If no routes are specified, no route table is created.\n\n| Field | Description |\n|-------|-------------|\n| `destined_for` | Required; sets the traffic target: `address_space` (CIDR, e.g., `192.168.1.0/24`), `network` (links to [`var.networks`](#networks) via `network_name`), or `subnet` (links to [`var.networks`](#networks) via `network_name` and `subnet_name`). |\n| `route_name` | Optional; names the route, defaults to `null` (auto-generated). |\n| `to_gateway` | Optional; if `true`, routes to a network gateway. Defaults to `false`. |\n| `to_internet` | Optional; if `true`, routes to the Internet. Defaults to `false`. |\n| `to_nowhere` | Optional; if `true`, drops traffic. Defaults to `false`. |\n| `to_appliance` | Optional; routes to an appliance with `ip_address` (e.g., `192.168.1.1`). Defaults to `null`. |\n\n### External Networks\n\n\u003e Terraform variable: `var.external_networks`\n\nThe `external_networks` table captures networks outside this model, unlike those defined in [`var.networks`](#networks). These can be on-premises, in Azure, or in another cloud, allowing your infrastructure to interact with them via [routing](#routes), [security rules](#security-rules), or [peering](#peerings). By specifying their address spaces and subnets, you can reference them in [`var.networks`](#networks) configurations. For Azure-based external networks, including a `resource_id` enables one-way [peering](#peerings) from [`var.networks`](#networks), provided you have sufficient permissions. In the ERD, `external_networks` links many-to-many with [`networks`](#networks) through [`peered_to`](#peerings), [`route_traffic`](#routes), and [`security_rules`](#security-rules), with `subnets` as a one-to-many child.\n\n```hcl\nexternal_networks = {                                  \n  on_prem_network = {                                 # 🔑 \"on_prem_network\" external network\n    address_space = \"10.10.0.0/16\"                    # External network address space can be used for\n                                                      # configuring routes and security rules\n    subnets = {\n      on_prem_database = {                            # 🔑 \"on_prem_database\" external subnet\n        name          = \"DatabaseSubnet\"              \n        address_space = \"10.10.0.0/24\"                # External subnet address space can be used for\n      }                                               # configuring routes and security rules\n    }\n  }\n\n  external_azure_network = {                          # 🔑 \"external_azure_network\" external network\n    address_space = \"10.20.0.0/16\"                    # External network address space can be used for\n                                                      # configuring routes and security rules\n    resource_id   = \"/subscriptions/12345678...\"      # External Azure network resource ID enables seamless\n                                                      # var.networks to var.external_networks peering                                               \n    subnets = {\n      external_service = {                            # 🔑 \"external_service\" subnet                \n        name          = \"ServiceSubnet\"\n        address_space = \"10.20.0.0/24\"                # External subnet address space can be used for\n      }                                               # configuring routes and security rules\n    }\n  }\n}\n```\n\n| Field | Description |\n|-------|-------------|\n| `address_space` | Required; defines the external network’s IP range, e.g., `10.10.0.0/16`, used in routes and security rules. |\n| `resource_id` | Optional; Azure resource ID for peering from [`var.networks`](#networks), e.g., `/subscriptions/12345678...`. Requires permissions. Defaults to `null`. |\n| `subnets` | Optional; maps subnets with `name` (e.g., `DatabaseSubnet`) and `address_space` (e.g., `10.10.0.0/24`) for detailed routing and security configs. Defaults to `{}`. |\n\n### Virtual Machine Sets\n\n\u003e Terraform variable: `var.virtual_machine_sets`\n\nThe `virtual_machine_sets` table configures groups of highly available VMs that share the same role, workload, and availability settings. By default, VMs are spread evenly across [Azure availability zones](https://learn.microsoft.com/azure/reliability/availability-zones-overview?tabs=azure-cli), with [custom distribution possible via `var.virtual_machine_set_zone_distribution`](#virtual-machine-set-zone-distribution). Related specs like VM count, SKU, and disks are defined in [`var.virtual_machine_set_specs`](#virtual-machine-set-specs), maintaining a 1:1 link with `virtual_machine_sets` and [`virtual_machine_set_zone_distribution`](#virtual-machine-set-zone-distribution) to streamline automation. In the ERD, `virtual_machine_sets` connects one-to-one with [`subscriptions`](#subscriptions), [`resource_groups`](#resource-groups), [`locations`](#locations), and [`key_vaults`](#key-vaults), and one-to-many with nested `extensions` and `data_disks`.\n\n```hcl\nvirtual_machine_sets = {\n  database = {                                             # 🔑 \"database\" VM set                                        \n    key_vault_name                    = \"primary\"          # 🔗 Links to var.key_vaults\n    location_name                     = \"primary\"          # 🔗 Links to var.locations\n    resource_group_name               = \"production\"       # 🔗 Links to var.resource_groups\n    subscription_name                 = \"production\"       # 🔗 Links to var.subscriptions\n    shutdown_schedule_name            = \"evening_shutdown\" # 🔗 Optional; links to var.virtual_machine_shutdown_schedules\n    scale_set_name                    = \"shared_vmss\"      # 🔗 Optional; links to var.virtual_machine_scale_sets\n    name                              = \"db\"               # Prefix for all VMs in this set\n    include_deployment_prefix_in_name = true               # Apply var.deployment_prefix? Default: false\n\n    tags = {\n      role = \"database\"                                    # Optional; tags all VMs\n    }\n\n    extensions = [                                         # Optional\n      \"azure_monitor\"                                      # 🔗 Links to var.virtual_machine_extensions\n    ]\n\n    lock_groups = [                                        # Optional\n      \"production_lock\"                                    # 🔗 Links to var.lock_groups\n    ]\n\n    maintenance = {                                        # Optional\n      schedule_name = \"guest_updates\"                      # 🔗 Optional; links to var.maintenance_schedules\n    }\n\n    os_type                   = \"Windows\"                  # Windows or Linux\n    os_disk_encryption_set_id = \"/subscriptions/12345678...\" # Optional; CMK encryption for the OS disk\n    disk_controller_type      = \"nvme\"                     # Optional; SCSI or NVMe based on SKU\n    enable_boot_diagnostics   = true                       # Enable boot diagnostics? Default: false\n  }\n}\n```\n\n| Field | Description |\n|-------|-------------|\n| `key_vault_name` | Links to a key in [`var.key_vaults`](#key-vaults), specifying the key vault for the VM set. |\n| `location_name` | Links to a key in [`var.locations`](#locations), setting the Azure region for the VMs. |\n| `resource_group_name` | Links to a key in [`var.resource_groups`](#resource-groups), defining the resource group for the VMs. |\n| `subscription_name` | Links to a key in [`var.subscriptions`](#subscriptions), tying the VMs to a subscription. |\n| `load_balancer` | Optional; if set, provisions an [Azure Load Balancer](https://learn.microsoft.com/azure/load-balancer/load-balancer-overview) for the VM set. See Virtual Machine Set Load Balancer for full configuration details. Defaults to `null` (no load balancer.) |\n| `lock_groups` | Optional; if set, links to keys in [`var.lock_groups`](#lock-groups). Specifies the resource lock groups that this VM set belongs to. By default, all child resources including disks and network interfaces inherit these lock groups. |\n| `maintenance.schedule_name` | Optional; if set, links to keys in [`var.maintenance_schedules`](#maintenance-schedules). Specifies the maintenance schedule that should be used when applying guest updates for the VMs. |\n| `shutdown_schedule_name` | Optional; if set, links to keys in [`var.virtual_machine_shutdown_schedules`](#shutdown-schedules). Applies a shutdown schedule to the VM set. |\n| `scale_set_name` | Optional; if set, links to a key in [`var.virtual_machine_scale_sets`](#virtual-machine-scale-sets). Allows multiple VM sets to share a single VM Scale Set. If omitted, a dedicated VM Scale Set is automatically created for this VM set. |\n| `name` | Prefixes all VMs in the set, used in their Azure names. |\n| `include_deployment_prefix_in_name` | If `true`, prepends `var.deployment_prefix` to resource names. Default: `false`. |\n| `tags` | Optional; applies key-value tags to all VMs, e.g., `role: database`. |\n| `extensions` | Optional; lists extensions from [`var.virtual_machine_extensions`](#virtual-machine-extensions) to apply. |\n| `os_type` | Specifies the OS: `Windows` or `Linux`. |\n| `os_disk_encryption_set_id` | Optional; specifies a disk encryption set ID (e.g., `/subscriptions/12345678...`) used to encrypt the OS disk with a customer-managed key (CMK). Defaults to `null`. |\n| `disk_controller_type` | Optional; sets disk controller to `SCSI` or `NVMe` based on VM SKU. |\n| `enable_boot_diagnostics` | If `true`, enables boot diagnostics. Default: `false`. |\n\n\u003e [!TIP]\n\u003e Lock groups can be overridden on VM set child resources. See [data disk groups](#virtual-machine-data-disk-groups) and [network interfaces](#virtual-machine-network-interfaces) for more information.\n\n\u003e [!NOTE]\n\u003e If a `virtual_machine_set` does not specify a `scale_set_name`, a dedicated VM Scale Set is automatically created for it. Use [`virtual_machine_scale_sets`](#virtual-machine-scale-sets) only when you need multiple VM sets to share the same scale set.\n\n#### Virtual Machine Image\n\n\u003e Terraform variable: `var.virtual_machine_sets.image`\n\nThe `image` section within [`virtual_machine_sets`](#virtual-machine-sets) selects the OS image for VMs, ensuring consistency and compliance. It can reference a custom/shared image by ID or an Azure Marketplace image by details like offer and publisher. In the ERD, `image` is a child of [`virtual_machine_sets`](#virtual-machine-sets), with a one-to-one relationship.\n\n```hcl\nvirtual_machine_sets = {\n  database = {                        # 🔑 \"database\" VM set\n                                      # Other fields...\n    image = {\n      reference = {\n        offer     = \"UbuntuServer\"    # Image offer name\n        publisher = \"Canonical\"       # Image publisher\n        sku       = \"18.04-LTS\"       # Image edition\n        version   = \"latest\"          # Image version\n      }\n    }\n  }\n}\n\n# Or, for a custom image:\n# image = {\n#   id = \"/subscriptions/12345678...\"  # Resource ID of custom/shared image\n# }\n```\n\n| Field | Description |\n|-------|-------------|\n| `id` | Optional; resource ID for a custom or shared image, e.g., `/subscriptions/12345678...`. |\n| `reference` | Optional; defines a Marketplace image with `offer`, `publisher`, `sku`, and `version`. |\n\n#### Virtual Machine Data Disk Groups\n\n\u003e Terraform variable: `var.virtual_machine_sets.data_disk_groups`\n\nThe `data_disk_groups` section within [`virtual_machine_sets`](#virtual-machine-sets) configures groups of data disks attached to VMs in a set, enabling scenarios like disk striping for high-performance workloads (e.g., SQL Server). Each group defines shared properties such as caching, encryption, and source images, with disks assigned contiguous Logical Unit Numbers (LUNs) for consistent attachment order. In the ERD, `data_disk_groups` is a one-to-many child of [`virtual_machine_sets`](#virtual-machine-sets), linking to [`key_vaults`](#key-vaults) for encryption and [`lock_groups`](#lock-groups) for resource protection. The number of disks and their sizes are specified in [`var.virtual_machine_set_specs.data_disk_groups`](#virtual-machine-set-disk-specs), ensuring a one-to-one key alignment between the two tables.\n\n```hcl\nvirtual_machine_sets = {\n  database = {                                         # 🔑 \"database\" VM set\n                                                       # Other fields...\n    data_disk_groups = {\n      data = {                                         # 🔑 \"data\" disk group\n        caching                      = \"ReadOnly\"      # ReadOnly caching for performance\n        enable_public_network_access = false           # Disable public access\n        disk_encryption_set_id       = \"/subscriptions/12345678...\"  # Optional; encryption set ID\n\n        image = {                                      # Optional; disk source\n          copy = {                                     # Copy from an existing managed disk\n            resource_id = \"/subscriptions/12345678/resourceGroups/rg/providers/Microsoft.Compute/disks/source-disk\"\n          }\n        }\n\n        lock_groups = [                               # Optional; overrides parent VM set lock groups\n          \"data_disk_lock\"                            # 🔗 Links to var.lock_groups\n        ]\n      }\n      logs = {                                         # 🔑 \"logs\" disk group\n        caching                      = \"ReadWrite\"    # ReadWrite caching\n        enable_public_network_access = false          # Disable public access\n      }\n    }\n  }\n}\n```\n\n| Field | Description |\n|-------|-------------|\n| `caching` | Optional; configures caching: `None`, `ReadOnly`, or `ReadWrite`. Defaults to `ReadWrite`. Optimizes performance for workloads like SQL Server striping. |\n| `disk_encryption_set_id` | Optional; specifies a disk encryption set ID (e.g., `/subscriptions/12345678...`) from Azure Key Vault for encryption. Defaults to `null`. |\n| `enable_public_network_access` | Optional; if `true`, allows public access to disks in the group for specific use cases. Defaults to `false` for security. |\n| `image` | Optional; defines the disk group’s source: `copy` (from a disk/snapshot), `import` (from a VHD), `platform` (from a Marketplace image), `restore` (from a backup/snapshot), or `null` (empty disks). Defaults to `null`. |\n| `lock_groups` | Optional; links to keys in [`var.lock_groups`](#lock-groups). Specifies lock groups for the disk group, overriding those defined in the parent [`virtual_machine_sets`](#virtual-machine-sets). Defaults to `[]`. |\n\n\u003e [!NOTE]  \n\u003e Each disk group is assigned contiguous LUNs automatically, starting from the lowest available LUN for the VM set. For example, if the `data` group has 3 disks and `logs` has 2, LUNs might be assigned as 0–2 for `data` and 3–4 for `logs`. This supports striping configurations for high-performance workloads.\n\n##### Image Configuration Options\n\nThe `image` field in `data_disk_groups` specifies the source for disks in the group, supporting various scenarios like copying existing disks, importing VHDs, using Marketplace images, or restoring from backups. Below are examples for each option, using the same fluent syntax as the [`network_security_rules`](#network-security-rules) section.\n\n###### Example: Copy Disks from an Existing Managed Disk\n\nThis configuration copies disks from an existing Azure managed disk or snapshot, useful for replicating pre-configured disk setups.\n\n```hcl\nvirtual_machine_sets = {\n  database = {                                         # 🔑 \"database\" VM set\n                                                       # Other fields...\n    data_disk_groups = {\n      data = {                                         # 🔑 \"data\" disk group\n        caching = \"ReadOnly\"                          # Optimize for read-heavy workloads\n        image = {\n          copy = {                                     # Copy from an existing managed disk\n            resource_id = \"/subscriptions/12345678/resourceGroups/rg/providers/Microsoft.Compute/disks/source-disk\"\n          }\n        }\n      }\n    }\n  }\n}\n```\n\n###### Example: Import Disks from a VHD File\n\nThis configuration imports disks from a VHD file stored in Azure Blob Storage, ideal for migrating existing disk images.\n\n```hcl\nvirtual_machine_sets = {\n  database = {                                         # 🔑 \"database\" VM set\n                                                       # Other fields...\n    data_disk_groups = {\n      data = {                                         # 🔑 \"data\" disk group\n        caching = \"ReadWrite\"                         # Enable read/write caching\n        image = {\n          import = {                                   # Import from a VHD\n            uri    = \"https://storage.blob.core.windows.net/vhds/sample.vhd\"\n            secure = true                              # Perform secure import\n          }\n        }\n      }\n    }\n  }\n}\n```\n\n###### Example: Use a Platform Image for Disks\n\nThis configuration uses a platform image from the Azure Marketplace, suitable for standardized disk setups.\n\n```hcl\nvirtual_machine_sets = {\n  database = {                                         # 🔑 \"database\" VM set\n                                                       # Other fields...\n    data_disk_groups = {\n      data = {                                         # 🔑 \"data\" disk group\n        caching = \"ReadOnly\"                          # Optimize for read-heavy workloads\n        image = {\n          platform = {                                # Use a platform image\n            image_reference_id = \"/subscriptions/12345678/resourceGroups/rg/providers/Microsoft.Compute/images/ubuntu-18.04\"\n          }\n        }\n      }\n    }\n  }\n}\n```\n\n###### Example: Restore Disks from a Backup\n\nThis configuration restores disks from an Azure Backup snapshot, useful for disaster recovery scenarios.\n\n```hcl\nvirtual_machine_sets = {\n  database = {                                         # 🔑 \"database\" VM set\n                                                       # Other fields...\n    data_disk_groups = {\n      data = {                                         # 🔑 \"data\" disk group\n        caching = \"ReadWrite\"                         # Enable read/write caching\n        image = {\n          restore = {                                 # Restore from a backup\n            resource_id = \"/subscriptions/12345678/resourceGroups/rg/providers/Microsoft.Compute/snapshots/backup-snapshot\"\n          }\n        }\n      }\n    }\n  }\n}\n```\n\n###### Example: Create Empty Disks\n\nThis configuration creates empty disks, ideal for initializing new storage without pre-existing data.\n\n```hcl\nvirtual_machine_sets = {\n  database = {                                         # 🔑 \"database\" VM set\n                                                       # Other fields...\n    data_disk_groups = {\n      data = {                                         # 🔑 \"data\" disk group\n        caching = \"ReadWrite\"                         # Enable read/write caching\n      }\n    }\n  }\n}\n```\n\n#### Virtual Machine Network Interfaces\n\n\u003e Terraform variable: `var.virtual_machine_sets.network_interfaces`\n\nThe `network_interfaces` section within [`virtual_machine_sets`](#virtual-machine-sets) configures the network connectivity for VMs, linking them to specific VNets and subnets. Each interface specifies a network, subnet, and IP settings, with options for accelerated networking. In the ERD, `network_interfaces` is a one-to-many child of [`virtual_machine_sets`](#virtual-machine-sets), with one-to-one links to [`networks`](#networks) and `subnets` via `network_name` and `subnet_name`, ensuring each VM set connects to the right network topology.\n\n\u003e [!IMPORTANT]\n\u003e Only one network interface per VM can have [accelerated networking](https://learn.microsoft.com/azure/virtual-network/accelerated-networking-overview?tabs=redhat) enabled (`enable_accelerated_networking = true`). By default, this feature is enabled. If the VM has multiple network interfaces, you must explicitly indicate which network interfaces should not have accelerated networking enabled (`enable_accelerated_networking = false`). \n\n```hcl\nvirtual_machine_sets = {\n  database = {                                         # 🔑 \"database\" VM set\n                                                       # Other fields...\n    network_interfaces = {\n      primary_nic = {                                  # 🔑 \"primary_nic\" network interface\n        network_name                  = \"main\"         # 🔗 Links to var.networks\n        subnet_name                   = \"subnet_a\"     # 🔗 Links to var.networks.main.subnets\n        private_ip                    = \"10.0.0.10\"    # Optional; static IP\n        private_ip_allocation         = \"Static\"       # Optional; static or dynamic\n        enable_accelerated_networking = true           # Optional; boost network performance.\n                                                       # See __Important__ accelerated networking note above.\n\n        lock_groups = [                                # Optional; overrides lock groups defined on parent VM set\n          \"nic_lock\"                                   # 🔗 Links to var.lock_groups\n        ]\n      }\n    }\n  }\n}\n```\n\n| Field | Description |\n|-------|-------------|\n| `network_name` | Required; links to a key in [`var.networks`](#networks), specifying the VNet for the interface. |\n| `subnet_name` | Required; links to a subnet key within the specified `network_name` in [`var.networks`](#networks). |\n| `lock_groups` | Optional; if set, links to keys in [`var.lock_groups`](#lock-groups). Specifies the resource lock groups that this network interface belongs to. These lock groups override lock groups defined at the [parent VM set](#virtual-machine-set) level. |\n| `private_ip` | Optional; sets a static private IP address, e.g., `10.0.0.10`. Defaults to `null` for dynamic allocation. |\n| `private_ip_allocation` | Optional; defines IP assignment: `Static` or `Dynamic`. Defaults to `Dynamic`. |\n| `enable_accelerated_networking` | Optional; if `true`, enables accelerated networking for better performance. Defaults to `true`. |\n\n#### Virtual Machine Set Load Balancer\n\n\u003e Terraform variable: `var.virtual_machine_sets.load_balancer`\n\nThe `load_balancer` section within [`virtual_machine_sets`](#virtual-machine-sets) provisions an [Azure Load Balancer](https://learn.microsoft.com/azure/load-balancer/load-balancer-overview) for the VM set, distributing inbound traffic across all VMs in the set. It supports both internal (private) and public frontends, a health probe, and one or more load-balancing rules. Port names in the health probe and rules reference entries in [`var.network_ports`](#network-ports), keeping port definitions consistent across your model.\n\n\u003e [!IMPORTANT]\n\u003e Exactly one of `internal_frontend` or `public_frontend` must be set per load balancer.\n\n##### Example: Internal Load Balancer\n\nAn internal load balancer distributes traffic within a VNet, using a private IP on a specified subnet as its frontend.\n\n```hcl\nnetwork_ports = {\n  https = \"443\"  # 🔑 \"https\" port\n}\n\nvirtual_machine_sets = {\n  app = {                                              # 🔑 \"app\" VM set\n                                                       # Other fields...\n    load_balancer = {\n      nic_name = \"primary_nic\"                         # 🔗 Links to a key in network_interfaces (below)\n      sku      = \"Standard\"                            # Optional; Standard (default) or Basic\n\n      internal_frontend = {                            # Private frontend on a VNet subnet\n        network_name       = \"main\"                    # 🔗 Links to var.networks\n        subnet_name        = \"app_subnet\"              # 🔗 Links to var.networks.main.subnets\n        private_ip_address = \"10.0.0.100\"              # Optional; static private IP. Dynamic if unset.\n      }\n\n      health_probe = {\n        protocol            = \"Tcp\"                    # Tcp, Http, or Https\n        port_name           = \"https\"                  # 🔗 Links to var.network_ports\n        interval_in_seconds = 15                       # Optional; seconds between probes\n        probe_threshold     = 2                        # Optional; consecutive failures before unhealthy\n      }\n\n      rules = {\n        https = {                                      # 🔑 \"https\" load-balancing rule\n          protocol           = \"Tcp\"                   # Tcp or Udp\n          frontend_port_name = \"https\"                 # 🔗 Links to var.network_ports\n          backend_port_name  = \"https\"                 # 🔗 Links to var.network_ports\n        }\n      }\n    }\n\n    network_interfaces = {\n      primary_nic = {                                  # 🔑 \"primary_nic\" — referenced by nic_name above\n        network_name = \"main\"                          # 🔗 Links to var.networks\n        subnet_name  = \"app_subnet\"                    # 🔗 Links to var.networks.main.subnets\n      }\n    }\n  }\n}\n```\n\n##### Example: Public Load Balancer\n\nA public load balancer exposes the VM set to the internet via a public IP address.\n\n```hcl\nnetwork_ports = {\n  https = \"443\"  # 🔑 \"https\" port\n}\n\nvirtual_machine_sets = {\n  web = {                                                    # 🔑 \"web\" VM set\n                                                             # Other fields...\n    load_balancer = {\n      nic_name = \"primary_nic\"                               # 🔗 Links to a key in network_interfaces (below)\n\n      public_frontend = {                                    # Public IP frontend\n        public_ip_name          = \"web-pip\"                  # Optional; name for the public IP resource\n        public_ip_zones         = [\"1\", \"2\", \"3\"]            # Optional; availability zones for the public IP\n        idle_timeout_in_minutes = 4                          # Optional; idle connection timeout in minutes\n        ddos_protection_mode    = \"VirtualNetworkInherited\"  # Optional; DDoS protection mode\n      }\n\n      health_probe = {\n        protocol     = \"Https\"                               # Tcp, Http, or Https\n        port_name    = \"https\"                               # 🔗 Links to var.network_ports\n        request_path = \"/health\"                             # Optional; required for Http/Https probes\n      }\n\n      rules = {\n        https = {                                            # 🔑 \"https\" load-balancing rule\n          protocol           = \"Tcp\"\n          frontend_port_name = \"https\"                       # 🔗 Links to var.network_ports\n          backend_port_name  = \"https\"                       # 🔗 Links to var.network_ports\n          enable_floating_ip = false                         # Optional; enable for SQL AlwaysOn, etc.\n        }\n      }\n    }\n\n    network_interfaces = {\n      primary_nic = {                                        # 🔑 \"primary_nic\" — referenced by nic_name above\n        network_name = \"main\"                                # 🔗 Links to var.networks\n        subnet_name  = \"web_subnet\"                          # 🔗 Links to var.networks.main.subnets\n      }\n    }\n  }\n}\n```\n\n| Field | Description |\n|-------|-------------|\n| `nic_name` | Required; links to a key in `network_interfaces` within this VM set. Specifies which NIC the load balancer backend pool attaches to. |\n| `sku` | Optional; sets the load balancer SKU: `Standard` or `Basic`. Defaults to `Standard`. |\n| `tags` | Optional; applies key-value tags to the load balancer resource. Defaults to `{}`. |\n| `internal_frontend` | Optional; configures a private frontend. Requires `network_name` (links to [`var.networks`](#networks)) and `subnet_name` (links to a subnet within that network). `private_ip_address` is optional; defaults to dynamic allocation if unset. |\n| `public_frontend` | Optional; configures a public IP frontend. `public_ip_name` (optional), `public_ip_zones` (optional; defaults to `[\"1\", \"2\", \"3\"]`), `idle_timeout_in_minutes` (optional; defaults to `4`), and `ddos_protection_mode` (optional; defaults to `VirtualNetworkInherited`). |\n| `health_probe.protocol` | Required; the probe protocol: `Tcp`, `Http`, or `Https`. |\n| `health_probe.port_name` | Required; links to a key in [`var.network_ports`](#network-ports), specifying the port to probe. |\n| `health_probe.interval_in_seconds` | Optional; seconds between probes. Defaults to `15`. |\n| `health_probe.probe_threshold` | Optional; consecutive failures before a VM is marked unhealthy. Defaults to `2`. |\n| `health_probe.request_path` | Optional; the HTTP/HTTPS path to probe, e.g., `/health`. Required when `protocol` is `Http` or `Https`. |\n| `rules` | Required; a map of load-balancing rules. Each rule requires `protocol` (`Tcp` or `Udp`), `frontend_port_name` (links to [`var.network_ports`](#network-ports)), and `backend_port_name` (links to [`var.network_ports`](#network-ports)). |\n| `rules.idle_timeout_in_minutes` | Optional; idle connection timeout per rule. Defaults to `4`. |\n| `rules.enable_floating_ip` | Optional; enables floating IP (Direct Server Return) for the rule. Required for scenarios like SQL Server AlwaysOn Availability Groups. Defaults to `false`. |\n\n\u003e [!NOTE]\n\u003e Port names in `health_probe.port_name`, `rules.frontend_port_name`, and `rules.backend_port_name` all link to [`var.network_ports`](#network-ports). This keeps port numbers defined in one place and reused consistently across security rules, health probes, and load-balancing rules.\n\n### Virtual Machine Set Specs\n\n\u003e Terraform variable: `var.virtual_machine_set_specs`\n\nThe `virtual_machine_set_specs` table defines the sizing and storage specs for each VM set in [`virtual_machine_sets`](#virtual-machine-sets), linked one-to-one by a shared key. It pairs with [`virtual_machine_sets`](#virtual-machine-sets) and [`virtual_machine_set_zone_distribution` (for custom zone adjustments)](#virtual-machine-set-zone-distribution) to complete the VM setup. In the ERD, `virtual_machine_set_specs` connects one-to-one with [`virtual_machine_sets`](#virtual-machine-sets), anchoring compute and storage details.\n\n```hcl\nvirtual_machine_set_specs = {\n  database = {                                # 🔑 \"database\" VM set\n    vm_count = 3                              # There are 3 VMs in this set\n    sku_size = \"Standard_D4ads_v5\"            # All VMs are size Standard_D4ads_v5\n    os_disk = {                                \n      disk_size_gb         = 128              # OS disk is 128 GiB\n      storage_account_type = \"Premium_LRS\"    # Can be Standard_LRS, Premium_LRS, StandardSSD_ZRS, or Premium_ZRS\n    }\n  }\n}\n```\n\n| Field | Description |\n|-------|-------------|\n| `vm_count` | Optional; sets the number of VMs in the set, e.g., `3`. Defaults to `2`. |\n| `sku_size` | Required; specifies the VM SKU, e.g., `Standard_D4ads_v5`, defining compute power. |\n| `os_disk` | Required; configures the OS disk with `disk_size_gb` (e.g., `128`) and `storage_account_type` (e.g., `Premium_LRS`, defaults to `PremiumV2_LRS`). |\n\n#### Virtual Machine Set Data Disk Group Specs\n\n\u003e Terraform variable: `var.virtual_machine_set_specs.data_disk_groups`\n\nThe `data_disk_groups` subsection within [`virtual_machine_set_specs`](#virtual-machine-set-specs) defines the sizing and storage specifications for data disk groups in [`virtual_machine_sets.data_disk_groups`](#virtual-machine-data-disk-groups). Each group specifies the number of disks, their size, and storage type, with optional IOPS settings for performance tuning. Keys must match those in [`var.virtual_machine_sets.data_disk_groups`](#virtual-machine-data-disk-groups) for a one-to-one relationship. In the ERD, `data_disk_groups` is a one-to-many child of [`virtual_machine_set_specs`](#virtual-machine-set-specs), ensuring consistent disk configurations across VM sets.\n\n```hcl\nvirtual_machine_set_specs = {\n  database = {                                # 🔑 \"database\" VM set\n                                              # Other fields...\n    data_disk_groups = {\n      data = {                                # 🔑 \"data\" disk group\n        disk_count           = 3              # 3 disks in the group\n        disk_size_gb         = 128            # Each disk is 128 GiB\n        storage_account_type = \"Premium_LRS\"  # Premium locally redundant storage\n        disk_iops_read_write = 5000           # 5000 IOPS for read/write operations\n      }\n      logs = {                                # 🔑 \"logs\" disk group\n        disk_count           = 2              # 2 disks in the group\n        disk_size_gb         = 256            # Each disk is 256 GiB\n        storage_account_type = \"Premium_LRS\"  # Premium locally redundant storage\n        disk_iops_read_only  = 3000           # 3000 IOPS for read-only operations\n      }\n    }\n  }\n}\n```\n\n| Field | Description |\n|-------|-------------|\n| `disk_count` | Optional; specifies the number of disks in the group, e.g., `3`. Defaults to `1`. Useful for striping scenarios like SQL Server. |\n| `disk_size_gb` | Required; sets the size of each disk in the group in gigabytes, e.g., `128`. |\n| `storage_account_type` | Optional; specifies the storage type: `Standard_LRS`, `StandardSSD_ZRS`, `Premium_LRS`, `PremiumV2_LRS`, `StandardSSD_LRS`, or `UltraSSD_LRS`. Defaults to `PremiumV2_LRS`. |\n| `disk_iops_read_write` | Optional; sets IOPS for read/write operations, e.g., `5000`. Defaults to `null` (provider default). |\n| `disk_iops_read_only` | Optional; sets IOPS for read-only operations, e.g., `3000`. Defaults to `null` (provider default). |\n\n\u003e [!IMPORTANT]  \n\u003e Ensure the `disk_count` aligns with workload requirements, as increasing the number of disks in a group can enhance performance for striped configurations but may increase costs. Verify that `storage_account_type` supports the chosen IOPS settings, as some types (e.g., `UltraSSD_LRS`) are required for high IOPS.\n\n### Virtual Machine Scale Sets\n\n\u003e Terraform variable: `var.virtual_machine_scale_sets`\n\nThe `virtual_machine_scale_sets` table defines named [Azure Virtual Machine Scale Sets (Flexible orchestration)](https://learn.microsoft.com/azure/virtual-machine-scale-sets/overview) that can be shared across multiple [`virtual_machine_sets`](#virtual-machine-sets). By default, each `virtual_machine_set` automatically gets its own dedicated VM Scale Set — no entry in this table is required for that behavior. Defining an entry here and referencing it via `scale_set_name` on one or more `virtual_machine_sets` allows those VM sets to share the same underlying scale set.\n\n```hcl\nvirtual_machine_scale_sets = {\n  shared_vmss = {                                          # 🔑 \"shared_vmss\" scale set\n    location_name                     = \"primary\"          # 🔗 Links to var.locations\n    resource_group_name               = \"production\"       # 🔗 Links to var.resource_groups\n    name                              = \"shared-vmss\"      # Optional; custom name in Azure\n    include_deployment_prefix_in_name = true               # Apply var.deployment_prefix? Default: true\n\n    tags = {\n      purpose = \"shared\"                                   # Optional; tags the scale set\n    }\n  }\n}\n\n# Reference the shared scale set from one or more virtual_machine_sets:\nvirtual_machine_sets = {\n  app = {                                                  # 🔑 \"app\" VM set\n    # Other fields...\n    scale_set_name = \"shared_vmss\"                         # 🔗 Links to var.virtual_machine_scale_sets\n  }\n  worker = {                                               # 🔑 \"worker\" VM set\n    # Other fields...\n    scale_set_name = \"shared_vmss\"                         # 🔗 Links to var.virtual_machine_scale_sets\n  }\n}\n```\n\n| Field | Description |\n|-------|-------------|\n| `location_name` | Links to a key in [`var.locations`](#locations), specifying the Azure region for the scale set. |\n| `resource_group_name` | Links to a key in [`var.resource_groups`](#resource-groups), defining the resource group for the scale set. |\n| `name` | Optional; custom name for the scale set in Azure. Defaults to an auto-generated name based on the map key if not set. |\n| `include_deployment_prefix_in_name` | If `true`, prepends `var.deployment_prefix` to the scale set name. Default: `true`. |\n| `tags` | Optional; applies key-value tags to the scale set. Defaults to `{}`. |\n\n\u003e [!NOTE]\n\u003e If a `virtual_machine_set` does not specify a `scale_set_name`, a dedicated VM Scale Set is automatically created for it. Use `virtual_machine_scale_sets` only when you need multiple VM sets to share the same scale set.\n\n### Virtual Machine Set Zone Distribution\n\n\u003e Terraform variable: `var.virtual_machine_set_zone_distribution`\n\nThe `virtual_machine_set_zone_distribution` table adjusts the placement of VMs from [`virtual_machine_sets`](#virtual-machine-sets) across [Azure availability zones](https://learn.microsoft.com/azure/reliability/availability-zones-overview?tabs=azure-cli), overriding the default even distribution (across all three zones) set by `infra_map_vm_set`. It shares a one-to-one relationship with [`virtual_machine_sets`](#virtual-machine-sets) and [`virtual_machine_set_specs`](#virtual-machine-set-specs) via a common key, used only when custom zone allocations are needed, like for capacity constraints. In the ERD, `virtual_machine_set_zone_distribution` links one-to-one with [`virtual_machine_sets`](#virtual-machine-sets), tailoring zonal deployment for each set. \n\n\u003e [!NOTE]\n\u003e If no zone distribution is configured for a [VM set defined in `var.virtual_machine_sets`](#virtual-machine-sets), VMs in that set will be distributed evenly across all three availability zones.\n\n```hcl\nvirtual_machine_set_zone_distribution = {\n  primary_bca_web = {  # 🔗 Links to var.virtual_machine_sets\n    custom = {         # Custom distribution    \n      \"1\" = 2          # 2 VMs in zone 1\n      \"2\" = 8          # 8 VMs in zone 2\n    }\n  }\n  database = {         # 🔗 Links to var.virtual_machine_sets\n    even = [           # Distribute VMs evenly across zones 1 and 3\n      \"1\",             \n      \"3\"\n    ]\n  }\n}\n```\n\n| Field | Description |\n|-------|-------------|\n| `custom` | Optional; maps zone numbers (e.g., `\"1\"`, `\"2\"`) to specific VM counts (e.g., `2`, `8`) for targeted distribution. Defaults to `null`. |\n| `even` | Optional; lists zones (e.g., `[\"1\", \"3\"]`) for even VM distribution across those zones. Defaults to `null`. If both `custom` and `even` are `null`, VMs spread evenly across all zones. |\n\n### Storage Accounts\n\n\u003e Terraform variable: `var.storage_accounts`\n\nThe `storage_accounts` table configures [Azure storage accounts](https://learn.microsoft.com/azure/storage/common/storage-account-overview) to store data such as [blobs](https://learn.microsoft.com/azure/storage/blobs/storage-blobs-overview) and [files](https://learn.microsoft.com/azure/storage/files/storage-files-introduction). Each account specifies its [location](#locations), [resource group](#resource-groups), and [subscription](#subscriptions), with options for [access tiers](https://learn.microsoft.com/azure/storage/blobs/access-tiers-overview) and [replication](https://learn.microsoft.com/azure/storage/common/storage-redundancy). In the ERD, `storage_accounts` links one-to-one with [`subscriptions`](#subscriptions), [`locations`](#locations), and [`resource_groups`](#resource-groups), and one-to-many with [`blob_containers`](#blob-containers) and [`file_shares`](#file-shares).\n\n```hcl\nstorage_accounts = {\n  files = {  # 🔑 Primary key: \"files\"\n    location_name       = \"primary\"      # 🔗 Links to var.locations\n    resource_group_name = \"shared\"       # 🔗 Links to var.resource_groups\n    subscription_name   = \"primary\"      # 🔗 Links to var.subscriptions\n    name                = \"appfiles\"\n    replication_type    = \"RAGRS\"\n  }\n}\n```\n\n| Field | Description |\n|-------|-------------|\n| `location_name` | Required; links to a key in [`var.locations`](#locations), setting the storage account’s Azure region. |\n| `resource_group_name` | Required; links to a key in [`var.resource_groups`](#resource-groups), defining the storage account’s resource group. |\n| `subscription_name` | Required; links to a key in [`var.subscriptions`](#subscriptions), tying the storage account to a subscription. |\n| `name` | Optional; names the storage account, e.g., `appfiles`. Defaults to `null` (auto-generated if unset). |\n| `access_tier` | Optional; sets the access tier: `Hot` or `Cool`. Defaults to `Hot`. |\n| `account_tier` | Optional; sets the performance tier: `Standard` or `Premium`. Defaults to `Standard`. |\n| `account_type` | Optional; specifies the account kind: `StorageV2`, `Storage`, `BlobStorage`, or `FileStorage`. Defaults to `StorageV2`. |\n| `replication_type` | Optional; sets data replication: `LRS`, `GRS`, `RAGRS`, `ZRS`, `GZRS`, and `RAGZRS`. Defaults to `ZRS`. |\n| `allow_http_access` | Optional; if `true`, enables HTTP access. Defaults to `false` for security. |\n| `include_deployment_prefix_in_name` | Optional; if `true`, prepends a deployment prefix to the name. Defaults to `true`. |\n| `lock_groups` | Optional; lists lock groups for resource protection, e.g., `[\"main_lock\"]`. Defaults to `[]`. |\n| `tags` | Optional; applies key-value tags, e.g., `{ environment = \"production\" }`. Defaults to `{}`. |\n\n\u003e [!WARNING]\n\u003e We strongly recommend that you allow storage account HTTPS access only (`allow_http_access = false`). This is the default.\n\n### Blob Containers\n\n\u003e Terraform variable: `var.blob_containers`\n\nThe `blob_containers` table configures [Azure Blob Storage](https://learn.microsoft.com/azure/storage/blobs/storage-blobs-overview) containers within [storage accounts](#storage-accounts) to store unstructured data like files or backups. Each container specifies its storage account and name, with an option for public access. In the ERD, `blob_containers` links one-to-one with [`storage_accounts`](#storage-accounts) via `storage_account_name`.\n\n```hcl\nblob_containers = {\n  uploaded_files = {                # 🔑 Primary key: \"uploaded_files\"\n    storage_account_name = \"files\"  # 🔗 Links to var.storage_accounts\n    name                 = \"uploaded-files\"\n  }\n}\n```\n\n| Field | Description |\n|-------|-------------|\n| `storage_account_name` | Required; links to a key in [`var.storage_accounts`](#storage_accounts), specifying the storage account for the container. |\n| `name` | Required; names the blob container, e.g., `uploaded-files`. |\n| `enable_public_network_access` | Optional; if `true`, allows public access to the container. Defaults to `false` for security. |\n\n### File Shares\n\n\u003e Terraform variable: `var.file_shares`\n\nThe `file_shares` table configures [Azure File Shares](https://learn.microsoft.com/azure/storage/files/storage-files-introduction) within [storage accounts](#storage-accounts) for shared file storage accessible via [SMB](https://learn.microsoft.com/azure/storage/files/files-smb-protocol?tabs=azure-portal) or [NFS](https://learn.microsoft.com/azure/storage/files/files-nfs-protocol) protocols. Each share specifies its storage account, name, and storage quota, with options for access tier and protocol. In the ERD, `file_shares` links one-to-one with [`storage_accounts`](#storage-accounts) via `storage_account_name`.\n\n```hcl\nfile_shares = {\n  uploaded_files = {                # 🔑 Primary key: \"uploaded_files\"\n    storage_account_name = \"files\"  # 🔗 Links to var.storage_accounts\n    name                 = \"uploaded-files\"\n    quota_gb             = 1\n  }\n}\n```\n\n| Field | Description |\n|-------|-------------|\n| `storage_account_name` | Required; links to a key in [`var.storage_accounts`](#storage_accounts), specifying the storage account for the file share. |\n| `name` | Required; names the file share, e.g., `uploaded-files`. |\n| `quota_gb` | Required; sets the storage limit in gigabytes, e.g., `1`. |\n| `access_tier` | Optional; sets the access tier: `Hot`, `Cool`, or `TransactionOptimized`. Defaults to `Hot`. |\n| `protocol` | Optional; specifies the access protocol: `SMB` or `NFS`. Defaults to `SMB`. |\n\n### Key Vaults\n\n\u003e Terraform variable: `var.key_vaults`\n\nThe `key_vaults` table configures Azure Key Vaults for secure storage of secrets, keys, and certificates, requiring a location, subscription, and resource group as its foundation. Commonly used optional fields like SKU, tags, and network ACLs enhance its setup. \n\n```hcl\nkey_vaults = {\n  primary = {                                # 🔑 \"primary\" key vault\n    location_name       = \"primary\"          # 🔗 Links to var.locations\n    subscription_name   = \"main\"             # 🔗 Links to var.subscriptions\n    resource_group_name = \"main_key_vaults\"  # 🔗 Links to var.resource_groups\n    sku_name            = \"standard\"         # Optional; standard or premium\n\n    lock_groups = [                          # Optional\n      \"production_lock\"                      # 🔗 Links to var.lock_groups\n    ]\n\n    tags = {\n      env = \"production\"                     # Optional; custom tags\n    }\n\n    network_acls = {\n      bypass         = \"AzureServices\"       # Optional; allow Azure services\n      default_action = \"Allow\"               # Optional; default access rule\n    }\n  }\n  alt = {                                    # 🔑 \"alt\" key vault\n    location_name       = \"alt\"              # 🔗 Links to var.locations\n    subscription_name   = \"main\"             # 🔗 Links to var.subscriptions\n    resource_group_name = \"main_key_vaults\"  # 🔗 Links to var.resource_groups\n    sku_name            = \"standard\"         # Optional; standard or premium\n\n    lock_groups = [                          # Optional\n      \"non_production_lock\"                  # 🔗 Links to var.lock_groups\n    ]\n\n    tags = {\n      env = \"production\"                     # Optional; custom tags \n    }\n\n    network_acls = {\n      bypass         = \"AzureServices\"       # Optional; allow Azure services\n      default_action = \"Allow\"               # Optional; default access rule\n    }\n  }\n}\n```\n\n| Field | Description |\n|-------|-------------|\n| `location_name` | Required; links to a key in [`var.locations`](#locations), setting the vault’s Azure region. |\n| `subscription_name` | Required; links to a key in [`var.subscriptions`](#subscriptions), tying the vault to a subscription. |\n| `resource_group_name` | Required; links to a key in [`var.resource_groups`](#resource-groups), defining the vault’s resource group. |\n| `lock_groups` | Optional; if set, links to keys in [`var.lock_groups`](#lock-groups). Specifies the resource lock groups that the vault belongs to. |\n| `sku_name` | Optional; sets the vault SKU: `standard` or `premium`. Defaults to `standard`. |\n| `tags` | Optional; applies key-value tags, e.g., `env: production`. Defaults to `{}`. |\n| `network_acls` | Optional; configures network access with `bypass` (e.g., `AzureServices`) and `default_action` (e.g., `Allow`). Defaults to `{}`. |\n\n## Contributing\n\nThis project welcomes contributions and suggestions.  Most contributions require you to agree to a\nContributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us\nthe rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.\n\nWhen you submit a pull request, a CLA bot will automatically determine whether you need to provide\na CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions\nprovided by the bot. You will only need to do this once across all repos using our CLA.\n\nThis project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).\nFor more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or\ncontact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.\n\n## Trademarks\n\nThis project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft \ntrademarks or logos is subject to and must follow \n[Microsoft's Trademark \u0026 Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general).\nUse of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship.\nAny use of third-party trademarks or logos are subject to those third-party's policies.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fazure%2Frelational-infrastructure","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fazure%2Frelational-infrastructure","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fazure%2Frelational-infrastructure/lists"}