快速入门:使用 ARM 模板创建 Azure Web 应用程序防火墙 v2

在本快速入门中,你将使用 Azure 资源管理器模板(ARM 模板)在 Azure 应用程序网关上创建 Azure Web 应用程序防火墙 (WAF) v2。

Azure 资源管理器模板是定义项目基础结构和配置的 JavaScript 对象表示法 (JSON) 文件。 模板使用声明性语法。 你可以在不编写用于创建部署的编程命令序列的情况下,描述预期部署。

注意

建议使用 Azure Az PowerShell 模块与 Azure 交互。 请参阅安装 Azure PowerShell 以开始使用。 若要了解如何迁移到 Az PowerShell 模块,请参阅 将 Azure PowerShell 从 AzureRM 迁移到 Az

如果环境满足先决条件并且你熟悉如何使用 ARM 模板,则可以选择“部署到 Azure”按钮在 Azure 门户中打开模板。

用于将资源管理器模板部署到 Azure 的按钮。

先决条件

查看模板

此模板在 Azure 应用程序网关上创建简单的 Web 应用程序防火墙 v2。 该模板创建公共 IP 前端 IP 地址、HTTP 设置、包含端口 80 上的基本侦听器的规则,以及后端池。 包含自定义规则的 WAF 策略会基于 IP 地址匹配类型阻止发往后端池的流量。

该模板定义以下 Azure 资源:

此模板来自 Azure 快速入门模板

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "metadata": {
    "_generator": {
      "name": "bicep",
      "version": "0.15.31.15270",
      "templateHash": "7253194970749033988"
    }
  },
  "parameters": {
    "adminUsername": {
      "type": "string",
      "metadata": {
        "description": "Admin username for the backend servers"
      }
    },
    "adminPassword": {
      "type": "securestring",
      "metadata": {
        "description": "Password for the admin account on the backend servers"
      }
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Location for all resources."
      }
    },
    "vmSize": {
      "type": "string",
      "defaultValue": "Standard_B2ms",
      "metadata": {
        "description": "Size of the virtual machine."
      }
    }
  },
  "variables": {
    "virtualMachines_myVM_name": "myVM",
    "virtualNetworks_myVNet_name": "myVNet",
    "myNic_name": "net-int",
    "ipconfig_name": "ipconfig",
    "publicIPAddress_name": "public_ip",
    "nsg_name": "vm-nsg",
    "applicationGateways_myAppGateway_name": "myAppGateway",
    "vnet_prefix": "10.0.0.0/16",
    "ag_subnet_prefix": "10.0.0.0/24",
    "backend_subnet_prefix": "10.0.1.0/24",
    "AppGW_AppFW_Pol_name": "WafPol01"
  },
  "resources": [
    {
      "copy": {
        "name": "nsg",
        "count": "[length(range(0, 2))]"
      },
      "type": "Microsoft.Network/networkSecurityGroups",
      "apiVersion": "2021-08-01",
      "name": "[format('{0}{1}', variables('nsg_name'), add(range(0, 2)[copyIndex()], 1))]",
      "location": "[parameters('location')]",
      "properties": {
        "securityRules": [
          {
            "name": "RDP",
            "properties": {
              "protocol": "Tcp",
              "sourcePortRange": "*",
              "destinationPortRange": "3389",
              "sourceAddressPrefix": "*",
              "destinationAddressPrefix": "*",
              "access": "Allow",
              "priority": 300,
              "direction": "Inbound"
            }
          }
        ]
      }
    },
    {
      "copy": {
        "name": "publicIPAddress",
        "count": "[length(range(0, 3))]"
      },
      "type": "Microsoft.Network/publicIPAddresses",
      "apiVersion": "2021-08-01",
      "name": "[format('{0}{1}', variables('publicIPAddress_name'), range(0, 3)[copyIndex()])]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard"
      },
      "properties": {
        "publicIPAddressVersion": "IPv4",
        "publicIPAllocationMethod": "Static",
        "idleTimeoutInMinutes": 4
      }
    },
    {
      "type": "Microsoft.Network/virtualNetworks",
      "apiVersion": "2021-08-01",
      "name": "[variables('virtualNetworks_myVNet_name')]",
      "location": "[parameters('location')]",
      "properties": {
        "addressSpace": {
          "addressPrefixes": [
            "[variables('vnet_prefix')]"
          ]
        },
        "subnets": [
          {
            "name": "myAGSubnet",
            "properties": {
              "addressPrefix": "[variables('ag_subnet_prefix')]",
              "privateEndpointNetworkPolicies": "Enabled",
              "privateLinkServiceNetworkPolicies": "Enabled"
            }
          },
          {
            "name": "myBackendSubnet",
            "properties": {
              "addressPrefix": "[variables('backend_subnet_prefix')]",
              "privateEndpointNetworkPolicies": "Enabled",
              "privateLinkServiceNetworkPolicies": "Enabled"
            }
          }
        ],
        "enableDdosProtection": false,
        "enableVmProtection": false
      }
    },
    {
      "copy": {
        "name": "myVM",
        "count": "[length(range(0, 2))]"
      },
      "type": "Microsoft.Compute/virtualMachines",
      "apiVersion": "2021-11-01",
      "name": "[format('{0}{1}', variables('virtualMachines_myVM_name'), add(range(0, 2)[copyIndex()], 1))]",
      "location": "[parameters('location')]",
      "properties": {
        "hardwareProfile": {
          "vmSize": "[parameters('vmSize')]"
        },
        "storageProfile": {
          "imageReference": {
            "publisher": "MicrosoftWindowsServer",
            "offer": "WindowsServer",
            "sku": "2019-Datacenter",
            "version": "latest"
          },
          "osDisk": {
            "osType": "Windows",
            "createOption": "FromImage",
            "caching": "ReadWrite",
            "managedDisk": {
              "storageAccountType": "StandardSSD_LRS"
            },
            "diskSizeGB": 127
          }
        },
        "osProfile": {
          "computerName": "[format('{0}{1}', variables('virtualMachines_myVM_name'), add(range(0, 2)[copyIndex()], 1))]",
          "adminUsername": "[parameters('adminUsername')]",
          "adminPassword": "[parameters('adminPassword')]",
          "windowsConfiguration": {
            "provisionVMAgent": true,
            "enableAutomaticUpdates": true
          },
          "allowExtensionOperations": true
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces', format('{0}{1}', variables('myNic_name'), add(range(0, 2)[copyIndex()], 1)))]"
            }
          ]
        }
      },
      "dependsOn": [
        "myNic"
      ]
    },
    {
      "copy": {
        "name": "myVM_IIS",
        "count": "[length(range(0, 2))]"
      },
      "type": "Microsoft.Compute/virtualMachines/extensions",
      "apiVersion": "2021-11-01",
      "name": "[format('{0}{1}/IIS', variables('virtualMachines_myVM_name'), add(range(0, 2)[copyIndex()], 1))]",
      "location": "[parameters('location')]",
      "properties": {
        "autoUpgradeMinorVersion": true,
        "publisher": "Microsoft.Compute",
        "type": "CustomScriptExtension",
        "typeHandlerVersion": "1.4",
        "settings": {
          "commandToExecute": "powershell Add-WindowsFeature Web-Server; powershell Add-Content -Path \"C:\\inetpub\\wwwroot\\Default.htm\" -Value $($env:computername)"
        }
      },
      "dependsOn": [
        "myVM"
      ]
    },
    {
      "type": "Microsoft.Network/applicationGateways",
      "apiVersion": "2021-08-01",
      "name": "[variables('applicationGateways_myAppGateway_name')]",
      "location": "[parameters('location')]",
      "properties": {
        "sku": {
          "name": "WAF_v2",
          "tier": "WAF_v2",
          "capacity": 2
        },
        "gatewayIPConfigurations": [
          {
            "name": "appGatewayIpConfig",
            "properties": {
              "subnet": {
                "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('virtualNetworks_myVNet_name'), 'myAGSubnet')]"
              }
            }
          }
        ],
        "frontendIPConfigurations": [
          {
            "name": "appGwPublicFrontendIp",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "publicIPAddress": {
                "id": "[resourceId('Microsoft.Network/publicIPAddresses', format('{0}0', variables('publicIPAddress_name')))]"
              }
            }
          }
        ],
        "frontendPorts": [
          {
            "name": "port_80",
            "properties": {
              "port": 80
            }
          }
        ],
        "backendAddressPools": [
          {
            "name": "myBackendPool",
            "properties": {}
          }
        ],
        "backendHttpSettingsCollection": [
          {
            "name": "myHTTPSetting",
            "properties": {
              "port": 80,
              "protocol": "Http",
              "cookieBasedAffinity": "Disabled",
              "pickHostNameFromBackendAddress": false,
              "requestTimeout": 20
            }
          }
        ],
        "httpListeners": [
          {
            "name": "myListener",
            "properties": {
              "firewallPolicy": {
                "id": "[resourceId('Microsoft.Network/ApplicationGatewayWebApplicationFirewallPolicies', variables('AppGW_AppFW_Pol_name'))]"
              },
              "frontendIPConfiguration": {
                "id": "[resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', variables('applicationGateways_myAppGateway_name'), 'appGwPublicFrontendIp')]"
              },
              "frontendPort": {
                "id": "[resourceId('Microsoft.Network/applicationGateways/frontendPorts', variables('applicationGateways_myAppGateway_name'), 'port_80')]"
              },
              "protocol": "Http",
              "requireServerNameIndication": false
            }
          }
        ],
        "requestRoutingRules": [
          {
            "name": "myRoutingRule",
            "properties": {
              "ruleType": "Basic",
              "priority": 10,
              "httpListener": {
                "id": "[resourceId('Microsoft.Network/applicationGateways/httpListeners', variables('applicationGateways_myAppGateway_name'), 'myListener')]"
              },
              "backendAddressPool": {
                "id": "[resourceId('Microsoft.Network/applicationGateways/backendAddressPools', variables('applicationGateways_myAppGateway_name'), 'myBackendPool')]"
              },
              "backendHttpSettings": {
                "id": "[resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', variables('applicationGateways_myAppGateway_name'), 'myHTTPSetting')]"
              }
            }
          }
        ],
        "enableHttp2": false,
        "firewallPolicy": {
          "id": "[resourceId('Microsoft.Network/ApplicationGatewayWebApplicationFirewallPolicies', variables('AppGW_AppFW_Pol_name'))]"
        }
      },
      "dependsOn": [
        "[resourceId('Microsoft.Network/ApplicationGatewayWebApplicationFirewallPolicies', variables('AppGW_AppFW_Pol_name'))]",
        "[resourceId('Microsoft.Network/virtualNetworks', variables('virtualNetworks_myVNet_name'))]",
        "publicIPAddress"
      ]
    },
    {
      "type": "Microsoft.Network/ApplicationGatewayWebApplicationFirewallPolicies",
      "apiVersion": "2021-08-01",
      "name": "[variables('AppGW_AppFW_Pol_name')]",
      "location": "[parameters('location')]",
      "properties": {
        "customRules": [
          {
            "name": "CustRule01",
            "priority": 100,
            "ruleType": "MatchRule",
            "action": "Block",
            "matchConditions": [
              {
                "matchVariables": [
                  {
                    "variableName": "RemoteAddr"
                  }
                ],
                "operator": "IPMatch",
                "negationConditon": true,
                "matchValues": [
                  "10.10.10.0/24"
                ]
              }
            ]
          }
        ],
        "policySettings": {
          "requestBodyCheck": true,
          "maxRequestBodySizeInKb": 128,
          "fileUploadLimitInMb": 100,
          "state": "Enabled",
          "mode": "Prevention"
        },
        "managedRules": {
          "managedRuleSets": [
            {
              "ruleSetType": "OWASP",
              "ruleSetVersion": "3.1"
            }
          ]
        }
      }
    },
    {
      "copy": {
        "name": "myNic",
        "count": "[length(range(0, 2))]"
      },
      "type": "Microsoft.Network/networkInterfaces",
      "apiVersion": "2021-08-01",
      "name": "[format('{0}{1}', variables('myNic_name'), add(range(0, 2)[copyIndex()], 1))]",
      "location": "[parameters('location')]",
      "properties": {
        "ipConfigurations": [
          {
            "name": "[format('{0}{1}', variables('ipconfig_name'), add(range(0, 2)[copyIndex()], 1))]",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "publicIPAddress": {
                "id": "[resourceId('Microsoft.Network/publicIPAddresses', format('{0}{1}', variables('publicIPAddress_name'), add(range(0, 2)[copyIndex()], 1)))]"
              },
              "subnet": {
                "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('virtualNetworks_myVNet_name'), 'myBackendSubnet')]"
              },
              "primary": true,
              "privateIPAddressVersion": "IPv4",
              "applicationGatewayBackendAddressPools": [
                {
                  "id": "[resourceId('Microsoft.Network/applicationGateways/backendAddressPools', variables('applicationGateways_myAppGateway_name'), 'myBackendPool')]"
                }
              ]
            }
          }
        ],
        "enableAcceleratedNetworking": false,
        "enableIPForwarding": false,
        "networkSecurityGroup": {
          "id": "[resourceId('Microsoft.Network/networkSecurityGroups', format('{0}{1}', variables('nsg_name'), add(range(0, 2)[copyIndex()], 1)))]"
        }
      },
      "dependsOn": [
        "[resourceId('Microsoft.Network/applicationGateways', variables('applicationGateways_myAppGateway_name'))]",
        "[resourceId('Microsoft.Network/virtualNetworks', variables('virtualNetworks_myVNet_name'))]",
        "nsg",
        "publicIPAddress"
      ]
    }
  ]
}

部署模板

将 ARM 模板部署到 Azure:

  1. 选择“部署到 Azure”,登录到 Azure 并打开模板。 该模板在运行 IIS 的后端池中创建应用程序网关、网络基础结构和两个 VM。

    用于将资源管理器模板部署到 Azure 的按钮。

  2. 选择或创建资源组。

  3. 选择“查看 + 创建”,然后在验证通过后选择“创建”。 部署可能需要 10 分钟或更长时间才能完成。

验证部署

尽管不需要 IIS,但该模板会在后端服务器上安装 IIS,以便可以验证 Azure 是否已在应用程序网关上成功创建了 WAF v2。

使用 IIS 测试应用程序网关:

  1. 从应用程序网关的“概述”页面复制其公共 IP 地址。

    显示应用程序网关公共 IP 地址的屏幕截图。

    还可以在 Azure 搜索框中搜索“应用程序网关”。 应用程序网关列表在“公共 IP 地址”列中显示公共 IP 地址。

  2. 将 IP 地址粘贴到浏览器的地址栏中以浏览该地址。

  3. 检查响应。 “403 禁止”响应验证 WAF 是否成功阻止与后端池的连接。

  4. 要更改自定义规则以允许流量,请运行以下 Azure PowerShell 脚本,替换资源组名称:

    $rg = "<your resource group name>"
    $AppGW = Get-AzApplicationGateway -Name myAppGateway -ResourceGroupName $rg
    $pol = Get-AzApplicationGatewayFirewallPolicy -Name WafPol01 -ResourceGroupName $rg
    $pol[0].customrules[0].action = "allow"
    $rule = $pol.CustomRules
    Set-AzApplicationGatewayFirewallPolicy -Name WafPol01 -ResourceGroupName $rg -CustomRule $rule
    $AppGW.FirewallPolicy = $pol
    Set-AzApplicationGateway -ApplicationGateway $AppGW
    
  5. 多次刷新浏览器。 应会看到与 myVM1 和 myVM2 的连接。

清理资源

不再需要在本快速入门中创建的资源时,请删除资源组以移除应用程序网关及其所有相关资源。

若要删除资源组,请调用 Remove-AzResourceGroup cmdlet:

Remove-AzResourceGroup -Name "<your resource group name>"

后续步骤