Configure AVD traffic on Azure firewall with IP Groups and Terraform Part 1

Hi All,

You may have heard that Microsoft has announced that the default outbound internet access that Azure virtual machines, will end on 30 september 2025. The news can be read here.

What does this mean for the IT admin?

Until that date, your Azure virtual machines will be able to reach the internet by default. After that date, the IT admin will have to use other methods to make sure that outbound internet access is possible.

One of the most used methods to allow outbound internet access is using an Azure Firewall. In this blog post I’ll show you how to deploy an Azure Firewall with Terraform and route all traffic for a specific subnet to the Azure firewall using a user defined route. In part 2 I’ll show how to create the necessary rules for the core AVD traffic.

To streamline the rules this I’ll use an IP Group. An IP Group can help to manage the rules on the Azure Firewall especially if you have multiple subnets for your session hosts.

Let’s start looking at deploying the Azure firewall. In this blog post I’ll show how to deploy it in an Hub-Spoke network topology.

Before we begin, there are a couple of resources that we need to have in place:

  • subnet for session hosts
  • AzureFirewallSubnet in hub virtual network
  • AzureFirewallManagementSubnet in hub virtual network
  • Log Analytics Workspace for the diagnostic settings
  • Resource group for the networking resources
data "azurerm_subnet" "azfwsubnet"{
  name = "AzureFirewallSubnet"
  resource_group_name = data.azurerm_resource_group.rg-fw.name
  virtual_network_name = "vnet-hub-jvn-we-01"
}
data "azurerm_subnet" "azfwmgmtsubnet"{
  name = "AzureFirewallManagementSubnet"
  resource_group_name = data.azurerm_resource_group.rg-fw.name
  virtual_network_name = "vnet-hub-jvn-we-01"
}

data "azurerm_subnet" "avd-sessionhost"{
  name = "snet-prd-jvn-avd-shared-sessionhosts-01"
  resource_group_name = "rg-prd-jvn-avd-networking-01"
  virtual_network_name = "vnet-prd-jvn-avd-we-01"
}

This virtual network for AVD is peered with my hub virtual network.

The first resources that we need for the firewall are the 2 public ip’s.

resource "azurerm_public_ip" "pip-01-fw" {
  provider = azurerm.hub
  name                = "pip-01-fw-hub-jvn-01"
  location            = var.location
  resource_group_name = data.azurerm_resource_group.rg-fw.name
  allocation_method   = "Static"
  sku                 = "Standard"
  zones               = ["1", "2", "3"]
  tags = {
    "Location"   = "We"
    "Costcenter" = "IT"
    "Purpose"    = "Public IP"
  }
}
resource "azurerm_public_ip" "pip-02-fw" {
  provider = azurerm.hub
  name                = "pip-02-fw-hub-jvn-01"
  location            = var.location
  resource_group_name = data.azurerm_resource_group.rg-fw.name
  allocation_method   = "Static"
  sku                 = "Standard"
  zones               = ["1", "2", "3"]
  tags = {
    "Location"   = "We"
    "Costcenter" = "IT"
    "Purpose"    = "Public IP"
  }
}

Now that the public ip’s are created, we can shift our focus to the Azure Firewall.

resource "azurerm_firewall" "fw" {
  provider = azurerm.hub
  name = "fw-hub-jvn-01"
  resource_group_name = data.azurerm_resource_group.rg-fw.name
  location = var.location
  sku_tier = "Standard"
  sku_name = "AZFW_VNet"
  zones               = ["1", "2", "3"]
  dns_servers = ["10.1.1.244"]
  dns_proxy_enabled = true
  ip_configuration {
    name                 = "ipc-01-fw-hub-jvn-01"
    subnet_id            = data.azurerm_subnet.azfwsubnet.id
    public_ip_address_id = azurerm_public_ip.pip-01-fw.id
  }
  management_ip_configuration {
    name = "ipc-02-fw-hub-jvn-01"
    subnet_id = data.azurerm_subnet.azfwmgmtsubnet.id
    public_ip_address_id = azurerm_public_ip.pip-02-fw.id
  }
  tags = {
    "Location"   = "We"
    "Costcenter" = "IT"
    "Purpose"    = "Networking"
  }

}

When using the Azure firewall, we will overwrite the default routing from Microsoft. This means we need to create our own route. This is done with an Azure route table. In here we define that all traffic goes to the virtual appliance.

resource "azurerm_route_table" "avd-route" {
  name                          = "route-prd-jvn-avd-01"
  location                      = data.azurerm_resource_group.rg-fw.location
  resource_group_name           = data.azurerm_resource_group.rg-fw.name
  #bgp_route_propagation_enabledion = false
  route {
    name                   = "avd-traffic"
    address_prefix         = "0.0.0.0/0"
    next_hop_type          = "VirtualAppliance"
    next_hop_in_ip_address = azurerm_firewall.fw.ip_configuration[0].private_ip_address
  }
    tags = {
    "Location"   = "We"
    "Costcenter" = "IT"
    "Purpose"    = "AVD routing table"
  }
}

Now that the Azure firewall and route table are in place, we can create an IP group. An IP group is ideal to group certain subnets so it’s easier to create networking rules for the AVD traffic. The cidr’s are in this case the subnets for the AVD session hosts.

resource "azurerm_ip_group" "ip-group-avd" {
  name                = "ipg-prd-jvn-avd-01"
  location            = data.azurerm_resource_group.rg-fw.location
  resource_group_name = data.azurerm_resource_group.rg-fw.name

  cidrs = ["10.1.6.0", "10.1.6.96"]

  tags = {
    "Location"   = "We"
    "Costcenter" = "IT"
    "Purpose"    = "AVD IP Group"
  }
}

Now all the different resources are in place so we can start building the necessary firewall rules for the AVD traffic. I’ll show this in Part 2 of this series.

I hope you found this part 1 useful and see you in part 2.

Leave a Reply

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