Using GitHub and Terraform to deploy Azure resources - Part 6

Table Of Contents


I have now come to the part where I will start deploying AVD resources in my Azure environment. I am going to split the resources up into three parts. This first part will be the “backend,” meaning AVD workspace, host pool, and application groups. The next part will be on RBAC roles and security groups, and the last part will be on the session hosts.

Azure virtual desktop hostpool

First, I will create a host pool for AVD as a container for the session hosts.

I have created a new folder in my repository called “rg-avd-cloudninja-001,” which will contain all the resources for my AVD environment.

I have added the following to my file.

resource "azurerm_resource_group" "resourcegroup" {
    name        = var.ResourceGroup
    location    = var.Location

resource "azurerm_virtual_desktop_host_pool" "hostpool" {
  location            = azurerm_resource_group.resourcegroup.location
  resource_group_name =

  name                     = "vdpool-cloudninja-001"
  friendly_name            = "Cloudninja host pool"
  validate_environment     = true
  start_vm_on_connect      = true
  custom_rdp_properties    = "targetisaadjoined:i:1;audiocapturemode:i:1;audiomode:i:0"
  description              = "Shared desktop for office use"
  type                     = "Pooled"
  maximum_sessions_allowed = 10
  load_balancer_type       = "DepthFirst"

resource "azurerm_virtual_desktop_host_pool_registration_info" "registrationkey" {
  hostpool_id     =
  expiration_date = timeadd(timestamp(), "180m")

As I have shown multiple times, the first section creates the resource group. I now create the host pool called “vdpool-cloudninja-001.” I will be using Azure AD login to this host pool, so I have added the custom RDP property called “targetisaadjoined:i:1” and set the maximum users to 10 and the load balancer to “DepthFirst.” I have chosen this load balancer to fill each session host up before turning on the next one.

The last section above is where I set the host pool registration token, and this needs to be created so I can add session hosts to the pool. I have set the expiration to be three hours from when I run my code, and this should give me enough time to provision the session host; if not, I can create a new token.

Azure virtual desktop workspace

Second, I am creating the workspace for AVD. The workspace is a collection of host pools that each user can access. In this blog series, I will have only one workspace and one host pool, but in larger environments, there can be multiple of each.

I have added the following to the file.

resource "azurerm_virtual_desktop_workspace" "workspace" {
  name                = "vdws-cloudninja-001"
  location            = azurerm_resource_group.resourcegroup.location
  resource_group_name =

  friendly_name = "Workspace for"
  description   = "Workspace for"
  depends_on = [azurerm_virtual_desktop_host_pool.hostpool]

The code above is straightforward. I am creating a workspace called “vdws-cloudninja-001,” with a friendly name of “Workspace for” I have a dependency on the host pool, but this is not needed; I just like to have it created in this order.

Application groups

To allow users to use AVD, they need to be assigned permissions for it, and this is done by adding the users (or groups) to application groups. I will be creating two application groups, one for remote applications and one for the desktop.

I have added the code below to the file.

resource "azurerm_virtual_desktop_application_group" "remoteapp" {
  name                = "vdag-cloudninja-remoteapp-001"
  location            = azurerm_resource_group.resourcegroup.location
  resource_group_name =

  type          = "RemoteApp"
  host_pool_id  =
  friendly_name = "Remote App group for Cloudninja"
  description   = "Remote App group for Cloudninja"

resource "azurerm_virtual_desktop_application_group" "desktopapp" {
  name                = "vdag-cloudninja-desktop-001"
  location            = azurerm_resource_group.resourcegroup.location
  resource_group_name =
  default_desktop_display_name = "Desktop"

  type          = "Desktop"
  host_pool_id  =
  friendly_name = "Desktop App group for Cloudninja"
  description   = "Desktop App group for Cloudninja"

The code above creates the application groups named “vdag-cloudninja-remoteapp-001” and “vdag-cloudninja-desktop-001.”

With the application groups created, I can now associate them with the workspace so the users can access their applications.

I have added the code below to the file.

resource "azurerm_virtual_desktop_workspace_application_group_association" "desktopapp" {
  workspace_id         =
  application_group_id =

resource "azurerm_virtual_desktop_workspace_application_group_association" "remoteapp" {
  workspace_id         =
  application_group_id =

As you can see from the code, I am using the output of the workspace section and the output of the application group to associate the workspace and the application group.

FSLogix storage account

The final section of this part of the blog series is creating a storage account that can host the FSLogix profiles for the AVD users. I use a premium storage account for this since I want the best user experience.

I have added the code below to the file.

resource "azurerm_storage_account" "FSLogixStorageAccount" {
  name                      = var.FSLogixStorageAccount
  location                  = azurerm_resource_group.resourcegroup.location
  resource_group_name       =
  account_tier              = "Premium"
  account_replication_type  = "LRS"
  account_kind              = "StorageV2"


In this part, I deployed all the main components of the AVD environment, except for session hosts. Session hosts will get a part for themselves, but before I start that section, I will ensure that my AVD environment gets the correct RBAC permissions and add users to Azure AD groups, so this will come in the next part of the blog series.

Any feedback is welcome, so reach out on Twitter or LinkedIn, so I can fix any errors or optimize the code I am using.

Part 1:

Part 2:

Part 3:

Part 4:

Part 5:

Part 7:

Part 8:

Link for all the code in this post

I have put all the code used in this blog post on my GitHub repository so you can download or fork the repository if you want to.