Deploy an Azure NAT Gateway for the outbound Azure Virtual Desktop traffic with Terraform

By default Azure virtual machine have outbound internet access. You might have the requirement of having a public ip on your resource for outbound connectivity. To avoid having to assign public ip’s on virtual machines, you can choose to use an Azure NAT gateway. If you enable NAT gateway all the devices in the subnet that is associated with the NAT gateway will use the gateway’s public ip.

There are some things to consider when planning to use this feature. The NAT gateway is a zonal resource. If you don’t specify an zone, Azure will choose in what zone it will deploy the gateway. Also If the NAT Gateway goes down the VM’s won’t have outbound connectivity anymore.

For those who want to learn more about the NAT Gateway can check out the Lean page here.

In this blogpost I’ll focus on deploying a NAT gateway inside my AVD spoke network and assign it with my session hosts subnet.

The first I need are to import several Azure resources in the main.tf.

  • Log Analytics Workspace for the diagnostic settings
  • AVD virtual network
  • Session host subnet
data "azurerm_log_analytics_workspace" "law" {
  provider            = azurerm.hub
  name                = "law-${var.env}-${var.prefix}-01"
  resource_group_name = "rg-${var.env}-${var.prefix}-management-01"
}
data "azurerm_virtual_network" "avd" {
  provider            = azurerm.hub
  name                = "vnet-${var.spoke}-${var.prefix}-${var.solution}-we-01"
  resource_group_name = "rg-${var.spoke}-${var.prefix}-${var.solution}-networking-01"
}
data "azurerm_subnet" "avd-sessionhosts" {
  name                 = "snet-${var.spoke}-${var.prefix}-${var.solution}-session-hosts-01"
  virtual_network_name = data.azurerm_virtual_network.avd.name
  resource_group_name  = data.azurerm_virtual_network.avd.resource_group_name
}

The resources I’ll deploy for the NAT Gateway are the following:

  • Public IP for the NAT gateway
  • Public IP prefix
  • Nat gateway
  • Diagnostic settings
resource "azurerm_public_ip_prefix" "pippre" {
  name                = "pippre-${var.spoke}-${var.prefix}-${var.solution}-01"
  location            = data.azurerm_virtual_network.avd.location
  resource_group_name = data.azurerm_virtual_network.avd.resource_group_name
  prefix_length       = 30
  zones               = ["1"]
}
resource "azurerm_nat_gateway_public_ip_prefix_association" "natg-pippre" {
  nat_gateway_id      = azurerm_nat_gateway.natg.id
  public_ip_prefix_id = azurerm_public_ip_prefix.pippre.id
}

resource "azurerm_nat_gateway" "natg" {
  name                    = "natg-${var.spoke}-${var.prefix}-${var.solution}-01"
  location                = data.azurerm_virtual_network.avd.location
  resource_group_name     = data.azurerm_virtual_network.avd.resource_group_name
  sku_name                = "Standard"
  idle_timeout_in_minutes = 10
  zones                   = ["1"]
  tags = {
    "Critical"    = "Yes"
    "Solution"    = "Nat Gateway"
    "Costcenter"  = "It"
    "Location"    = "We"
    "Environment" = "AVD"
  }

}

Now that we have the NAT gateway, we need to associate the public ip, the public ip prefix and the subnet we want to use with the gateway.

resource "azurerm_nat_gateway_public_ip_prefix_association" "natg-pippre" {
  nat_gateway_id      = azurerm_nat_gateway.natg.id
  public_ip_prefix_id = azurerm_public_ip_prefix.pippre.id
}
resource "azurerm_nat_gateway_public_ip_association" "natg-pip-ass" {
  nat_gateway_id       = azurerm_nat_gateway.natg.id
  public_ip_address_id = azurerm_public_ip.pip-natg.id
}
resource "azurerm_subnet_nat_gateway_association" "nat-avd-sessionhosts" {
  subnet_id      = data.azurerm_subnet.avd-sessionhosts.id
  nat_gateway_id = azurerm_nat_gateway.natg.id
}

The last step is to activate the diagnostic settings for the public ip address. As destination I put the Log Analytics Workspace that is located in my Hub.

resource "azurerm_monitor_diagnostic_setting" "natg-pip-diag" {
  provider                   = azurerm.hub
  name                       = "diag-pip-${var.prefix}-natg"
  target_resource_id         = azurerm_public_ip.pip-natg.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
    }
  }

}

In the Azure portal you can also associate a subnet with the NAT Gateway.

You can also do this the other way and associate the NAT Gateway in the subnet blade.

After you assign the NAT gateway to the subnet all the outbound traffic will pas the gateway.

As usual the code can be found on my Github.

I hope this belogpost can help you to setup the NAT Gateway. If you have any questions about this blogpost feel free to contact me.

1 thought on “Deploy an Azure NAT Gateway for the outbound Azure Virtual Desktop traffic with Terraform

Leave a Reply

Your email address will not be published. Required fields are marked *