So you have an Azure Virtual Desktop environment and you need to check something on a session host. These machines don’t have a public ip address so you need a way of connecting to it on the private ip address.
You can use Azure Bastion and connect through the Azure portal or with the native client if you have a Bastion on the Standard sku. The other way to connect is through a VPN tunnel.
In this blog post I’ll describe the steps you need to create a P2S VPN tunnel with Terraform. I’m going to configure the VPN gateway to use a Certificate to authenticate. The script I use to generate the root and client certificate is from Wim Matthyssen. You can find his blog about it here.
Where does the VPN Gateway belong in your Azure environment?
In a typical Hub-Spoke virtual network environment you put the VPN Gateway in the Hub. In my example in the “rg-hub-jvn-networking-01” resource group.
I have a separate networking resource group for the AVD network that is peered with the hub to complete the hub-spoke topology. Don’t forget to make sure that you configure the peering between your hub and spoke correctly.
What resources to put in your Terraform file?
- Public IP for the VPN Gateway
- Diagnostic Settings for the Public IP
- VPN Gateway
I also use a couple of data blocks to import the following resources:
- Log Analytics Workspace for the diagnostic settings of the public ip
- Hub virtual network
- GatewaySubnet
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "=3.4.0"
}
}
}
provider "azurerm" {
features {}
}
provider "azurerm" {
features {}
alias = "hub"
subscription_id = var.subscription_id_mgmt
}
provider "azurerm" {
features {}
alias = "prod"
subscription_id = var.subscription_id_prd
}
provider "azurerm" {
features {}
alias = "identity"
subscription_id = var.subscription_id_identity
}
provider "azurerm" {
features {}
alias = "avd"
subscription_id = var.subscription_id_avd
}
data "azurerm_virtual_network" "hub" {
provider = azurerm.hub
name = "vnet-${var.env}-${var.prefix}-we-01"
resource_group_name = "rg-${var.env}-${var.prefix}-networking-01"
}
data "azurerm_log_analytics_workspace" "law" {
name = "law-${var.env}-${var.prefix}-01"
resource_group_name = "rg-${var.env}-${var.prefix}-management-01"
}
data "azurerm_subnet" "gateway" {
name = "GatewaySubnet"
resource_group_name = "rg-${var.env}-${var.prefix}-networking-01"
virtual_network_name = data.azurerm_virtual_network.hub.name
}
resource "azurerm_public_ip" "pip" {
name = "pip-${var.env}-${var.prefix}-vpng-01"
location = data.azurerm_virtual_network.hub.location
resource_group_name = data.azurerm_virtual_network.hub.resource_group_name
allocation_method = "Dynamic"
tags = {
"Critical" = "Yes"
"Solution" = "Public IP VPNG"
"Costcenter" = "It"
"Location" = "We"
}
}
resource "azurerm_monitor_diagnostic_setting" "vpng-pip-diag" {
provider = azurerm.hub
name = "diag-pip-${var.prefix}-vpng"
target_resource_id = azurerm_public_ip.pip.id
log_analytics_workspace_id = data.azurerm_log_analytics_workspace.law.id
log {
category = "DDoSProtectionNotifications"
enabled = true
retention_policy {
enabled = true
}
}
log {
category = "DDoSMitigationFlowLogs"
enabled = true
retention_policy {
enabled = true
}
}
log {
category = "DDoSMitigationReports"
enabled =true
}
metric {
category = "AllMetrics"
retention_policy {
enabled = true
}
}
}
resource "azurerm_virtual_network_gateway" "gateway" {
name = "vpng-${var.env}-${var.prefix}-01"
location = data.azurerm_virtual_network.hub.location
resource_group_name = data.azurerm_virtual_network.hub.resource_group_name
type = "Vpn"
vpn_type = "RouteBased"
active_active = false
enable_bgp = false
sku = "VpnGw1"
tags = {
"Critical" = "Yes"
"Solution" = "VPN Gateway"
"Costcenter" = "It"
"Location" = "We"
}
ip_configuration {
name = "vnetGatewayConfig"
public_ip_address_id = azurerm_public_ip.pip.id
private_ip_address_allocation = "Dynamic"
subnet_id = data.azurerm_subnet.gateway.id
}
vpn_client_configuration {
address_space = ["172.16.101.0/24"]
root_certificate {
name = "p2s-jvn-root-cert"
public_cert_data = <<EOF
Your cert goes here
EOF
}
}
}
P2S config
When the deployment is finished we can check the config of the P2S connection. To view this info go to your VPN Gateway and select Point-to-site configuration in the left blade. You can see that it has certificate selected as authentication type.
You can also see the root cert and the certificate information on the right.
How do you connect with the VPN Gateway?
To connect you can use the Azure VPN Client that you can download from the Microsoft store.
To get the correct VPN config you can download the xml file as you can see in below screenshot. You will get a zip with the name of your VPN Gateway. the file you need is in the Azure VPN folder. Click the + sign in the client and select import to import the xml file.
When everything is configured as it should you can connect to your VPN Gateway.
Connect to the AVD session hosts
Now that the VPN is working and the Hub-Spoke config is configured it’s possible to connect to the hosts with the private ip.
This concludes my blog post about how to deploy a P2S VPN connection to an AVD spoke virtual network.
I hope this blog post can help you and if you have any more questions feel free to contact me.
1 thought on “Configure a P2S VPN connection to your Azure Virtual Desktop Environment using Terraform”