Terraform Configuration for Azure Virtual Desktop Host Pools and Session Hosts

Azure Virtual Desktop delivers Windows desktops and applications to users anywhere. It is the managed replacement for traditional RDS deployments, handling the session brokering, load balancing, and gateway infrastructure for you. Setting up AVD through the portal involves a lot of clicking and is hard to reproduce. Terraform brings repeatability and version control to the process. This article provides an overview of how to use Terraform to deploy an ARM Azure Virtual Desktop environment, not AVD Classic. There are several pre-requisites requirements for Azure Virtual Desktop. New to Azure Virtual Desktop.

The platform foundation assumption matters before any Terraform code is written. It is assumed that an appropriate platform foundation is already setup which may or may not be the Enterprise Scale Landing Zone platform foundation. The foundation assumption shapes how resource groups, networking, and identity are referenced in Terraform modules. An existing foundation reduces duplication and ensures that the AVD resources are placed inside a consistent subscription and landing zone boundary. The impact for an operator is that Terraform can reference pre-existing subnets and resource groups by name or ID rather than attempting to recreate corporate networking. Contextually, the foundation assumption connects directly to the resource group and virtual network definitions that follow, because those definitions inherit location and naming conventions from the platform.

Prerequisites and Platform Foundation

An Azure subscription is required. If you don't have an Azure subscription, create a free account before you begin. The subscription provides the billing boundary and permission scope for all azurerm resources created by Terraform. Without an active subscription, the provider cannot authenticate and the plan phase fails.

The working directory is established by creating a directory in which to test the sample Terraform code and make it the current directory. The directory isolation allows variables, state files, and provider configuration to remain separate from other infrastructure code. This separation prevents state collisions and supports version control.

Authentication is performed with Azure CLI. Install it and log in using

bash az login

Authentication establishes an access token that the Azure provider uses to read and write resources. The impact is that Terraform operations succeed only when the logged-in principal has Contributor or equivalent permissions on the target subscription and resource group. Contextually, az login precedes terraform init and any apply, because the provider configuration relies on the CLI authentication context or explicit service principal credentials.

The Azure provider for Terraform is installed with

bash terraform init

Initialization downloads the azurerm provider plugin and builds the dependency graph. The impact is that subsequent plan and apply commands can resolve resource schemas and provider-specific attributes. Contextually, provider initialization must occur after providers.tf is created, and before any plan is generated.

Provider Configuration and Initial Setup

Provider configuration is defined in a file named providers.tf. The reference configuration is

hcl terraform { required_providers { azurerm = { source = "hashicorp/azurerm" version = "~>2.0" } azuread = { source = "hashicorp/azuread" } } } provider "azurerm" { features {} }

The required_providers block pins the azurerm source to hashicorp/azurerm with version ~>2.0 and declares azuread for identity resources. The impact is deterministic provider resolution across team members and CI pipelines. Using the same provider version avoids breaking changes in resource schemas. Contextually, this providers.tf file is reused in both infrastructure setup and session host deployment articles, establishing a consistent authentication and feature baseline.

The article tested with the following Terraform and Terraform provider versions:

[!INCLUDE Terraform abstract]

The inclusion placeholder signals that exact version numbers are documented in the source article. The impact is that readers can verify compatibility before upgrading Terraform. Contextually, version testing aligns with the requirement to avoid hardcoding sensitive information and to maintain reproducible plans.

Resource Group and Networking Foundation

Building a basic Azure Virtual Desktop infrastructure with Terraform begins with a resource group to hold all AVD resources.

hcl resource "azurerm_resource_group" "rg" { name = "avd-resource-group" location = "WestUS" }

The resource group name avd-resource-group provides a logical container for all subsequent resources. The location WestUS determines the Azure region for the resource group and all resources that inherit its location. The impact is cost, latency, and compliance alignment for users. If the location does not match the user population, latency increases. Contextually, the resource group location is later referenced by the virtual network and by azurermvirtualdesktop_workspace.

Virtual network and subnet definition follows:

hcl resource "azurerm_virtual_network" "vnet" { name = "avd-vnet" address_space = ["10.0.0.0/16"] location = azurerm_resource_group.rg.location resource_group_name = azurerm_resource_group.rg.name } resource "azurerm_subnet" "subnet" { name = "avd-subnet" resource_group_name = azurerm_resource_group.rg.name virtual_network_name = azurerm_virtual_network.vnet.name address_prefixes = ["10.0.1.0/24"] }

The virtual network avd-vnet with addressspace 10.0.0.0/16 provides the IP address space for session hosts. The subnet avd-subnet with addressprefixes 10.0.1.0/24 isolates AVD traffic. The impact is network segmentation and security group application. Using a dedicated subnet allows network security groups and private endpoints to be scoped to AVD only. Contextually, these network resources are referenced later by session host NICs via azurerm_subnet.subnet.id.

Workspace Creation

An AVD workspace is created with azurermvirtualdesktop_workspace. The reference main.tf snippet includes:

hcl resource "azurerm_resource_group" "sh" { name = var.rg_name location = var.resource_group_location }

The resource group name is output when execution plan is applied. Using variables var.rgname and var.resourcegroup_location decouples naming from code and supports multiple environments. The impact is that the same module can be applied to dev, test, and prod by changing variables only. Contextually, variable-driven resource groups enable scaling and updates without editing code.

The workspace resource is:

hcl resource "azurerm_virtual_desktop_workspace" "workspace" { name = var.workspace resource_group_name = azurerm_resource_group.sh.name location = azurerm_resource_group.sh.location friendly_name = "${var.prefix} Workspace" description = "${var.prefix} Workspace" }

The workspace groups application groups together for user access. The friendly_name and description provide user-facing labels in the Azure portal and in the client. The impact is improved discoverability for end users. Contextually, the workspace must exist before application groups can be associated, establishing a dependency chain.

Host Pool Definition

The host pool is the core resource. The host pool is the collection of session hosts (VMs) that users connect to. Application groups define what users can access - either a full desktop or individual applications. Workspaces group application groups together for user access. And finally, the session hosts are the actual VMs that run the desktops.

The article teaches how to:

  • Use Terraform to create an Azure Virtual Desktop workspace
  • Use Terraform to create an Azure Virtual Desktop host pool
  • Use Terraform to create an Azure Desktop Application Group
  • Associate a Workspace and a Desktop Application Group

The host pool resource is referenced as:

hcl resource "azurerm_virtual_desktop_host_pool" "hostpool"

In practice the host pool definition includes name, resource group, location, type, and friendly name. The impact is that the host pool becomes the registration target for session hosts and the scope for load balancing. Contextually, the host pool name is later referenced by session host registration and by application group associations.

Architecture overview shows the relationships:

A Workspace connects to Desktop App Group and RemoteApp Group. Both groups connect to Host Pool. Host Pool connects to Session Host 1, Session Host 2, Session Host N.

The graph relationship informs dependency ordering in Terraform. The workspace must exist before application groups can reference it. The host pool must exist before session hosts can register. This ordering prevents apply failures due to missing references.

Application Group Association

Application groups define what users can access - either a full desktop or individual applications. The article teaches how to use Terraform to create an Azure Desktop Application Group and associate a Workspace and a Desktop Application Group.

The association step links an application group to a workspace via azurermvirtualdesktopworkspaceapplicationgroupassociation. The impact is that users browsing the workspace see the correct applications or desktops. Without association, the application group remains orphaned and inaccessible. Contextually, association closes the loop between workspace, application group, and host pool.

Session Host Deployment

This article shows you how to build Session Hosts and deploy them to an AVD Host Pool with Terraform. This article assumes you've already deployed the Azure Virtual Desktop Infrastructure.

Session host deployment covers:

  • Use Terraform to create NIC for each session host
  • Use Terraform to create VM for session host
  • Join VM to domain
  • Register VM with Azure Virtual Desktop
  • Use variables file

The providers.tf file is reused:

hcl terraform { required_providers { azurerm = { source = "hashicorp/azurerm" version = "~>2.0" } azuread = { source = "hashicorp/azuread" } } } provider "azurerm" { features {} }

Session host VMs reference resources created when the infrastructure was built - such as

azurerm_subnet.subnet.id

and

azurerm_virtual_desktop_host_pool.hostpool.name

Referencing existing resources ensures that session hosts join the correct subnet and register with the correct host pool. The impact is correct network placement and user routing. Contextually, this reference pattern prevents drift between infrastructure and session host layers.

Key points for session host scaling include:

  • Use count to indicate how many resources will be created

Using count allows a single VM definition to be duplicated for Session Host 1, Session Host 2, and Session Host N. The impact is rapid scaling up or down by changing a variable. Contextually, count ties directly to the Scaling benefit described earlier: easily scale your AVD infrastructure up or down by modifying your Terraform configuration and re-applying it.

Lifecycle Management with Terraform

You can use Terraform to manage your Azure Virtual Desktop environment throughout its lifecycle.

Scaling: Easily scale your AVD infrastructure up or down by modifying your Terraform configuration and re-applying it. Scaling changes the number of session hosts or the size of the host pool. The impact is cost elasticity and user capacity matching. Contextually, scaling relies on count and variable-driven VM sizing, which are defined in the session host module.

Updates: Update VM images, configurations, or application groups by modifying the Terraform code and re-running the apply command. Updates propagate changes to the entire fleet consistently. The impact is reduced manual patching and configuration drift. Contextually, updates work because Terraform state tracks current resource attributes and computes a plan for changes.

Rollback: In case of errors, you can easily roll back to previous states using Terraform's state management features. Rollback restores the previous configuration and resource set. The impact is reduced downtime risk during changes. Contextually, rollback depends on version-controlled Terraform code and state snapshots, reinforcing the value of version control.

Benefits and Operational Considerations

What are the benefits of using Terraform for Azure Virtual Desktop?

Using Terraform offers several advantages, including automation of deployments, improved consistency, reproducibility, version control, and streamlined management of your Azure Virtual Desktop environment. It significantly reduces manual effort and potential human errors.

Automation of deployments removes portal clicking. Consistency is achieved because the same HCL produces identical resources across environments. Reproducibility ensures that a new environment can be recreated from code. Version control enables peer review and audit trails. Streamlined management centralizes changes in code rather than scattered portal edits. The impact is faster delivery and fewer configuration mistakes. Contextually, these benefits are realized across workspace, host pool, application group, and session host layers.

Can I manage existing Azure Virtual Desktop deployments with Terraform?

While Terraform excels in creating new deployments, it can also be used to manage existing resources. You can import existing resources into your Terraform state, allowing you to manage them alongside newly created ones. Consult the Azure provider documentation for specifics on importing resources.

Importing bridges brownfield environments to Terraform. The impact is gradual migration without rebuilding resources. Contextually, import aligns with the lifecycle management goal of managing the environment throughout its lifecycle, not just at creation.

Security and Sensitive Information Handling

How do I handle sensitive information like passwords in my Terraform configuration?

Avoid hardcoding sensitive information directly into Terraform code.

Hardcoding exposes secrets in version control and logs. The impact is credential leakage and compliance violations. Contextually, avoiding hardcoding supports the reproducibility and version control benefits, because secrets can be injected via variables files, Azure Key Vault, or environment variables while the code remains shareable.

Component Relationships Table

The following table summarizes the core AVD components and their Terraform responsibilities.

| Component | Terraform Resource | Purpose |
| Host Pool | azurermvirtualdesktophostpool | Collection of session hosts users connect to |
| Application Group | azurermvirtualdesktopapplicationgroup | Defines desktop or RemoteApp access |
| Workspace | azurermvirtualdesktopworkspace | Groups application groups for user access |
| Session Host | azurerm
windowsvirtualmachine + NIC | VM that runs desktops and registers to host pool |
| Resource Group | azurermresourcegroup | Container for all AVD resources |
| Virtual Network | azurermvirtualnetwork | Network boundary for session hosts |
| Subnet | azurerm_subnet | IP range for session host NICs |

The table clarifies dependencies. Workspaces group application groups. Application groups reference host pools. Host pools contain session hosts. Session hosts require network resources. This dense web of information ensures that Terraform dependencies are declared correctly.

Common Operational Patterns

A typical workflow starts with providers.tf and main.tf creation. Create a file named providers.tf and insert the following code. Create a file named main.tf and insert the following code. Once you verify the changes, you apply the execution plan to deploy the infrastructure.

The execution plan review is a safety checkpoint. The impact is early detection of unintended changes before they are applied to production. Contextually, plan review combines with version control to provide an audit trail for who approved a change.

For session hosts, a variables file supports environment-specific values. Use variables file. The impact is separation of code and configuration. Contextually, variables enable the scaling and updates benefits by allowing changes without code edits.

Conclusion

Terraform configuration for Azure Virtual Desktop creates a repeatable, version-controlled path from zero to production AVD. The platform foundation assumption sets the boundary for resource groups and networking. Provider configuration establishes authentication and version pinning. Resource groups and virtual networks provide the secure network foundation. Workspaces, host pools, and application groups define the logical access model. Session hosts materialize the compute layer and register to the host pool.

Lifecycle management through Terraform enables scaling by modifying configuration and re-applying, updates by changing VM images and application groups and re-running apply, and rollback through state management. Importing existing resources extends Terraform control to brownfield deployments. Avoiding hardcoded secrets preserves security while maintaining reproducibility.

The architecture overview ties workspace to application groups to host pool to session hosts. The graph relationship enforces dependency ordering and clarifies impact of changes. The benefits of automation, consistency, reproducibility, version control, and streamlined management reduce manual effort and human errors. The operational patterns of providers.tf, main.tf, variables files, and execution plan verification complete the process.

This configuration approach aligns with Azure best practices for ARM Azure Virtual Desktop environments, not AVD Classic, and supports enterprise scale landing zone foundations when present.

Sources

  1. DevOpsRoles
  2. OneUptime
  3. GitHub MicrosoftDocs
  4. Microsoft Learn Configure
  5. Microsoft Learn Create

Related Posts