From 4dab10866fcec9508b733a0d708e9f8e7fbc9b72 Mon Sep 17 00:00:00 2001 From: Jen Sheerin Date: Mon, 3 Jan 2022 19:38:18 -0500 Subject: [PATCH 1/7] initial file creation --- .vscode/settings.json | 8 + .../101-azure-virtual-desktop/README.md | 138 ++++++++++++++++++ .../101-azure-virtual-desktop/afstorage.tf | 43 ++++++ .../101-azure-virtual-desktop/defaults.tfvars | 20 +++ quickstart/101-azure-virtual-desktop/host.tf | 126 ++++++++++++++++ .../101-azure-virtual-desktop/loganalytics.tf | 14 ++ quickstart/101-azure-virtual-desktop/main.tf | 54 +++++++ .../101-azure-virtual-desktop/networking.tf | 57 ++++++++ .../options/netapp/defaults.tfvars | 16 ++ .../options/netapp/netappstorage.tf | 67 +++++++++ .../options/netapp/variables.tf | 122 ++++++++++++++++ .../101-azure-virtual-desktop/outputs.tf | 39 +++++ .../101-azure-virtual-desktop/provider.tf | 15 ++ quickstart/101-azure-virtual-desktop/rbac.tf | 25 ++++ quickstart/101-azure-virtual-desktop/sig.tf | 35 +++++ .../101-azure-virtual-desktop/variables.tf | 101 +++++++++++++ 16 files changed, 880 insertions(+) create mode 100644 .vscode/settings.json create mode 100644 quickstart/101-azure-virtual-desktop/README.md create mode 100644 quickstart/101-azure-virtual-desktop/afstorage.tf create mode 100644 quickstart/101-azure-virtual-desktop/defaults.tfvars create mode 100644 quickstart/101-azure-virtual-desktop/host.tf create mode 100644 quickstart/101-azure-virtual-desktop/loganalytics.tf create mode 100644 quickstart/101-azure-virtual-desktop/main.tf create mode 100644 quickstart/101-azure-virtual-desktop/networking.tf create mode 100644 quickstart/101-azure-virtual-desktop/options/netapp/defaults.tfvars create mode 100644 quickstart/101-azure-virtual-desktop/options/netapp/netappstorage.tf create mode 100644 quickstart/101-azure-virtual-desktop/options/netapp/variables.tf create mode 100644 quickstart/101-azure-virtual-desktop/outputs.tf create mode 100644 quickstart/101-azure-virtual-desktop/provider.tf create mode 100644 quickstart/101-azure-virtual-desktop/rbac.tf create mode 100644 quickstart/101-azure-virtual-desktop/sig.tf create mode 100644 quickstart/101-azure-virtual-desktop/variables.tf diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..ed9462b7 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "markdownlint.config": { + "MD028": false, + "MD025": { + "front_matter_title": "" + } + } +} \ No newline at end of file diff --git a/quickstart/101-azure-virtual-desktop/README.md b/quickstart/101-azure-virtual-desktop/README.md new file mode 100644 index 00000000..9098f388 --- /dev/null +++ b/quickstart/101-azure-virtual-desktop/README.md @@ -0,0 +1,138 @@ +## Terraform for Azure Virtual Desktop + +The purpose of this repository is to demonstrate using Terraform to deploy a simple Azure Virtual Desktop environment. For Classic Azure Virtual Desktop click [here](https://github.com/Azure/RDS-Templates/tree/master/wvd-sh/terraform-azurerm-windowsvirtualdesktop). + +## Requirements and limitations +* Ensure that you meet the [requirements for Azure Virtual Desktop](https://docs.microsoft.com/en-us/azure/virtual-desktop/overview#requirements) +* Terraform must be installed and configured as outlined [here](https://docs.microsoft.com/en-us/azure/developer/terraform/get-started-cloud-shell) +* Active Directory already in place in this example, we are using AD in it’s own VNet. +* Users in AAD that will be given access to AVD +* This demo does not support Azure ADDS only deployment +* Destroy could produce errors deleting subnet due to resources associated. Manually delete resources within the subnet before running destroy + +## Components + +* Azure Virtual Desktop Environment +* Networking Infrastructure +* Session Hosts +* Profile Storage +* Role Based Access Control + +## Features + +This directory contains the various components for building out Azure Virtual Desktop. +* `main.tf` + deploys a new workspace, hostpool, application group with associations +* `networking.tf` + deploys a new vnet, subnet, nsg and peering to AD vnet +* `host.tf` + deploys new session host from the marketplace build and join to domain +* `afstorage.tf` + deploys Azure Files storage for profiles and creates file share with RBAC permissions for the users group ([NTFS permissions will need to be configured](https://docs.microsoft.com/en-us/azure/virtual-desktop/create-file-share)) +* `rbac.tf` + deploys rbac assignment for the users group +* `variables.tf` + Input variables +* `defaults.tfvars` + declares the actual input values (keep security in mind if you are putting confidential data) +* `provider.tf` + Azure RM and Azure AD provider configuation +* `outputs.tf` + defines the outputs that will be displayed on deployment +* `netappstorage.tf` + as an alternate to Azure Files storage this deploys NetApp Files storage for profiles in a dedicated subnet (access needs to be granted to the ANF service) [Set up Azure NetApp Files](https://docs.microsoft.com/en-us/azure/azure-netapp-files/azure-netapp-files-quickstart-set-up-account-create-volumes?tabs=azure-portal) + +## Varialble Inputs + +| Name | Description | Default | +|:---|:---|:---| +| `rg_name` | Name of the Resource Group in which to deploy these resources | `AVD-TF` | +| `deploy_location` | Region in which to deploy these resources | - | +| `hostpool` | Name of the Azure Virtual Desktop host pool | `AVD-TF-HP` | +| `ad_vnet` | Name of domain controller VNet | - | +| `dns_servers` | Custom DNS configuration | - | +| `vnet_range` | Address range for deployment VNet | - | +| `subnet_range` | Address range for session host subnet | - | +| `avd_users` | The resource group for AD VM | `[]` | +| `aad_group_name` | Azure Active Directory Group for AVD users | - | +| `rdsh_count` | Number of AVD machines to deploy | 2 | +| `prefix` | Prefix of the name of the AVD machine(s) | - | +| `domain_name` | Name of the domain to join | - | +| `domain_user_upn` | Username for domain join (do not include domain name as this is appended | - | +| `domain_password` | Password of the user to authenticate with the domain | - | +| `vm_size` | Size of the machine to deploy | `Standard_DS2_v2` | +| `ou_path` | The ou path for AD | `""` | +| `local_admin_username` | The local admin username for the VM | - | +| `local_admin_password` | The local admin password for the VM | - | +| `netapp_acct_name` | The NetApp account name | `AVD_NetApp` | +| `netapp_pool_name` | The NetApp pool name | `AVD_NetApp_pool` | +| `netapp_volume_name` | The NetApp volume name | `AVD_NetApp_volume` | +| `netapp_smb_name` | The NetApp smb name | `AVDNetApp` | +| `netapp_volume_path` | The NetApp volume path | `AVDNetAppVolume` | +| `netapp_subnet_name` | The NetApp subnet name | `NetAppSubnet` | +| `netapp_address` | The Address range for NetApp Subnet | - | + +## Deploy +If you’ve not previously setup terraform, check out this article to get it installed [Quickstart - Configure Terraform using Azure Cloud Shell](https://docs.microsoft.com/en-us/azure/developer/terraform/get-started-cloud-shell) + +You can review our sample configuration video here + +Once Terraform is setup and you have created your Terraform templates, the first step is to initialize Terraform. This step ensures that Terraform has all the prerequisites to build your template in Azure. + +``` +terraform init +``` + +The next step is to have Terraform review and validate the template. An execution plan is generated and stored in the file specified by the -out parameter. + +We also need to pass our variable definitions file during the plan. We can either load it automatically by renaming env.tfvars as terraform.tfvars OR env.auto.tfvars, in which case we will use the following to create the execution plan: + +```bash +terraform plan -out terraform_azure.tfplan +``` + +When you're ready to build the infrastructure in Azure, apply the execution plan: + +```bash +terraform apply terraform_azure.tfplan +``` + +## Final Configuration + +You’ll notice we didn’t actually configure the session hosts to use our profile storage at any point. There is an assumption that we are using GPO to manage FSLogix across our host pools as documented here: [Use FSLogix Group Policy Template Files - FSLogix](https://docs.microsoft.com/en-us/fslogix/use-group-policy-templates-ht). + +At a minimum you’ll need to configure the registry keys to enable FSLogix and configure the VHD Location to the NetApp Share URI: [Profile Container registry configuration settings - FSLogix](https://docs.microsoft.com/en-us/fslogix/profile-container-configuration-reference#enabled) + +## Troubleshooting Terraform deployment +
+Click to expand +Terraform deployment can fail in two main categories: + +Issues with Terraform code +1. [Issues with Desired State Configuration (DSC)](#issues-with-desired-state-configuration-dsc) +2. [Issues with Terraform code](#issues-with-desired-state-configuration-dsc) + +While it is rare to have issues with the Terraform code it is still possible, however most often errors are due to bad input in variables.tf. + +* If there are errors in the Terraform code, please file a GitHub issue. +* If there are warning in the Terraform code feel free to ignore or address for your own instance of that code. +* Using Terraform error messages it's a good starting point towards identifying issues with input variables + +### Issues with Desired State Configuration (DSC) + +To troubleshoot this type of issue, navigate to the Azure portal and if needed reset the password on the VM that failed DSC. Once you are able to log in to the VM review the log files in the following two folders: +
+ +## Additional References +
+Click to expand + +- [Terraform Download](https://www.terraform.io/downloads.html) +- [Visual Code Download](https://code.visualstudio.com/Download) +- [Powershell VS Code Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.PowerShell) +- [HashiCorp Terraform VS Code Extension](https://marketplace.visualstudio.com/items?itemName=HashiCorp.terraform) +- [Azure Terraform VS Code Extension Name](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azureterraform) +- [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-windows?tabs=azure-cli) +- [Configure the Azure Terraform Visual Studio Code extension](https://docs.microsoft.com/en-us/azure/developer/terraform/configure-vs-code-extension-for-terraform) +- [Setup video](https://youtu.be/YmbmpGdhI6w) +
\ No newline at end of file diff --git a/quickstart/101-azure-virtual-desktop/afstorage.tf b/quickstart/101-azure-virtual-desktop/afstorage.tf new file mode 100644 index 00000000..d674a34e --- /dev/null +++ b/quickstart/101-azure-virtual-desktop/afstorage.tf @@ -0,0 +1,43 @@ +## Create a Resource Group for Storage +resource "azurerm_resource_group" "rg_storage" { + location = "east us" + name = "af-storage-rg" +} + +# generate a random string (consisting of four characters) +# https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string +resource "random_string" "random" { + length = 4 + upper = false + special = false +} + +## Azure Storage Accounts requires a globally unique names +## https://docs.microsoft.com/en-us/azure/storage/common/storage-account-overview +## Create a File Storage Account +resource "azurerm_storage_account" "storage" { + name = "stor${random_string.random.id}" + resource_group_name = azurerm_resource_group.rg_storage.name + location = azurerm_resource_group.rg_storage.location + account_tier = "Premium" + account_replication_type = "LRS" + account_kind = "FileStorage" +} + +resource "azurerm_storage_share" "FSShare" { + name = "fslogix" + storage_account_name = azurerm_storage_account.storage.name + depends_on = [azurerm_storage_account.storage] +} + +## Azure built-in roles +## https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles +data "azurerm_role_definition" "storage_role" { + name = "Storage File Data SMB Share Contributor" +} + +resource "azurerm_role_assignment" "af_role" { + scope = azurerm_storage_account.storage.id + role_definition_id = data.azurerm_role_definition.storage_role.id + principal_id = azuread_group.aad_group.id +} diff --git a/quickstart/101-azure-virtual-desktop/defaults.tfvars b/quickstart/101-azure-virtual-desktop/defaults.tfvars new file mode 100644 index 00000000..228003aa --- /dev/null +++ b/quickstart/101-azure-virtual-desktop/defaults.tfvars @@ -0,0 +1,20 @@ +# Customized the sample values below for your environment and either rename to terraform.tfvars or env.auto.tfvars + +deploy_location = "west europe" +rg_name = "avd-resources-rg" +prefix = "avdtf" +local_admin_username = "localadm" +local_admin_password = "ChangeMe123$" +vnet_range = ["10.1.0.0/16"] +subnet_range = ["10.1.0.0/24"] +dns_servers = ["10.0.1.4", "168.63.129.16"] +aad_group_name = "AVDUsers" +domain_name = "infra.local" +domain_user_upn = "admin" # do not include domain name as this is appended +domain_password = "ChangeMe123!" +ad_vnet = "infra-network" +ad_rg = "infra-rg" +avd_users = [ + "avduser01@infra.local", + "avduser01@infra.local" +] diff --git a/quickstart/101-azure-virtual-desktop/host.tf b/quickstart/101-azure-virtual-desktop/host.tf new file mode 100644 index 00000000..aa3285ff --- /dev/null +++ b/quickstart/101-azure-virtual-desktop/host.tf @@ -0,0 +1,126 @@ +locals { + registration_token = azurerm_virtual_desktop_host_pool.hostpool.registration_info[0].token +} + +resource "random_string" "AVD_local_password" { + count = var.rdsh_count + length = 16 + special = true + min_special = 2 + override_special = "*!@#?" +} + +resource "azurerm_network_interface" "avd_vm_nic" { + count = var.rdsh_count + name = "${var.prefix}-${count.index + 1}-nic" + resource_group_name = var.rg_name + location = var.deploy_location + + ip_configuration { + name = "nic${count.index + 1}_config" + subnet_id = azurerm_subnet.subnet.id + private_ip_address_allocation = "dynamic" + } + + depends_on = [ + azurerm_resource_group.rg + ] +} + +resource "azurerm_windows_virtual_machine" "avd_vm" { + count = var.rdsh_count + name = "${var.prefix}-${count.index + 1}" + resource_group_name = var.rg_name + location = var.deploy_location + size = var.vm_size + network_interface_ids = ["${azurerm_network_interface.avd_vm_nic.*.id[count.index]}"] + provision_vm_agent = true + admin_username = var.local_admin_username + admin_password = var.local_admin_password + + os_disk { + name = "${lower(var.prefix)}-${count.index + 1}" + caching = "ReadWrite" + storage_account_type = "Standard_LRS" + } + + source_image_reference { + publisher = "MicrosoftWindowsDesktop" + offer = "Windows-10" + sku = "20h2-evd" + version = "latest" + } + + depends_on = [ + azurerm_resource_group.rg, + azurerm_network_interface.avd_vm_nic + ] +} + +resource "azurerm_virtual_machine_extension" "domain_join" { + count = var.rdsh_count + name = "${var.prefix}-${count.index + 1}-domainJoin" + virtual_machine_id = azurerm_windows_virtual_machine.avd_vm.*.id[count.index] + publisher = "Microsoft.Compute" + type = "JsonADDomainExtension" + type_handler_version = "1.3" + auto_upgrade_minor_version = true + + settings = <.com", + "user2@.com" +] diff --git a/quickstart/101-azure-virtual-desktop/options/netapp/netappstorage.tf b/quickstart/101-azure-virtual-desktop/options/netapp/netappstorage.tf new file mode 100644 index 00000000..4bd63341 --- /dev/null +++ b/quickstart/101-azure-virtual-desktop/options/netapp/netappstorage.tf @@ -0,0 +1,67 @@ +resource "azurerm_subnet" "netapp_subnet" { + name = var.netapp_subnet_name + resource_group_name = var.rg_name + virtual_network_name = azurerm_virtual_network.vnet.name + address_prefixes = var.netapp_address + + delegation { + name = "NetAppdelegation" + + service_delegation { + name = "Microsoft.Netapp/volumes" + } + } +} + +resource "azurerm_netapp_account" "netapp_acct" { + name = var.netapp_acct_name + resource_group_name = var.rg_name + location = var.deploy_location + + active_directory { + username = var.domain_user_upn + password = var.domain_password + smb_server_name = var.netapp_smb_name + dns_servers = var.dns_servers + domain = var.domain_name + organizational_unit = var.ou_path + } + + depends_on = [ + azurerm_resource_group.rg + ] +} + +resource "azurerm_netapp_pool" "netapp_pool" { + name = var.netapp_pool_name + location = var.deploy_location + resource_group_name = var.rg_name + account_name = var.netapp_acct_name + service_level = "Standard" + size_in_tb = 4 + + depends_on = [ + azurerm_resource_group.rg, azurerm_netapp_account.netapp_acct + ] +} + +resource "azurerm_netapp_volume" "NetApp_Vol" { + lifecycle { + prevent_destroy = true + } + + name = var.netapp_volume_name + location = var.deploy_location + resource_group_name = var.rg_name + account_name = var.netapp_acct_name + pool_name = var.netapp_pool_name + volume_path = var.netapp_volume_path + service_level = "Standard" + subnet_id = azurerm_subnet.netapp_subnet.id + protocols = ["CIFS"] + storage_quota_in_gb = 100 + + depends_on = [ + azurerm_netapp_pool.netapp_pool + ] +} diff --git a/quickstart/101-azure-virtual-desktop/options/netapp/variables.tf b/quickstart/101-azure-virtual-desktop/options/netapp/variables.tf new file mode 100644 index 00000000..f9bc290e --- /dev/null +++ b/quickstart/101-azure-virtual-desktop/options/netapp/variables.tf @@ -0,0 +1,122 @@ +variable "rg_name" { + type = string + default = "AVD-TF" + description = "Name of the Resource group in which to deploy these resources" +} + +variable "deploy_location" { + type = string + description = "The Azure Region in which all resources in this example should be created." +} + +variable "workspace" { + description = "Name of the Azure Virtual Desktop workspace" + default = "AVD TF Workspace" +} + +variable "hostpool" { + description = "Name of the Azure Virtual Desktop host pool" + default = "AVD-TF-HP" +} + +variable "ad_vnet" { + type = string + description = "Name of domain controller vnet" +} + +variable "dns_servers" { + description = "Custom DNS configuration" +} + +variable "vnet_range" { + description = "Address range for deployment VNet" +} +variable "subnet_range" { + description = "Address range for session host subnet" +} + +variable "ad_rg" { + type = string + description = "The resource group for AD VM" +} + +variable "avd_users" { + description = "AVD users" + default = [] +} + +variable "aad_group_name" { + description = "Azure Active Directory Group for AVD users" +} + +variable "rdsh_count" { + description = "Number of AVD machines to deploy" + default = 2 +} + +variable "prefix" { + description = "Prefix of the name of the AVD machine(s)" +} + +variable "domain_name" { + type = string + description = "Name of the domain to join" +} + +variable "domain_user_upn" { + type = string + description = "Username for domain join (do not include domain name as this is appended)" +} + +variable "domain_password" { + type = string + description = "Password of the user to authenticate with the domain" +} + +variable "vm_size" { + description = "Size of the machine to deploy" + default = "Standard_DS2_v2" +} + +variable "ou_path" { + default = "" +} + +variable "local_admin_username" { + type = string + description = "local admin username" +} + +variable "local_admin_password" { + description = "local admin password" +} + +# optional section - only use if deploying ANF + +variable "netapp_acct_name" { + default = "AVD_NetApp" +} + +variable "netapp_pool_name" { + default = "AVD_NetApp_pool" +} + +variable "netapp_volume_name" { + default = "AVD_NetApp_volume" +} + +variable "netapp_smb_name" { + default = "AVDNetApp" +} + +variable "netapp_volume_path" { + default = "AVDNetAppVolume" +} + +variable "netapp_subnet_name" { + default = "NetAppSubnet" +} + +variable "netapp_address" { + description = "Address range for NetApp Subnet" +} diff --git a/quickstart/101-azure-virtual-desktop/outputs.tf b/quickstart/101-azure-virtual-desktop/outputs.tf new file mode 100644 index 00000000..ec1f9624 --- /dev/null +++ b/quickstart/101-azure-virtual-desktop/outputs.tf @@ -0,0 +1,39 @@ +output "resource_group_name" { + description = "Name of the Resource group created" + value = azurerm_resource_group.rg.name +} + +output "location" { + description = "The Azure region" + value = azurerm_resource_group.rg.location +} + +output "storage_account_share" { + description = "Name of the Azure File Share created for FSLogix" + value = azurerm_storage_share.FSShare.name +} + +output "rdshcount" { + description = "The number of VMs created" + value = var.rdsh_count +} + +output "dnsservers" { + description = "Custom DNS configuration" + value = azurerm_virtual_network.vnet.dns_servers +} + +output "vnetrange" { + description = "Address range for deployment vnet" + value = azurerm_virtual_network.vnet.address_space + +} +output "avdusers" { + description = "AVD users" + value = azuread_group.aad_group.members +} + +output "aadgroupname" { + description = "Azure Active Directory Group for AVD users" + value = azuread_group.aad_group.display_name +} diff --git a/quickstart/101-azure-virtual-desktop/provider.tf b/quickstart/101-azure-virtual-desktop/provider.tf new file mode 100644 index 00000000..185ac1fa --- /dev/null +++ b/quickstart/101-azure-virtual-desktop/provider.tf @@ -0,0 +1,15 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~>2.0" + } + azuread = { + source = "hashicorp/azuread" + } + } +} + +provider "azurerm" { + features {} +} diff --git a/quickstart/101-azure-virtual-desktop/rbac.tf b/quickstart/101-azure-virtual-desktop/rbac.tf new file mode 100644 index 00000000..7da8669d --- /dev/null +++ b/quickstart/101-azure-virtual-desktop/rbac.tf @@ -0,0 +1,25 @@ +data "azuread_user" "aad_user" { + for_each = toset(var.avd_users) + user_principal_name = format("%s", each.key) +} + +data "azurerm_role_definition" "role" { # access an existing built-in role + name = "Desktop Virtualization User" +} + +resource "azuread_group" "aad_group" { + display_name = var.aad_group_name + security_enabled = true +} + +resource "azuread_group_member" "aad_group_member" { + for_each = data.azuread_user.aad_user + group_object_id = azuread_group.aad_group.id + member_object_id = each.value["id"] +} + +resource "azurerm_role_assignment" "role" { + scope = azurerm_virtual_desktop_application_group.dag.id + role_definition_id = data.azurerm_role_definition.role.id + principal_id = azuread_group.aad_group.id +} diff --git a/quickstart/101-azure-virtual-desktop/sig.tf b/quickstart/101-azure-virtual-desktop/sig.tf new file mode 100644 index 00000000..9ec2d2f3 --- /dev/null +++ b/quickstart/101-azure-virtual-desktop/sig.tf @@ -0,0 +1,35 @@ +resource "azurerm_resource_group" "sigrg" { + location = var.deploy_location + name = "${var.prefix}-rg" +} + +# Creates Shared Image Gallery +# https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/shared_image_gallery +resource "azurerm_shared_image_gallery" "sig" { + name = "AVDTFsig" + resource_group_name = azurerm_resource_group.rg.name + location = azurerm_resource_group.rg.location + description = "Shared images" + + tags = { + Environment = "Demo" + Tech = "Terraform" + } +} + +#Creates image definition +# https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/shared_image +resource "azurerm_shared_image" "example" { + name = "avd-image" + gallery_name = azurerm_shared_image_gallery.sig.name + resource_group_name = azurerm_resource_group.rg.name + location = azurerm_resource_group.rg.location + os_type = "Windows" + + identifier { + publisher = "MicrosoftWindowsDesktop" + offer = "office-365" + sku = "20h2-evd-o365pp" + } +} + diff --git a/quickstart/101-azure-virtual-desktop/variables.tf b/quickstart/101-azure-virtual-desktop/variables.tf new file mode 100644 index 00000000..69a769cb --- /dev/null +++ b/quickstart/101-azure-virtual-desktop/variables.tf @@ -0,0 +1,101 @@ +variable "rg_name" { + type = string + default = "AVD-TF" + description = "Name of the Resource group in which to deploy these resources" +} + +variable "deploy_location" { + type = string + description = "The Azure Region in which all resources in this example should be created." +} + +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 "ad_vnet" { + type = string + description = "Name of domain controller vnet" +} + +variable "dns_servers" { + type = list(string) + description = "Custom DNS configuration" +} + +variable "vnet_range" { + type = list(string) + description = "Address range for deployment VNet" +} +variable "subnet_range" { + type = list(string) + description = "Address range for session host subnet" +} + +variable "ad_rg" { + type = string + description = "The resource group for AD VM" +} + +variable "avd_users" { + description = "AVD users" + default = [] +} + +variable "aad_group_name" { + type = string + description = "Azure Active Directory Group for AVD users" +} + +variable "rdsh_count" { + description = "Number of AVD machines to deploy" + default = 2 +} + +variable "prefix" { + type = string + description = "Prefix of the name of the AVD machine(s)" +} + +variable "domain_name" { + type = string + description = "Name of the domain to join" +} + +variable "domain_user_upn" { + type = string + description = "Username for domain join (do not include domain name as this is appended)" +} + +variable "domain_password" { + type = string + description = "Password of the user to authenticate with the domain" + sensitive = true +} + +variable "vm_size" { + description = "Size of the machine to deploy" + default = "Standard_DS2_v2" +} + +variable "ou_path" { + default = "" +} + +variable "local_admin_username" { + type = string + description = "local admin username" +} + +variable "local_admin_password" { + description = "local admin password" + sensitive = true +} From dbcd0a7415657bcfd14273087576e9bfb9eed2ef Mon Sep 17 00:00:00 2001 From: Jen Sheerin Date: Mon, 3 Jan 2022 19:51:51 -0500 Subject: [PATCH 2/7] update readme --- .../101-azure-virtual-desktop/README.md | 41 ++----- quickstart/101-azure-virtual-desktop/USAGE.md | 102 ++++++++++++++++++ 2 files changed, 112 insertions(+), 31 deletions(-) create mode 100644 quickstart/101-azure-virtual-desktop/USAGE.md diff --git a/quickstart/101-azure-virtual-desktop/README.md b/quickstart/101-azure-virtual-desktop/README.md index 9098f388..71d89ffa 100644 --- a/quickstart/101-azure-virtual-desktop/README.md +++ b/quickstart/101-azure-virtual-desktop/README.md @@ -30,47 +30,26 @@ This directory contains the various components for building out Azure Virtual De * `afstorage.tf` deploys Azure Files storage for profiles and creates file share with RBAC permissions for the users group ([NTFS permissions will need to be configured](https://docs.microsoft.com/en-us/azure/virtual-desktop/create-file-share)) * `rbac.tf` - deploys rbac assignment for the users group + deploys rbac assignment for the users group * `variables.tf` Input variables +* `loganalytics.tf` + deploys log anaylytics workspace +* `sig.tf` + deploys log anaylytics workspace +* `random.tf` + Random provider configuration * `defaults.tfvars` declares the actual input values (keep security in mind if you are putting confidential data) * `provider.tf` - Azure RM and Azure AD provider configuation + Azure RM and Azure AD provider configuration * `outputs.tf` defines the outputs that will be displayed on deployment * `netappstorage.tf` as an alternate to Azure Files storage this deploys NetApp Files storage for profiles in a dedicated subnet (access needs to be granted to the ANF service) [Set up Azure NetApp Files](https://docs.microsoft.com/en-us/azure/azure-netapp-files/azure-netapp-files-quickstart-set-up-account-create-volumes?tabs=azure-portal) -## Varialble Inputs - -| Name | Description | Default | -|:---|:---|:---| -| `rg_name` | Name of the Resource Group in which to deploy these resources | `AVD-TF` | -| `deploy_location` | Region in which to deploy these resources | - | -| `hostpool` | Name of the Azure Virtual Desktop host pool | `AVD-TF-HP` | -| `ad_vnet` | Name of domain controller VNet | - | -| `dns_servers` | Custom DNS configuration | - | -| `vnet_range` | Address range for deployment VNet | - | -| `subnet_range` | Address range for session host subnet | - | -| `avd_users` | The resource group for AD VM | `[]` | -| `aad_group_name` | Azure Active Directory Group for AVD users | - | -| `rdsh_count` | Number of AVD machines to deploy | 2 | -| `prefix` | Prefix of the name of the AVD machine(s) | - | -| `domain_name` | Name of the domain to join | - | -| `domain_user_upn` | Username for domain join (do not include domain name as this is appended | - | -| `domain_password` | Password of the user to authenticate with the domain | - | -| `vm_size` | Size of the machine to deploy | `Standard_DS2_v2` | -| `ou_path` | The ou path for AD | `""` | -| `local_admin_username` | The local admin username for the VM | - | -| `local_admin_password` | The local admin password for the VM | - | -| `netapp_acct_name` | The NetApp account name | `AVD_NetApp` | -| `netapp_pool_name` | The NetApp pool name | `AVD_NetApp_pool` | -| `netapp_volume_name` | The NetApp volume name | `AVD_NetApp_volume` | -| `netapp_smb_name` | The NetApp smb name | `AVDNetApp` | -| `netapp_volume_path` | The NetApp volume path | `AVDNetAppVolume` | -| `netapp_subnet_name` | The NetApp subnet name | `NetAppSubnet` | -| `netapp_address` | The Address range for NetApp Subnet | - | +## Variable Inputs +[Variable Inputs](https://github.com/jensheerin/AVD-Terraform/blob/main/USAGE.md#inputs) ## Deploy If you’ve not previously setup terraform, check out this article to get it installed [Quickstart - Configure Terraform using Azure Cloud Shell](https://docs.microsoft.com/en-us/azure/developer/terraform/get-started-cloud-shell) diff --git a/quickstart/101-azure-virtual-desktop/USAGE.md b/quickstart/101-azure-virtual-desktop/USAGE.md new file mode 100644 index 00000000..436527e7 --- /dev/null +++ b/quickstart/101-azure-virtual-desktop/USAGE.md @@ -0,0 +1,102 @@ +# Usage + + +## Requirements + +| Name | Version | +|------|---------| +| [azurerm](#requirement\_azurerm) | ~>2.0 | + +## Providers + +| Name | Version | +|------|---------| +| [azuread](#provider\_azuread) | n/a | +| [azurerm](#provider\_azurerm) | ~>2.0 | +| [random](#provider\_random) | n/a | +| [time](#provider\_time) | n/a | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [azuread_group.aad_group](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/resources/group) | resource | +| [azuread_group_member.aad_group_member](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/resources/group_member) | resource | +| [azurerm_log_analytics_workspace.law](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/log_analytics_workspace) | resource | +| [azurerm_network_interface.avd_vm_nic](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_interface) | resource | +| [azurerm_network_security_group.nsg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_security_group) | resource | +| [azurerm_resource_group.log](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) | resource | +| [azurerm_resource_group.rg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) | resource | +| [azurerm_resource_group.rg_storage](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) | resource | +| [azurerm_resource_group.sigrg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) | resource | +| [azurerm_role_assignment.af_role](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource | +| [azurerm_role_assignment.role](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource | +| [azurerm_shared_image.example](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/shared_image) | resource | +| [azurerm_shared_image_gallery.sig](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/shared_image_gallery) | resource | +| [azurerm_storage_account.storage](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_account) | resource | +| [azurerm_storage_share.FSShare](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_share) | resource | +| [azurerm_subnet.subnet](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet) | resource | +| [azurerm_subnet_network_security_group_association.nsg_assoc](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet_network_security_group_association) | resource | +| [azurerm_virtual_desktop_application_group.dag](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_desktop_application_group) | resource | +| [azurerm_virtual_desktop_host_pool.hostpool](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_desktop_host_pool) | resource | +| [azurerm_virtual_desktop_workspace.workspace](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_desktop_workspace) | resource | +| [azurerm_virtual_desktop_workspace_application_group_association.ws-dag](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_desktop_workspace_application_group_association) | resource | +| [azurerm_virtual_machine_extension.domain_join](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_machine_extension) | resource | +| [azurerm_virtual_machine_extension.vmext_dsc](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_machine_extension) | resource | +| [azurerm_virtual_network.vnet](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_network) | resource | +| [azurerm_virtual_network_peering.peer1](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_network_peering) | resource | +| [azurerm_virtual_network_peering.peer2](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_network_peering) | resource | +| [azurerm_windows_virtual_machine.avd_vm](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/windows_virtual_machine) | resource | +| [random_string.AVD_local_password](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string) | resource | +| [random_string.random](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string) | resource | +| [time_rotating.avd_token](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/rotating) | resource | +| [azuread_user.aad_user](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/data-sources/user) | data source | +| [azurerm_role_definition.role](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/role_definition) | data source | +| [azurerm_role_definition.storage_role](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/role_definition) | data source | +| [azurerm_virtual_network.ad_vnet_data](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/virtual_network) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [aad\_group\_name](#input\_aad\_group\_name) | Azure Active Directory Group for AVD users | `string` | n/a | yes | +| [ad\_rg](#input\_ad\_rg) | The resource group for AD VM | `string` | n/a | yes | +| [ad\_vnet](#input\_ad\_vnet) | Name of domain controller vnet | `string` | n/a | yes | +| [avd\_users](#input\_avd\_users) | AVD users | `list` | `[]` | no | +| [deploy\_location](#input\_deploy\_location) | The Azure Region in which all resources in this example should be created. | `string` | n/a | yes | +| [dns\_servers](#input\_dns\_servers) | Custom DNS configuration | `list(string)` | n/a | yes | +| [domain\_name](#input\_domain\_name) | Name of the domain to join | `string` | n/a | yes | +| [domain\_password](#input\_domain\_password) | Password of the user to authenticate with the domain | `string` | n/a | yes | +| [domain\_user\_upn](#input\_domain\_user\_upn) | Username for domain join (do not include domain name as this is appended) | `string` | n/a | yes | +| [hostpool](#input\_hostpool) | Name of the Azure Virtual Desktop host pool | `string` | `"AVD-TF-HP"` | no | +| [local\_admin\_password](#input\_local\_admin\_password) | local admin password | `any` | n/a | yes | +| [local\_admin\_username](#input\_local\_admin\_username) | local admin username | `string` | n/a | yes | +| [ou\_path](#input\_ou\_path) | n/a | `string` | `""` | no | +| [prefix](#input\_prefix) | Prefix of the name of the AVD machine(s) | `string` | n/a | yes | +| [rdsh\_count](#input\_rdsh\_count) | Number of AVD machines to deploy | `number` | `2` | no | +| [rg\_name](#input\_rg\_name) | Name of the Resource group in which to deploy these resources | `string` | `"AVD-TF"` | no | +| [shared](#input\_shared) | Prefix of the name of the AVD machine(s) | `string` | n/a | yes | +| [subnet\_range](#input\_subnet\_range) | Address range for session host subnet | `list(string)` | n/a | yes | +| [vm\_size](#input\_vm\_size) | Size of the machine to deploy | `string` | `"Standard_DS2_v2"` | no | +| [vnet\_range](#input\_vnet\_range) | Address range for deployment VNet | `list(string)` | n/a | yes | +| [workspace](#input\_workspace) | Name of the Azure Virtual Desktop workspace | `string` | `"AVD TF Workspace"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [aadgroupname](#output\_aadgroupname) | Azure Active Directory Group for AVD users | +| [avdusers](#output\_avdusers) | AVD users | +| [dnsservers](#output\_dnsservers) | Custom DNS configuration | +| [location](#output\_location) | The Azure region | +| [rdshcount](#output\_rdshcount) | The number of VMs created | +| [resource\_group\_name](#output\_resource\_group\_name) | Name of the Resource group created | +| [storage\_account\_share](#output\_storage\_account\_share) | Name of the Azure File Share created for FSLogix | +| [vnetrange](#output\_vnetrange) | Address range for deployment vnet | + + + From 95c7436033cebe08fdd92f30371f8d1ae6d90a79 Mon Sep 17 00:00:00 2001 From: Jen Sheerin Date: Mon, 3 Jan 2022 19:54:16 -0500 Subject: [PATCH 3/7] update link --- quickstart/101-azure-virtual-desktop/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickstart/101-azure-virtual-desktop/README.md b/quickstart/101-azure-virtual-desktop/README.md index 71d89ffa..7326d00b 100644 --- a/quickstart/101-azure-virtual-desktop/README.md +++ b/quickstart/101-azure-virtual-desktop/README.md @@ -49,7 +49,7 @@ This directory contains the various components for building out Azure Virtual De as an alternate to Azure Files storage this deploys NetApp Files storage for profiles in a dedicated subnet (access needs to be granted to the ANF service) [Set up Azure NetApp Files](https://docs.microsoft.com/en-us/azure/azure-netapp-files/azure-netapp-files-quickstart-set-up-account-create-volumes?tabs=azure-portal) ## Variable Inputs -[Variable Inputs](https://github.com/jensheerin/AVD-Terraform/blob/main/USAGE.md#inputs) +[Variable Inputs](../USAGE.md#inputs) ## Deploy If you’ve not previously setup terraform, check out this article to get it installed [Quickstart - Configure Terraform using Azure Cloud Shell](https://docs.microsoft.com/en-us/azure/developer/terraform/get-started-cloud-shell) From b49da51665bc3c53196512a1be200408f77e2a64 Mon Sep 17 00:00:00 2001 From: Jen Sheerin Date: Sun, 6 Feb 2022 23:51:32 -0500 Subject: [PATCH 4/7] new folder for anf option, edits to variables --- .gitignore | 12 ++ .../101-azure-virtual-desktop-anf/README.md | 125 +++++++++++++++++ .../101-azure-virtual-desktop-anf/USAGE.md | 102 ++++++++++++++ .../environments/sample.tfvars | 21 +++ .../101-azure-virtual-desktop-anf/host.tf | 126 ++++++++++++++++++ .../loganalytics.tf | 14 ++ .../101-azure-virtual-desktop-anf/main.tf | 54 ++++++++ .../netappstorage.tf | 2 + .../networking.tf | 57 ++++++++ .../101-azure-virtual-desktop-anf/outputs.tf | 39 ++++++ .../101-azure-virtual-desktop-anf/provider.tf | 15 +++ .../101-azure-virtual-desktop-anf/rbac.tf | 25 ++++ .../101-azure-virtual-desktop-anf/sig.tf | 35 +++++ .../variables.tf | 33 ++++- .../101-azure-virtual-desktop/README.md | 102 +++++++------- .../sample.tfvars} | 0 .../options/netapp/defaults.tfvars | 16 --- .../101-azure-virtual-desktop/variables.tf | 21 ++- 18 files changed, 730 insertions(+), 69 deletions(-) create mode 100644 .gitignore create mode 100644 quickstart/101-azure-virtual-desktop-anf/README.md create mode 100644 quickstart/101-azure-virtual-desktop-anf/USAGE.md create mode 100644 quickstart/101-azure-virtual-desktop-anf/environments/sample.tfvars create mode 100644 quickstart/101-azure-virtual-desktop-anf/host.tf create mode 100644 quickstart/101-azure-virtual-desktop-anf/loganalytics.tf create mode 100644 quickstart/101-azure-virtual-desktop-anf/main.tf rename quickstart/{101-azure-virtual-desktop/options/netapp => 101-azure-virtual-desktop-anf}/netappstorage.tf (83%) create mode 100644 quickstart/101-azure-virtual-desktop-anf/networking.tf create mode 100644 quickstart/101-azure-virtual-desktop-anf/outputs.tf create mode 100644 quickstart/101-azure-virtual-desktop-anf/provider.tf create mode 100644 quickstart/101-azure-virtual-desktop-anf/rbac.tf create mode 100644 quickstart/101-azure-virtual-desktop-anf/sig.tf rename quickstart/{101-azure-virtual-desktop/options/netapp => 101-azure-virtual-desktop-anf}/variables.tf (74%) rename quickstart/101-azure-virtual-desktop/{defaults.tfvars => environments/sample.tfvars} (100%) delete mode 100644 quickstart/101-azure-virtual-desktop/options/netapp/defaults.tfvars diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..6953e0fd --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +log/ +obj/ +_site/ +.optemp/ +_themes*/ +_repo.*/ +.vs/ +.vscode/ +.idea +.ionide/ +.openpublishing.buildcore.ps1.vscode/ +*.DS_Store \ No newline at end of file diff --git a/quickstart/101-azure-virtual-desktop-anf/README.md b/quickstart/101-azure-virtual-desktop-anf/README.md new file mode 100644 index 00000000..52452d7f --- /dev/null +++ b/quickstart/101-azure-virtual-desktop-anf/README.md @@ -0,0 +1,125 @@ +## Terraform for Azure Virtual Desktop + +The purpose of this repository is to demonstrate using Terraform to deploy a simple Azure Virtual Desktop environment. For Classic Azure Virtual Desktop click [here](https://github.com/Azure/RDS-Templates/tree/master/wvd-sh/terraform-azurerm-windowsvirtualdesktop). + +## Requirements and limitations + +* Ensure that you meet the [requirements for Azure Virtual Desktop](https://docs.microsoft.com/en-us/azure/virtual-desktop/overview#requirements) +* Terraform must be installed and configured as outlined [here](https://docs.microsoft.com/en-us/azure/developer/terraform/get-started-cloud-shell) +* Active Directory already in place in this example, we are using AD in it’s own VNet. +* Users in AAD that will be given access to AVD +* This demo does not support Azure ADDS only deployment +* Destroy could produce errors deleting subnet due to resources associated. Manually delete resources within the subnet before running destroy + +## Components + +* Azure Virtual Desktop Environment +* Networking Infrastructure +* Session Hosts +* Profile Storage +* Role Based Access Control + +## Features + +This directory contains the various components for building out Azure Virtual Desktop. + +* `main.tf` + deploys a new workspace, hostpool, application group with associations +* `networking.tf` + deploys a new vnet, subnet, nsg and peering to AD vnet +* `host.tf` + deploys new session host from the marketplace build and join to domain +* `afstorage.tf` + deploys Azure Files storage for profiles and creates file share with RBAC permissions for the users group ([NTFS permissions will need to be configured](https://docs.microsoft.com/en-us/azure/virtual-desktop/create-file-share)) +* `rbac.tf` + deploys rbac assignment for the users group +* `variables.tf` + Input variables +* `loganalytics.tf` + deploys log anaylytics workspace +* `sig.tf` + deploys log anaylytics workspace +* `random.tf` + Random provider configuration +* `defaults.tfvars` + declares the actual input values (keep security in mind if you are putting confidential data) +* `provider.tf` + Azure RM and Azure AD provider configuration +* `outputs.tf` + defines the outputs that will be displayed on deployment +* `netappstorage.tf` + as an alternate to Azure Files storage this deploys NetApp Files storage for profiles in a dedicated subnet (access needs to be granted to the ANF service) [Set up Azure NetApp Files](https://docs.microsoft.com/en-us/azure/azure-netapp-files/azure-netapp-files-quickstart-set-up-account-create-volumes?tabs=azure-portal) + +## Variable Inputs + +[Variable Inputs](../USAGE.md#inputs) + +## Deploy + +If you’ve not previously setup terraform, check out this article to get it installed [Quickstart - Configure Terraform using Azure Cloud Shell](https://docs.microsoft.com/en-us/azure/developer/terraform/get-started-cloud-shell) + +You can review our sample configuration video here + +Once Terraform is setup and you have created your Terraform templates, the first step is to initialize Terraform. This step ensures that Terraform has all the prerequisites to build your template in Azure. + +``` +terraform init +``` + +The next step is to have Terraform review and validate the template. An execution plan is generated and stored in the file specified by the -out parameter. + +We also need to pass our variable definitions file during the plan. We can either load it automatically by renaming env.tfvars as terraform.tfvars OR env.auto.tfvars, in which case we will use the following to create the execution plan: + +```bash +terraform plan -out terraform_azure.tfplan +``` + +When you're ready to build the infrastructure in Azure, apply the execution plan: + +```bash +terraform apply terraform_azure.tfplan +``` + +## Final Configuration + +You’ll notice we didn’t actually configure the session hosts to use our profile storage at any point. There is an assumption that we are using GPO to manage FSLogix across our host pools as documented here: [Use FSLogix Group Policy Template Files - FSLogix](https://docs.microsoft.com/en-us/fslogix/use-group-policy-templates-ht). + +At a minimum you’ll need to configure the registry keys to enable FSLogix and configure the VHD Location to the NetApp Share URI: [Profile Container registry configuration settings - FSLogix](https://docs.microsoft.com/en-us/fslogix/profile-container-configuration-reference#enabled) + +## Troubleshooting Terraform deployment + +
+Click to expand +Terraform deployment can fail in two main categories: + +Issues with Terraform code + +1. [Issues with Desired State Configuration (DSC)](#issues-with-desired-state-configuration-dsc) +2. [Issues with Terraform code](#issues-with-desired-state-configuration-dsc) + +While it is rare to have issues with the Terraform code it is still possible, however most often errors are due to bad input in variables.tf. + +* If there are errors in the Terraform code, please file a GitHub issue. +* If there are warning in the Terraform code feel free to ignore or address for your own instance of that code. +* Using Terraform error messages it's a good starting point towards identifying issues with input variables + +### Issues with Desired State Configuration (DSC) + +To troubleshoot this type of issue, navigate to the Azure portal and if needed reset the password on the VM that failed DSC. Once you are able to log in to the VM review the log files in the following two folders: +
+ +## Additional References + +
+Click to expand + +* [Terraform Download](https://www.terraform.io/downloads.html) +* [Visual Code Download](https://code.visualstudio.com/Download) +* [Powershell VS Code Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.PowerShell) +* [HashiCorp Terraform VS Code Extension](https://marketplace.visualstudio.com/items?itemName=HashiCorp.terraform) +* [Azure Terraform VS Code Extension Name](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azureterraform) +* [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-windows?tabs=azure-cli) +* [Configure the Azure Terraform Visual Studio Code extension](https://docs.microsoft.com/en-us/azure/developer/terraform/configure-vs-code-extension-for-terraform) +* [Setup video](https://youtu.be/YmbmpGdhI6w) + +
diff --git a/quickstart/101-azure-virtual-desktop-anf/USAGE.md b/quickstart/101-azure-virtual-desktop-anf/USAGE.md new file mode 100644 index 00000000..436527e7 --- /dev/null +++ b/quickstart/101-azure-virtual-desktop-anf/USAGE.md @@ -0,0 +1,102 @@ +# Usage + + +## Requirements + +| Name | Version | +|------|---------| +| [azurerm](#requirement\_azurerm) | ~>2.0 | + +## Providers + +| Name | Version | +|------|---------| +| [azuread](#provider\_azuread) | n/a | +| [azurerm](#provider\_azurerm) | ~>2.0 | +| [random](#provider\_random) | n/a | +| [time](#provider\_time) | n/a | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [azuread_group.aad_group](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/resources/group) | resource | +| [azuread_group_member.aad_group_member](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/resources/group_member) | resource | +| [azurerm_log_analytics_workspace.law](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/log_analytics_workspace) | resource | +| [azurerm_network_interface.avd_vm_nic](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_interface) | resource | +| [azurerm_network_security_group.nsg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_security_group) | resource | +| [azurerm_resource_group.log](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) | resource | +| [azurerm_resource_group.rg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) | resource | +| [azurerm_resource_group.rg_storage](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) | resource | +| [azurerm_resource_group.sigrg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) | resource | +| [azurerm_role_assignment.af_role](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource | +| [azurerm_role_assignment.role](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource | +| [azurerm_shared_image.example](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/shared_image) | resource | +| [azurerm_shared_image_gallery.sig](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/shared_image_gallery) | resource | +| [azurerm_storage_account.storage](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_account) | resource | +| [azurerm_storage_share.FSShare](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_share) | resource | +| [azurerm_subnet.subnet](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet) | resource | +| [azurerm_subnet_network_security_group_association.nsg_assoc](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet_network_security_group_association) | resource | +| [azurerm_virtual_desktop_application_group.dag](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_desktop_application_group) | resource | +| [azurerm_virtual_desktop_host_pool.hostpool](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_desktop_host_pool) | resource | +| [azurerm_virtual_desktop_workspace.workspace](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_desktop_workspace) | resource | +| [azurerm_virtual_desktop_workspace_application_group_association.ws-dag](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_desktop_workspace_application_group_association) | resource | +| [azurerm_virtual_machine_extension.domain_join](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_machine_extension) | resource | +| [azurerm_virtual_machine_extension.vmext_dsc](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_machine_extension) | resource | +| [azurerm_virtual_network.vnet](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_network) | resource | +| [azurerm_virtual_network_peering.peer1](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_network_peering) | resource | +| [azurerm_virtual_network_peering.peer2](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_network_peering) | resource | +| [azurerm_windows_virtual_machine.avd_vm](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/windows_virtual_machine) | resource | +| [random_string.AVD_local_password](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string) | resource | +| [random_string.random](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string) | resource | +| [time_rotating.avd_token](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/rotating) | resource | +| [azuread_user.aad_user](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/data-sources/user) | data source | +| [azurerm_role_definition.role](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/role_definition) | data source | +| [azurerm_role_definition.storage_role](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/role_definition) | data source | +| [azurerm_virtual_network.ad_vnet_data](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/virtual_network) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [aad\_group\_name](#input\_aad\_group\_name) | Azure Active Directory Group for AVD users | `string` | n/a | yes | +| [ad\_rg](#input\_ad\_rg) | The resource group for AD VM | `string` | n/a | yes | +| [ad\_vnet](#input\_ad\_vnet) | Name of domain controller vnet | `string` | n/a | yes | +| [avd\_users](#input\_avd\_users) | AVD users | `list` | `[]` | no | +| [deploy\_location](#input\_deploy\_location) | The Azure Region in which all resources in this example should be created. | `string` | n/a | yes | +| [dns\_servers](#input\_dns\_servers) | Custom DNS configuration | `list(string)` | n/a | yes | +| [domain\_name](#input\_domain\_name) | Name of the domain to join | `string` | n/a | yes | +| [domain\_password](#input\_domain\_password) | Password of the user to authenticate with the domain | `string` | n/a | yes | +| [domain\_user\_upn](#input\_domain\_user\_upn) | Username for domain join (do not include domain name as this is appended) | `string` | n/a | yes | +| [hostpool](#input\_hostpool) | Name of the Azure Virtual Desktop host pool | `string` | `"AVD-TF-HP"` | no | +| [local\_admin\_password](#input\_local\_admin\_password) | local admin password | `any` | n/a | yes | +| [local\_admin\_username](#input\_local\_admin\_username) | local admin username | `string` | n/a | yes | +| [ou\_path](#input\_ou\_path) | n/a | `string` | `""` | no | +| [prefix](#input\_prefix) | Prefix of the name of the AVD machine(s) | `string` | n/a | yes | +| [rdsh\_count](#input\_rdsh\_count) | Number of AVD machines to deploy | `number` | `2` | no | +| [rg\_name](#input\_rg\_name) | Name of the Resource group in which to deploy these resources | `string` | `"AVD-TF"` | no | +| [shared](#input\_shared) | Prefix of the name of the AVD machine(s) | `string` | n/a | yes | +| [subnet\_range](#input\_subnet\_range) | Address range for session host subnet | `list(string)` | n/a | yes | +| [vm\_size](#input\_vm\_size) | Size of the machine to deploy | `string` | `"Standard_DS2_v2"` | no | +| [vnet\_range](#input\_vnet\_range) | Address range for deployment VNet | `list(string)` | n/a | yes | +| [workspace](#input\_workspace) | Name of the Azure Virtual Desktop workspace | `string` | `"AVD TF Workspace"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [aadgroupname](#output\_aadgroupname) | Azure Active Directory Group for AVD users | +| [avdusers](#output\_avdusers) | AVD users | +| [dnsservers](#output\_dnsservers) | Custom DNS configuration | +| [location](#output\_location) | The Azure region | +| [rdshcount](#output\_rdshcount) | The number of VMs created | +| [resource\_group\_name](#output\_resource\_group\_name) | Name of the Resource group created | +| [storage\_account\_share](#output\_storage\_account\_share) | Name of the Azure File Share created for FSLogix | +| [vnetrange](#output\_vnetrange) | Address range for deployment vnet | + + + diff --git a/quickstart/101-azure-virtual-desktop-anf/environments/sample.tfvars b/quickstart/101-azure-virtual-desktop-anf/environments/sample.tfvars new file mode 100644 index 00000000..f09c5c8d --- /dev/null +++ b/quickstart/101-azure-virtual-desktop-anf/environments/sample.tfvars @@ -0,0 +1,21 @@ +# Customized the sample values below for your environment and either rename to terraform.tfvars or env.auto.tfvars + +deploy_location = "west europe" +rg_name = "avd-resources-rg" +prefix = "avdtf" +local_admin_username = "localadm" +local_admin_password = "ChangeMe123$" +vnet_range = ["10.1.0.0/16"] +subnet_range = ["10.1.0.0/24"] +netapp_address = ["10.1.1.0/24"] +dns_servers = ["10.0.1.4", "168.63.129.16"] +aad_group_name = "AVDUsers" +domain_name = "infra.local" +domain_user_upn = "admin" # do not include domain name as this is appended +domain_password = "ChangeMe123!" +ad_vnet = "infra-network" +ad_rg = "infra-rg" +avd_users = [ + "avduser01@infra.local", + "avduser01@infra.local" +] diff --git a/quickstart/101-azure-virtual-desktop-anf/host.tf b/quickstart/101-azure-virtual-desktop-anf/host.tf new file mode 100644 index 00000000..aa3285ff --- /dev/null +++ b/quickstart/101-azure-virtual-desktop-anf/host.tf @@ -0,0 +1,126 @@ +locals { + registration_token = azurerm_virtual_desktop_host_pool.hostpool.registration_info[0].token +} + +resource "random_string" "AVD_local_password" { + count = var.rdsh_count + length = 16 + special = true + min_special = 2 + override_special = "*!@#?" +} + +resource "azurerm_network_interface" "avd_vm_nic" { + count = var.rdsh_count + name = "${var.prefix}-${count.index + 1}-nic" + resource_group_name = var.rg_name + location = var.deploy_location + + ip_configuration { + name = "nic${count.index + 1}_config" + subnet_id = azurerm_subnet.subnet.id + private_ip_address_allocation = "dynamic" + } + + depends_on = [ + azurerm_resource_group.rg + ] +} + +resource "azurerm_windows_virtual_machine" "avd_vm" { + count = var.rdsh_count + name = "${var.prefix}-${count.index + 1}" + resource_group_name = var.rg_name + location = var.deploy_location + size = var.vm_size + network_interface_ids = ["${azurerm_network_interface.avd_vm_nic.*.id[count.index]}"] + provision_vm_agent = true + admin_username = var.local_admin_username + admin_password = var.local_admin_password + + os_disk { + name = "${lower(var.prefix)}-${count.index + 1}" + caching = "ReadWrite" + storage_account_type = "Standard_LRS" + } + + source_image_reference { + publisher = "MicrosoftWindowsDesktop" + offer = "Windows-10" + sku = "20h2-evd" + version = "latest" + } + + depends_on = [ + azurerm_resource_group.rg, + azurerm_network_interface.avd_vm_nic + ] +} + +resource "azurerm_virtual_machine_extension" "domain_join" { + count = var.rdsh_count + name = "${var.prefix}-${count.index + 1}-domainJoin" + virtual_machine_id = azurerm_windows_virtual_machine.avd_vm.*.id[count.index] + publisher = "Microsoft.Compute" + type = "JsonADDomainExtension" + type_handler_version = "1.3" + auto_upgrade_minor_version = true + + settings = < Click to expand -Terraform deployment can fail in two main categories: +Terraform deployment can fail in two main categories: + +Issues with Terraform code -Issues with Terraform code 1. [Issues with Desired State Configuration (DSC)](#issues-with-desired-state-configuration-dsc) 2. [Issues with Terraform code](#issues-with-desired-state-configuration-dsc) - -While it is rare to have issues with the Terraform code it is still possible, however most often errors are due to bad input in variables.tf. -* If there are errors in the Terraform code, please file a GitHub issue. -* If there are warning in the Terraform code feel free to ignore or address for your own instance of that code. -* Using Terraform error messages it's a good starting point towards identifying issues with input variables - -### Issues with Desired State Configuration (DSC) +While it is rare to have issues with the Terraform code it is still possible, however most often errors are due to bad input in variables.tf. -To troubleshoot this type of issue, navigate to the Azure portal and if needed reset the password on the VM that failed DSC. Once you are able to log in to the VM review the log files in the following two folders: +* If there are errors in the Terraform code, please file a GitHub issue. +* If there are warning in the Terraform code feel free to ignore or address for your own instance of that code. +* Using Terraform error messages it's a good starting point towards identifying issues with input variables + +### Issues with Desired State Configuration (DSC) + +To troubleshoot this type of issue, navigate to the Azure portal and if needed reset the password on the VM that failed DSC. Once you are able to log in to the VM review the log files in the following two folders: ## Additional References +
Click to expand -- [Terraform Download](https://www.terraform.io/downloads.html) -- [Visual Code Download](https://code.visualstudio.com/Download) -- [Powershell VS Code Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.PowerShell) -- [HashiCorp Terraform VS Code Extension](https://marketplace.visualstudio.com/items?itemName=HashiCorp.terraform) -- [Azure Terraform VS Code Extension Name](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azureterraform) -- [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-windows?tabs=azure-cli) -- [Configure the Azure Terraform Visual Studio Code extension](https://docs.microsoft.com/en-us/azure/developer/terraform/configure-vs-code-extension-for-terraform) -- [Setup video](https://youtu.be/YmbmpGdhI6w) -
\ No newline at end of file +* [Terraform Download](https://www.terraform.io/downloads.html) +* [Visual Code Download](https://code.visualstudio.com/Download) +* [Powershell VS Code Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.PowerShell) +* [HashiCorp Terraform VS Code Extension](https://marketplace.visualstudio.com/items?itemName=HashiCorp.terraform) +* [Azure Terraform VS Code Extension Name](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azureterraform) +* [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-windows?tabs=azure-cli) +* [Configure the Azure Terraform Visual Studio Code extension](https://docs.microsoft.com/en-us/azure/developer/terraform/configure-vs-code-extension-for-terraform) +* [Setup video](https://youtu.be/YmbmpGdhI6w) + + diff --git a/quickstart/101-azure-virtual-desktop/defaults.tfvars b/quickstart/101-azure-virtual-desktop/environments/sample.tfvars similarity index 100% rename from quickstart/101-azure-virtual-desktop/defaults.tfvars rename to quickstart/101-azure-virtual-desktop/environments/sample.tfvars diff --git a/quickstart/101-azure-virtual-desktop/options/netapp/defaults.tfvars b/quickstart/101-azure-virtual-desktop/options/netapp/defaults.tfvars deleted file mode 100644 index 8729f531..00000000 --- a/quickstart/101-azure-virtual-desktop/options/netapp/defaults.tfvars +++ /dev/null @@ -1,16 +0,0 @@ -deploy_location = "west europe" -rg_name = "avd-resources-rg" -prefix = "avdtf" -local_admin_username = "localadm" -local_admin_password = "ChangeMe123$" -vnet_range = ["10.1.0.0/16"] -subnet_range = ["10.1.0.0/24"] -netapp_address = ["10.1.1.0/24"] -dns_servers = ["10.0.0.4", "168.63.129.16"] -aad_group_name = "AVDUserGroup" -ad_vnet = "" -ad_rg = "" -avd_users = [ - "user1@.com", - "user2@.com" -] diff --git a/quickstart/101-azure-virtual-desktop/variables.tf b/quickstart/101-azure-virtual-desktop/variables.tf index 69a769cb..4d4064ba 100644 --- a/quickstart/101-azure-virtual-desktop/variables.tf +++ b/quickstart/101-azure-virtual-desktop/variables.tf @@ -1,11 +1,12 @@ variable "rg_name" { type = string - default = "AVD-TF" + default = "avd-resources-rg" description = "Name of the Resource group in which to deploy these resources" } variable "deploy_location" { type = string + default = "east us" description = "The Azure Region in which all resources in this example should be created." } @@ -23,35 +24,44 @@ variable "hostpool" { variable "ad_vnet" { type = string + default = "infra-network" description = "Name of domain controller vnet" } variable "dns_servers" { type = list(string) + default = ["10.0.1.4", "168.63.129.16"] description = "Custom DNS configuration" } variable "vnet_range" { type = list(string) + default = ["10.1.0.0/16"] description = "Address range for deployment VNet" } variable "subnet_range" { type = list(string) + default = ["10.1.0.0/24"] description = "Address range for session host subnet" } variable "ad_rg" { type = string + default = "infra-rg" description = "The resource group for AD VM" } variable "avd_users" { description = "AVD users" - default = [] + default = [ + "avduser01@infra.local", + "avduser01@infra.local" + ] } variable "aad_group_name" { type = string + default = "AVDUsers" description = "Azure Active Directory Group for AVD users" } @@ -62,21 +72,25 @@ variable "rdsh_count" { variable "prefix" { type = string + default = "avdtf" description = "Prefix of the name of the AVD machine(s)" } variable "domain_name" { type = string + default = "infra.local" description = "Name of the domain to join" } variable "domain_user_upn" { type = string + default = "admin" # do not include domain name as this is appended description = "Username for domain join (do not include domain name as this is appended)" } variable "domain_password" { type = string + default = "ChangeMe123!" description = "Password of the user to authenticate with the domain" sensitive = true } @@ -92,10 +106,13 @@ variable "ou_path" { variable "local_admin_username" { type = string + default = "localadm" description = "local admin username" } variable "local_admin_password" { + type = string + default = "ChangeMe123!" description = "local admin password" sensitive = true } From f11c1958b6c8d99c9b513e69e33011050aadd004 Mon Sep 17 00:00:00 2001 From: Jen Sheerin <84478520+jensheerin@users.noreply.github.com> Date: Sun, 6 Feb 2022 23:55:15 -0500 Subject: [PATCH 5/7] Delete .vscode directory --- .vscode/settings.json | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index ed9462b7..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "markdownlint.config": { - "MD028": false, - "MD025": { - "front_matter_title": "" - } - } -} \ No newline at end of file From f8c986b4dcabcd385e48fd8bdc323c9a70fd5ffd Mon Sep 17 00:00:00 2001 From: Jen Sheerin Date: Sun, 6 Feb 2022 23:57:47 -0500 Subject: [PATCH 6/7] update readme --- quickstart/101-azure-virtual-desktop-anf/README.md | 2 -- quickstart/101-azure-virtual-desktop/README.md | 2 -- 2 files changed, 4 deletions(-) diff --git a/quickstart/101-azure-virtual-desktop-anf/README.md b/quickstart/101-azure-virtual-desktop-anf/README.md index 52452d7f..2cbc1d9c 100644 --- a/quickstart/101-azure-virtual-desktop-anf/README.md +++ b/quickstart/101-azure-virtual-desktop-anf/README.md @@ -29,8 +29,6 @@ This directory contains the various components for building out Azure Virtual De deploys a new vnet, subnet, nsg and peering to AD vnet * `host.tf` deploys new session host from the marketplace build and join to domain -* `afstorage.tf` - deploys Azure Files storage for profiles and creates file share with RBAC permissions for the users group ([NTFS permissions will need to be configured](https://docs.microsoft.com/en-us/azure/virtual-desktop/create-file-share)) * `rbac.tf` deploys rbac assignment for the users group * `variables.tf` diff --git a/quickstart/101-azure-virtual-desktop/README.md b/quickstart/101-azure-virtual-desktop/README.md index 52452d7f..3609143b 100644 --- a/quickstart/101-azure-virtual-desktop/README.md +++ b/quickstart/101-azure-virtual-desktop/README.md @@ -47,8 +47,6 @@ This directory contains the various components for building out Azure Virtual De Azure RM and Azure AD provider configuration * `outputs.tf` defines the outputs that will be displayed on deployment -* `netappstorage.tf` - as an alternate to Azure Files storage this deploys NetApp Files storage for profiles in a dedicated subnet (access needs to be granted to the ANF service) [Set up Azure NetApp Files](https://docs.microsoft.com/en-us/azure/azure-netapp-files/azure-netapp-files-quickstart-set-up-account-create-volumes?tabs=azure-portal) ## Variable Inputs From a69ec0bec04e30df9d54c7d529e9e5c274f55dab Mon Sep 17 00:00:00 2001 From: Jen Sheerin Date: Mon, 7 Feb 2022 09:36:11 -0500 Subject: [PATCH 7/7] fix broken link --- quickstart/101-azure-virtual-desktop-anf/README.md | 2 +- quickstart/101-azure-virtual-desktop/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/quickstart/101-azure-virtual-desktop-anf/README.md b/quickstart/101-azure-virtual-desktop-anf/README.md index 2cbc1d9c..cf8bdca3 100644 --- a/quickstart/101-azure-virtual-desktop-anf/README.md +++ b/quickstart/101-azure-virtual-desktop-anf/README.md @@ -50,7 +50,7 @@ This directory contains the various components for building out Azure Virtual De ## Variable Inputs -[Variable Inputs](../USAGE.md#inputs) +[Variable Inputs](USAGE.md#inputs) ## Deploy diff --git a/quickstart/101-azure-virtual-desktop/README.md b/quickstart/101-azure-virtual-desktop/README.md index 3609143b..2f45e18f 100644 --- a/quickstart/101-azure-virtual-desktop/README.md +++ b/quickstart/101-azure-virtual-desktop/README.md @@ -50,7 +50,7 @@ This directory contains the various components for building out Azure Virtual De ## Variable Inputs -[Variable Inputs](../USAGE.md#inputs) +[Variable Inputs](USAGE.md#inputs) ## Deploy