Thursday, 11 July 2024

Create an Azure Firewall and IP Groups - ARM template

 Create an Azure Firewall and IP Groups - ARM template

In this quickstart, you use an Azure Resource Manager template (ARM template) to deploy an Azure Firewall with sample IP Groups used in a network rule and application rule. An IP Group is a top-level resource that allows you to define and group IP addresses, ranges, and subnets into a single object. This is useful for managing IP addresses in Azure Firewall rules. You can either manually enter IP addresses or import them from a file.

An Azure Resource Manager template is a JavaScript Object Notation (JSON) file that defines the infrastructure and configuration for your project. The template uses declarative syntax. You describe your intended deployment without writing the sequence of programming commands to create the deployment.

If your environment meets the prerequisites and you're familiar with using ARM templates, select the Deploy to Azure button. The template will open in the Azure portal.

Prerequisites

Review the template

This template creates an Azure Firewall and IP Groups, along with the necessary resources to support the Azure Firewall.

The template used in this quickstart is from Azure Quickstart Templates.

JSON
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "metadata": {
    "_generator": {
      "name": "bicep",
      "version": "0.25.53.49325",
      "templateHash": "9380698035208685611"
    }
  },
  "parameters": {
    "virtualNetworkName": {
      "type": "string",
      "defaultValue": "[format('vnet{0}', uniqueString(resourceGroup().id))]",
      "metadata": {
        "description": "virtual network name"
      }
    },
    "ipgroups_name1": {
      "type": "string",
      "defaultValue": "[format('ipgroup1{0}', uniqueString(resourceGroup().id))]"
    },
    "ipgroups_name2": {
      "type": "string",
      "defaultValue": "[format('ipgroup2{0}', uniqueString(resourceGroup().id))]"
    },
    "adminUsername": {
      "type": "string",
      "metadata": {
        "description": "Username for the Virtual Machine."
      }
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Location for all resources."
      }
    },
    "vmSize": {
      "type": "string",
      "defaultValue": "Standard_D2s_v3",
      "metadata": {
        "description": "Zone numbers e.g. 1,2,3."
      }
    },
    "numberOfFirewallPublicIPAddresses": {
      "type": "int",
      "defaultValue": 1,
      "minValue": 1,
      "maxValue": 100,
      "metadata": {
        "description": "Number of public IP addresses for the Azure Firewall"
      }
    },
    "authenticationType": {
      "type": "string",
      "defaultValue": "sshPublicKey",
      "allowedValues": [
        "sshPublicKey",
        "password"
      ],
      "metadata": {
        "description": "Type of authentication to use on the Virtual Machine. SSH key is recommended."
      }
    },
    "adminPasswordOrKey": {
      "type": "securestring",
      "metadata": {
        "description": "SSH Key or password for the Virtual Machine. SSH key is recommended."
      }
    }
  },
  "variables": {
    "copy": [
      {
        "name": "azureFirewallIpConfigurations",
        "count": "[length(range(0, parameters('numberOfFirewallPublicIPAddresses')))]",
        "input": {
          "name": "[format('IpConf{0}', range(0, parameters('numberOfFirewallPublicIPAddresses'))[copyIndex('azureFirewallIpConfigurations')])]",
          "properties": {
            "subnet": {
              "id": "[if(equals(range(0, parameters('numberOfFirewallPublicIPAddresses'))[copyIndex('azureFirewallIpConfigurations')], 0), variables('azureFirewallSubnetId'), null())]"
            },
            "publicIPAddress": {
              "id": "[resourceId('Microsoft.Network/publicIPAddresses', format('{0}{1}', variables('publicIPNamePrefix'), add(range(0, parameters('numberOfFirewallPublicIPAddresses'))[range(0, parameters('numberOfFirewallPublicIPAddresses'))[copyIndex('azureFirewallIpConfigurations')]], 1)))]"
            }
          }
        }
      }
    ],
    "vnetAddressPrefix": "10.0.0.0/16",
    "serversSubnetPrefix": "10.0.2.0/24",
    "azureFirewallSubnetPrefix": "10.0.1.0/24",
    "jumpboxSubnetPrefix": "10.0.0.0/24",
    "nextHopIP": "10.0.1.4",
    "azureFirewallSubnetName": "AzureFirewallSubnet",
    "jumpBoxSubnetName": "JumpboxSubnet",
    "serversSubnetName": "ServersSubnet",
    "jumpBoxPublicIPAddressName": "JumpHostPublicIP",
    "jumpBoxNsgName": "JumpHostNSG",
    "jumpBoxNicName": "JumpHostNic",
    "jumpBoxSubnetId": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), variables('jumpBoxSubnetName'))]",
    "serverNicName": "ServerNic",
    "serverSubnetId": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), variables('serversSubnetName'))]",
    "storageAccountName": "[format('{0}sajumpbox', uniqueString(resourceGroup().id))]",
    "azfwRouteTableName": "AzfwRouteTable",
    "firewallName": "firewall1",
    "publicIPNamePrefix": "publicIP",
    "azureFirewallSubnetId": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), variables('azureFirewallSubnetName'))]",
    "linuxConfiguration": {
      "disablePasswordAuthentication": true,
      "ssh": {
        "publicKeys": [
          {
            "path": "[format('/home/{0}/.ssh/authorized_keys', parameters('adminUsername'))]",
            "keyData": "[parameters('adminPasswordOrKey')]"
          }
        ]
      }
    },
    "networkSecurityGroupName": "[format('{0}-nsg', variables('serversSubnetName'))]"
  },
  "resources": [
    {
      "type": "Microsoft.Network/ipGroups",
      "apiVersion": "2023-09-01",
      "name": "[parameters('ipgroups_name1')]",
      "location": "[parameters('location')]",
      "properties": {
        "ipAddresses": [
          "13.73.64.64/26",
          "13.73.208.128/25",
          "52.126.194.0/23"
        ]
      }
    },
    {
      "type": "Microsoft.Network/ipGroups",
      "apiVersion": "2023-09-01",
      "name": "[parameters('ipgroups_name2')]",
      "location": "[parameters('location')]",
      "properties": {
        "ipAddresses": [
          "12.0.0.0/24",
          "13.9.0.0/24"
        ]
      }
    },
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2023-01-01",
      "name": "[variables('storageAccountName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard_LRS"
      },
      "kind": "StorageV2",
      "properties": {}
    },
    {
      "type": "Microsoft.Network/routeTables",
      "apiVersion": "2023-09-01",
      "name": "[variables('azfwRouteTableName')]",
      "location": "[parameters('location')]",
      "properties": {
        "disableBgpRoutePropagation": false,
        "routes": [
          {
            "name": "AzfwDefaultRoute",
            "properties": {
              "addressPrefix": "0.0.0.0/0",
              "nextHopType": "VirtualAppliance",
              "nextHopIpAddress": "[variables('nextHopIP')]"
            }
          }
        ]
      }
    },
    {
      "type": "Microsoft.Network/networkSecurityGroups",
      "apiVersion": "2023-09-01",
      "name": "[variables('networkSecurityGroupName')]",
      "location": "[parameters('location')]",
      "properties": {}
    },
    {
      "type": "Microsoft.Network/virtualNetworks",
      "apiVersion": "2023-09-01",
      "name": "[parameters('virtualNetworkName')]",
      "location": "[parameters('location')]",
      "tags": {
        "displayName": "[parameters('virtualNetworkName')]"
      },
      "properties": {
        "addressSpace": {
          "addressPrefixes": [
            "[variables('vnetAddressPrefix')]"
          ]
        },
        "subnets": [
          {
            "name": "[variables('jumpBoxSubnetName')]",
            "properties": {
              "addressPrefix": "[variables('jumpboxSubnetPrefix')]"
            }
          },
          {
            "name": "[variables('azureFirewallSubnetName')]",
            "properties": {
              "addressPrefix": "[variables('azureFirewallSubnetPrefix')]"
            }
          },
          {
            "name": "[variables('serversSubnetName')]",
            "properties": {
              "addressPrefix": "[variables('serversSubnetPrefix')]",
              "routeTable": {
                "id": "[resourceId('Microsoft.Network/routeTables', variables('azfwRouteTableName'))]"
              },
              "networkSecurityGroup": {
                "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]"
              }
            }
          }
        ]
      },
      "dependsOn": [
        "[resourceId('Microsoft.Network/routeTables', variables('azfwRouteTableName'))]",
        "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]"
      ]
    },
    {
      "copy": {
        "name": "publicIP",
        "count": "[length(range(0, parameters('numberOfFirewallPublicIPAddresses')))]"
      },
      "type": "Microsoft.Network/publicIPAddresses",
      "apiVersion": "2023-09-01",
      "name": "[format('{0}{1}', variables('publicIPNamePrefix'), add(range(0, parameters('numberOfFirewallPublicIPAddresses'))[copyIndex()], 1))]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard"
      },
      "properties": {
        "publicIPAllocationMethod": "Static",
        "publicIPAddressVersion": "IPv4"
      }
    },
    {
      "type": "Microsoft.Network/publicIPAddresses",
      "apiVersion": "2023-09-01",
      "name": "[variables('jumpBoxPublicIPAddressName')]",
      "location": "[parameters('location')]",
      "properties": {
        "publicIPAllocationMethod": "Dynamic"
      }
    },
    {
      "type": "Microsoft.Network/networkSecurityGroups",
      "apiVersion": "2023-09-01",
      "name": "[variables('jumpBoxNsgName')]",
      "location": "[parameters('location')]",
      "properties": {
        "securityRules": [
          {
            "name": "myNetworkSecurityGroupRuleSSH",
            "properties": {
              "protocol": "Tcp",
              "sourcePortRange": "*",
              "destinationPortRange": "22",
              "sourceAddressPrefix": "*",
              "destinationAddressPrefix": "*",
              "access": "Allow",
              "priority": 1000,
              "direction": "Inbound"
            }
          }
        ]
      }
    },
    {
      "type": "Microsoft.Network/networkInterfaces",
      "apiVersion": "2023-09-01",
      "name": "[variables('jumpBoxNicName')]",
      "location": "[parameters('location')]",
      "properties": {
        "ipConfigurations": [
          {
            "name": "ipconfig1",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "publicIPAddress": {
                "id": "[resourceId('Microsoft.Network/publicIPAddresses', variables('jumpBoxPublicIPAddressName'))]"
              },
              "subnet": {
                "id": "[variables('jumpBoxSubnetId')]"
              }
            }
          }
        ],
        "networkSecurityGroup": {
          "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('jumpBoxNsgName'))]"
        }
      },
      "dependsOn": [
        "[resourceId('Microsoft.Network/networkSecurityGroups', variables('jumpBoxNsgName'))]",
        "[resourceId('Microsoft.Network/publicIPAddresses', variables('jumpBoxPublicIPAddressName'))]",
        "[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworkName'))]"
      ]
    },
    {
      "type": "Microsoft.Network/networkInterfaces",
      "apiVersion": "2023-09-01",
      "name": "[variables('serverNicName')]",
      "location": "[parameters('location')]",
      "properties": {
        "ipConfigurations": [
          {
            "name": "ipconfig1",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "subnet": {
                "id": "[variables('serverSubnetId')]"
              }
            }
          }
        ]
      },
      "dependsOn": [
        "[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworkName'))]"
      ]
    },
    {
      "type": "Microsoft.Compute/virtualMachines",
      "apiVersion": "2023-09-01",
      "name": "JumpBox",
      "location": "[parameters('location')]",
      "properties": {
        "hardwareProfile": {
          "vmSize": "[parameters('vmSize')]"
        },
        "storageProfile": {
          "imageReference": {
            "publisher": "Canonical",
            "offer": "UbuntuServer",
            "sku": "18.04-LTS",
            "version": "latest"
          },
          "osDisk": {
            "createOption": "FromImage"
          }
        },
        "osProfile": {
          "computerName": "JumpBox",
          "adminUsername": "[parameters('adminUsername')]",
          "adminPassword": "[parameters('adminPasswordOrKey')]",
          "linuxConfiguration": "[if(equals(parameters('authenticationType'), 'password'), json('null'), variables('linuxConfiguration'))]"
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('jumpBoxNicName'))]"
            }
          ]
        },
        "diagnosticsProfile": {
          "bootDiagnostics": {
            "enabled": true,
            "storageUri": "[reference(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2023-01-01').primaryEndpoints.blob]"
          }
        }
      },
      "dependsOn": [
        "[resourceId('Microsoft.Network/networkInterfaces', variables('jumpBoxNicName'))]",
        "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
      ]
    },
    {
      "type": "Microsoft.Compute/virtualMachines",
      "apiVersion": "2023-09-01",
      "name": "Server",
      "location": "[parameters('location')]",
      "properties": {
        "hardwareProfile": {
          "vmSize": "[parameters('vmSize')]"
        },
        "storageProfile": {
          "imageReference": {
            "publisher": "Canonical",
            "offer": "UbuntuServer",
            "sku": "18.04-LTS",
            "version": "latest"
          },
          "osDisk": {
            "createOption": "FromImage"
          }
        },
        "osProfile": {
          "computerName": "Server",
          "adminUsername": "[parameters('adminUsername')]",
          "adminPassword": "[parameters('adminPasswordOrKey')]",
          "linuxConfiguration": "[if(equals(parameters('authenticationType'), 'password'), null(), variables('linuxConfiguration'))]"
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('serverNicName'))]"
            }
          ]
        },
        "diagnosticsProfile": {
          "bootDiagnostics": {
            "enabled": true,
            "storageUri": "[reference(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2023-01-01').primaryEndpoints.blob]"
          }
        }
      },
      "dependsOn": [
        "[resourceId('Microsoft.Network/networkInterfaces', variables('serverNicName'))]",
        "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
      ]
    },
    {
      "type": "Microsoft.Network/azureFirewalls",
      "apiVersion": "2023-09-01",
      "name": "[variables('firewallName')]",
      "location": "[parameters('location')]",
      "properties": {
        "ipConfigurations": "[variables('azureFirewallIpConfigurations')]",
        "applicationRuleCollections": [
          {
            "name": "appRc1",
            "properties": {
              "priority": 101,
              "action": {
                "type": "Allow"
              },
              "rules": [
                {
                  "name": "someAppRule",
                  "protocols": [
                    {
                      "protocolType": "Http",
                      "port": 8080
                    }
                  ],
                  "targetFqdns": [
                    "*bing.com"
                  ],
                  "sourceIpGroups": [
                    "[resourceId('Microsoft.Network/ipGroups', parameters('ipgroups_name1'))]"
                  ]
                },
                {
                  "name": "someOtherAppRule",
                  "protocols": [
                    {
                      "protocolType": "Mssql",
                      "port": 1433
                    }
                  ],
                  "targetFqdns": [
                    "[format('sql1{0}', environment().suffixes.sqlServerHostname)]"
                  ],
                  "sourceIpGroups": [
                    "[resourceId('Microsoft.Network/ipGroups', parameters('ipgroups_name1'))]",
                    "[resourceId('Microsoft.Network/ipGroups', parameters('ipgroups_name2'))]"
                  ]
                }
              ]
            }
          }
        ],
        "networkRuleCollections": [
          {
            "name": "netRc1",
            "properties": {
              "priority": 200,
              "action": {
                "type": "Allow"
              },
              "rules": [
                {
                  "name": "networkRule",
                  "description": "desc1",
                  "protocols": [
                    "UDP",
                    "TCP",
                    "ICMP"
                  ],
                  "sourceAddresses": [
                    "10.0.0.0",
                    "111.1.0.0/23"
                  ],
                  "sourceIpGroups": [
                    "[resourceId('Microsoft.Network/ipGroups', parameters('ipgroups_name1'))]"
                  ],
                  "destinationIpGroups": [
                    "[resourceId('Microsoft.Network/ipGroups', parameters('ipgroups_name2'))]"
                  ],
                  "destinationPorts": [
                    "90"
                  ]
                }
              ]
            }
          }
        ]
      },
      "dependsOn": [
        "[resourceId('Microsoft.Network/ipGroups', parameters('ipgroups_name1'))]",
        "[resourceId('Microsoft.Network/ipGroups', parameters('ipgroups_name2'))]",
        "publicIP",
        "[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworkName'))]"
      ]
    }
  ],
  "outputs": {
    "location": {
      "type": "string",
      "value": "[parameters('location')]"
    },
    "name": {
      "type": "string",
      "value": "[variables('firewallName')]"
    },
    "resourceGroupName": {
      "type": "string",
      "value": "[resourceGroup().name]"
    },
    "resourceId": {
      "type": "string",
      "value": "[resourceId('Microsoft.Network/azureFirewalls', variables('firewallName'))]"
    }
  }
}

Multiple Azure resources are defined in the template:

Deploy the template

Deploy the ARM template to Azure:

  1. Select Deploy to Azure to sign in to Azure and open the template. The template creates an Azure Firewall, the network infrastructure, and two virtual machines.

  2. In the portal, on the Create an Azure Firewall with IpGroups page, type or select the following values:

    • Subscription: Select from existing subscriptions
    • Resource group: Select from existing resource groups or select Create new, and select OK.
    • Location: Select a location
    • Virtual Network Name: Type a name for the new virtual network (VNet)
    • IP Group Name 1: Type name for IP Group 1
    • IP Group Name 2: Type name for IP Group 2
    • Admin Username: Type username for the administrator user account
    • Authentication: Select sshPublicKey or password
    • Admin Password: Type an administrator password or key
  3. Select I agree to the terms and conditions stated above and then select Purchase. The deployment can take 10 minutes or longer to complete.

Review deployed resources

In the Azure portal, review the deployed resources, especially the firewall rules that use IP Groups.

IP Groups.

Network rules.

IP Groups in Azure Firewall

 

IP Groups in Azure Firewall

IP Groups allow you to group and manage IP addresses for Azure Firewall rules in the following ways:

  • As a source address in DNAT rules
  • As a source or destination address in network rules
  • As a source address in application rules

An IP Group can have a single IP address, multiple IP addresses, one or more IP address ranges or addresses and ranges in combination.

IP Groups can be reused in Azure Firewall DNAT, network, and application rules for multiple firewalls across regions and subscriptions in Azure. Group names must be unique. You can configure an IP Group in the Azure portal, Azure CLI, or REST API. A sample template is provided to help you get started.

Sample format

The following IPv4 address format examples are valid to use in IP Groups:

  • Single address: 10.0.0.0
  • CIDR notation: 10.1.0.0/32
  • Address range: 10.2.0.0-10.2.0.31

Create an IP Group

An IP Group can be created using the Azure portal, Azure CLI, or REST API. For more information, see Create an IP Group.

Browse IP Groups

  1. In the Azure portal search bar, type IP Groups and select it. You can see the list of the IP Groups, or you can select Add to create a new IP Group.

  2. Select an IP Group to open the overview page. You can edit, add, or delete IP addresses or IP Groups.

    IP Groups overview

Manage an IP Group

You can see all the IP addresses in the IP Group and the rules or resources that are associated with it. To delete an IP Group, you must first dissociate the IP Group from the resource that is using it.

  1. To view or edit the IP addresses, select IP Addresses under Settings on the left pane.
  2. To add a single or multiple IP address(es), select Add IP Addresses. This opens the Drag or Browse page for an upload, or you can enter the address manually.
  3. Selecting the ellipses () to the right to edit or delete IP addresses. To edit or delete multiple IP addresses, select the boxes and select Edit or Delete at the top.
  4. Finally, can export the file in the CSV file format.

Use an IP Group

You can now select IP Group as a Source type or Destination type for the IP address(es) when you create Azure Firewall DNAT, application, or network rules.

IP Groups in Firewall

Parallel IP Group updates (preview)

You can now update multiple IP Groups in parallel at the same time. This is particularly useful for administrators who want to make configuration changes more quickly and at scale, especially when making those changes using a dev ops approach (templates, ARM, CLI, and Azure PowerShell).

With this support, you can now:

  • Update 20 IP Groups at a time
  • Update the firewall and firewall policy during IP Group updates
  • Use the same IP Group in parent and child policy
  • Update multiple IP Groups referenced by firewall policy or classic firewall simultaneously
  • Receive new and improved error messages
    • Fail and succeed states

      For example, if there is an error with one IP Group update out of 20 parallel updates, the other updates proceed, and the errored IP Group fails. In addition, if the IP Group update fails, and the firewall is still healthy, the firewall remains in a Succeeded state. To check if the IP Group update has failed or succeeded, you can view the status on the IP Group resource.

To activate Parallel IP Group support, you can register the feature using either Azure PowerShell or the Azure portal.

Azure PowerShell

Use the following Azure PowerShell commands:

Azure PowerShell
Connect-AzAccount
Select-AzSubscription -Subscription <subscription_id> or <subscription_name>
Register-AzProviderFeature -FeatureName AzureFirewallParallelIPGroupUpdate -ProviderNamespace Microsoft.Network
Register-AzResourceProvider -ProviderNamespace Microsoft.Network

It can take several minutes for this to take effect. Once the feature is completely registered, consider performing an update on Azure Firewall for the change to take effect immediately.

Azure portal

  1. Navigate to Preview features in the Azure portal.
  2. Search and register AzureFirewallParallelIPGroupUpdate.
  3. Ensure the feature is enabled.

Screenshot showing the parallel IP groups feature.