Azure Virtual Desktop lets organizations deliver 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. But 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 post walks through deploying a complete AVD environment with Terraform, including host pools, application groups, workspaces, and session host VMs. The decision to move from portal clicks to Terraform is a structural shift in how the environment is governed. Repeatability means that the same topology can be rebuilt on demand in development, test, and production without manual drift. Version control means that changes to host pool capacity, application group membership, or workspace associations are captured as code history, auditable and reviewable.
The architecture that Terraform materializes is not a single resource but a layered dependency graph. The host pool is the collection of session hosts, which are 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 relationship is directional. A Workspace points to Desktop App Group and RemoteApp Group. Both groups point to a Host Pool. The Host Pool points to Session Host 1, Session Host 2, Session Host N. This graph is reproduced in Terraform by resource references that enforce create order and dependency.
The host pool is the core resource in the AVD Terraform model. The host pool is the core resource. Establishing the host pool first creates the identity that session hosts will register against. Without a host pool, application groups cannot be scoped, and workspaces have no target. In practice, the host pool name becomes the namespace for registration tokens, personal versus pooled desktop types, and session limits. The Terraform configuration for the host pool is the anchor for subsequent NIC, VM, and registration resources.
The resource group and networking foundation is expressed as explicit Terraform resources. First, create a resource group to hold all your AVD resources:
resource "azurerm_resource_group" "rg" {
name = "avd-resource-group"
location = "WestUS"
}
The resource group name avd-resource-group and location WestUS are the top-level container for all AVD resources. The location choice propagates to the virtual network, session hosts, and virtual desktop services. Impact is that all resources inherit the same Azure region, which determines latency to users and data residency.
Next, define your virtual network and subnet:
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"] and subnet avd-subnet with addressprefixes ["10.0.1.0/24"] provides the private IP space for session hosts. The reference to azurermresourcegroup.rg.location and azurermresourcegroup.rg.name ensures the network is co-located with the resource group. This coupling prevents accidental cross-region networking. In production, the subnet is the network boundary for VM placement, NSG rules, and ExpressRoute or VPN connectivity.
Deploying the virtual machines that will host Azure Virtual Desktop sessions is the next material step. Note that you would typically use more robust configurations in a production environment. The section details the creation of the virtual machines that will host your Azure Virtual Desktop sessions. The VM creation references the subnet id and the host pool name. Key points from the session host build are to use count to indicate how many resources will be created and to reference resources that were created when the infrastructure was built, such as azurermsubnet.subnet.id and azurermvirtualdesktophost_pool.hostpool.name. Using count enables a single VM definition to be multiplied to Session Host 1, Session Host 2, Session Host N. Referencing the subnet and host pool enforces that the VM is placed in the correct network and can register to the correct pool.
The provider configuration is the entry point for Terraform to interact with Azure and Azure AD. 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. The providers file establishes the required providers and the azurerm provider features block.
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~>2.0"
}
azuread = {
source = "hashicorp/azuread"
}
}
}
provider "azurerm" {
features {}
}
The required_providers block pins azurerm to ~>2.0 and declares azuread. The version pin influences which resource schemas are available. The azurerm provider features {} block is the standard placeholder for provider-level feature toggles.
The workspace and application group layer is described in the Configure Azure Virtual Desktop using Terraform article. This article provides an overview of how to use Terraform to deploy an ARM Azure Virtual Desktop environment, not AVD Classic. The article is dated 03/18/2023. The pre-requisites for Azure Virtual Desktop are several. New to Azure Virtual Desktop is referenced. It is assumed that an appropriate platform foundation is already setup which may or may not be the Enterprise Scale Landing Zone platform foundation.
In this article, you learn 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 learning goals map directly to the architecture graph. Workspace creation enables user-facing grouping. Host pool creation provides the backend VM collection. Application group creation defines desktop versus RemoteApp access. Association binds the workspace to the application groups.
The Terraform workflow for this article follows a file structure. Create a directory in which to test the sample Terraform code and make it the current directory. Create a file named providers.tf and insert the following code. Create a file named main.tf and insert the following code. Create a file named variables.tf and insert the following code. The variables file contains parameterized inputs that control deployment location and naming.
variable "resource_group_location" { default = "eastus" description = "Location of the resource group." }
variable "rg_name" { type = string default = "rg-avd-resources" description = "Name of the Resource group in which to deploy service objects" }
variable "workspace" { type = string description = "Name of the Azure Virtual Desktop workspace" default = "AVD TF Workspace" }
variable "hostpool" { type = string description = "Name of the Azure Virtual Desktop host pool" default = "AVD-TF-HP" }
variable "rfc3339" { type = string default = "2022-03-30T12:43:13Z" description = "Registration token expiration" }
variable "prefix" {
The variable resourcegrouplocation defaults to eastus. The variable rg_name defaults to rg-avd-resources. The variable workspace defaults to AVD TF Workspace. The variable hostpool defaults to AVD-TF-HP. The variable rfc3339 defaults to 2022-03-30T12:43:13Z for registration token expiration. The prefix variable is started but truncated in the reference. Parameterization allows the same module to be reused across subscriptions without editing code.
Outputs are used to surface identity information. The output is defined as:
output "AVD_user_groupname" { description = "Azure Active Directory Group for AVD users" value = azuread_group.aad_group.display_name }
The output exposes the Azure Active Directory Group for AVD users. This enables downstream modules or documentation to reference the user group name without querying state manually.
The Terraform lifecycle operations are referenced via includes. Terraform init is performed to install the Azure provider. The command sequence is:
terraform init
Authentication to Azure is performed with:
az login
The Azure CLI login establishes the AzureRM provider context. The article also references terraform plan and terraform apply plan steps, and terraform plan destroy for teardown.
Verification after apply is portal based. On the Azure portal, Select Azure Virtual Desktop. Select Host pools and then the Name of the pool created resource. Select Session hosts and then verify the session host is listed. This portal verification confirms that the Terraform created resources are visible in the AVD service plane and that session hosts have registered.
The benefits of using Terraform for Azure Virtual Desktop are enumerated as 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. Scaling is easily done by modifying Terraform configuration and re-applying it. Updates to VM images, configurations, or application groups are done by modifying the Terraform code and re-running the apply command. Rollback is possible using Terraform's state management features.
Frequently asked questions cover management of existing deployments. 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.
Sensitive information handling is addressed. Avoid hardcoding sensitive information directly into your Terraform code. This guidance prevents credentials, passwords, and registration tokens from being committed to source control. Sensitive values should be supplied via variable files, environment variables, or secret stores.
Terraform Lifecycle Management
The lifecycle of an AVD environment under Terraform is scaling, updates, and rollback. Scaling is performed by changing the count of session host VMs or the size parameter in the VM resource and re-applying. Updates are performed by changing VM image versions or application group definitions in code and re-applying. Rollback is performed by reverting the Terraform state to a previous commit and applying. State management is the mechanism that makes rollback reliable.
Prerequisites and Provider Configuration
Prerequisites include an Azure subscription. If you don't have an Azure subscription, create a free account before you begin. The Azure provider for Terraform is installed using terraform init. Azure CLI login is performed using az login. The platform foundation may be Enterprise Scale Landing Zone or a custom foundation. The article is tested with the following Terraform and Terraform provider versions. The exact version matrix is abstracted in the reference.
Variables and Parameterization
Parameterization is central to reuse. The variables file defines resourcegrouplocation, rg_name, workspace, hostpool, rfc3339, and prefix. Each variable has a default and description. Defaults allow quick testing. Descriptions document intent for operators.
Security and Sensitivity Handling
Sensitive information like passwords should not be hardcoded. The recommendation is to avoid hardcoding sensitive information directly into your Terraform code. This applies to registration tokens, admin passwords, and client secrets. The impact is reduced exposure in source control and CI pipelines.
Verification and Operational Workflow
After apply, verification is performed in the Azure portal under Azure Virtual Desktop, Host pools, Session hosts. The session host list confirms registration. The Terraform plan destroy step is documented for clean teardown.
The table below summarizes the core AVD components and their Terraform role.
| Component | Terraform Resource Concept | User Impact |
| Workspace | azure virtual desktop workspace | Groups application groups for user access |
| Host Pool | azure virtual desktop host pool | Collection of session hosts VMs users connect to |
| Application Group | desktop application group / remoteapp group | Defines what users can access desktop or app |
| Session Host | VM with NIC registered to host pool | Actual VM running desktops |
The table below summarizes the Terraform files referenced in the articles.
| File | Purpose | Example Content |
| providers.tf | Provider and requiredproviders declaration | terraform requiredproviders azurerm ~>2.0 |
| main.tf | Resource definitions | host pool, workspace, application group |
| variables.tf | Parameter inputs | resourcegrouplocation, rg_name, workspace, hostpool |
The table below summarizes the key variables from variables.tf.
| Variable | Default | Description |
| resourcegrouplocation | eastus | Location of the resource group |
| rg_name | rg-avd-resources | Name of the Resource group in which to deploy service objects |
| workspace | AVD TF Workspace | Name of the Azure Virtual Desktop workspace |
| hostpool | AVD-TF-HP | Name of the Azure Virtual Desktop host pool |
| rfc3339 | 2022-03-30T12:43:13Z | Registration token expiration |
The architecture graph is reproduced as a dependency model. Workspace points to Desktop App Group and RemoteApp Group. Both groups point to Host Pool. Host Pool points to Session Host 1, Session Host 2, Session Host N. This dependency model ensures that Terraform creates resources in the correct order and that references are resolvable.
The overall workflow for a new deployment is to create a directory, create providers.tf, main.tf, variables.tf, run terraform init, run terraform plan, run terraform apply. For session hosts specifically, the workflow assumes the AVD infrastructure is already deployed, then creates NIC for each session host, creates VM for session host, joins VM to domain, registers VM with Azure Virtual Desktop, and uses a variables file.
The impact of using Terraform for AVD is operational consistency. Manual portal changes create drift that is invisible to source control. Terraform codifies the desired state and makes drift detectable via plan. The contextual layer is that organizations managing multiple AVD environments for different business units benefit from module reuse and variable overrides rather than duplicated portal clicks.
Conclusion
The reference facts describe a complete path from initial provider setup through resource group and network creation, host pool and workspace definition, application group association, session host VM build, and verification. Terraform brings repeatability and version control to AVD deployments that were previously portal driven. The host pool remains the core resource, with workspaces and application groups providing user access semantics. Session hosts are built with count based replication and references to pre-created network and host pool resources. Variables provide parameterization for location, naming, and token expiration. Provider configuration pins azurerm to ~>2.0 and declares azuread. The workflow includes init, plan, apply, and destroy, with portal verification of host pool and session host registration. Scaling, updates, and rollback are enabled by state management. Importing existing resources is supported for brownfield adoption. Sensitive information is avoided via hardcoding. The articles referenced are the oneuptime deployment walkthrough, devopsroles lifecycle guidance, MicrosoftDocs configuration article dated 03/18/2023 for ARM AVD, and the learn.microsoft.com session host creation guide. Together these form a cohesive Terraform practice for Azure Virtual Desktop that emphasizes code as the source of truth for host pools, session hosts, workspaces, and application groups.