教程:使用 Azure PowerShell 保护虚拟中心Tutorial: Secure your virtual hub using Azure PowerShell

本教程将使用一个区域中的虚拟中心创建一个虚拟 WAN 实例,并在该虚拟中心部署 Azure 防火墙以确保连接安全。In this tutorial, you create a Virtual WAN instance with a Virtual Hub in one region, and you deploy an Azure Firewall in the Virtual Hub to secure connectivity. 此示例将演示虚拟网络之间的安全连接。In this example, you demonstrate secure connectivity between Virtual Networks. 虚拟网络和站点到站点、点到站点或 ExpressRoute 分支之间的流量也受虚拟安全中心支持。Traffic between virtual networks and site-to-site, point-to-site, or ExpressRoute branches are supported by Virtual Secure Hub as well.

在本教程中,你将了解如何执行以下操作:In this tutorial, you learn how to:

  • 部署虚拟 WANDeploy the virtual WAN
  • 部署 Azure 防火墙并配置自定义路由Deploy Azure Firewall and configure custom routing
  • 测试连接Test connectivity

先决条件Prerequisites

  • 如果没有 Azure 订阅,可在开始前创建一个试用帐户If you don't have an Azure subscription, create a trial account before you begin.

  • PowerShell 7PowerShell 7

    本教程要求在 PowerShell 7 上本地运行 Azure PowerShell。This tutorial requires that you run Azure PowerShell locally on PowerShell 7. 若要安装 PowerShell 7,请参阅从 Windows PowerShell 5.1 迁移到 PowerShell 7To install PowerShell 7, see Migrating from Windows PowerShell 5.1 to PowerShell 7.

  • Az.Network 版本 3.2.0Az.Network version 3.2.0

    如果已有 Az.Network 版本 3.4.0 或更高版本,则需要降级才能使用本教程中的某些命令。If you have Az.Network version 3.4.0 or later, you'll need to downgrade to use some of the commands in this tutorial. 可以通过命令 Get-InstalledModule -Name Az.Network 查看 Az. Network 模块的版本。You can check the version of your Az.Network module with the command Get-InstalledModule -Name Az.Network. 若要卸载 Az.Network 模块,请运行 Uninstall-Module -name az.networkTo uninstall the Az.Network module, run Uninstall-Module -name az.network. 若要安装 Az.Network 3.2.0 模块,请运行 Install-Module az.network -RequiredVersion 3.2.0 -forceTo install the Az.Network 3.2.0 module, run Install-Module az.network -RequiredVersion 3.2.0 -force.

登录 AzureSign in to Azure

Connect-AzAccount -Environment AzureChinaCloud
Select-AzSubscription -Subscription "<sub name>"

初始虚拟 WAN 部署Initial Virtual WAN deployment

第一步,需要设置一些变量并创建资源组、虚拟 WAN 实例和虚拟中心:As a first step, you need to set some variables and create the resource group, the virtual WAN instance, and the virtual hub:

# Variable definition
$RG = "vwan-rg"
$Location = "chinaeast2"
$VwanName = "vwan"
$HubName =  "hub1"
# Create Resource Group, Virtual WAN and Virtual Hub
New-AzResourceGroup -Name $RG -Location $Location
$Vwan = New-AzVirtualWan -Name $VwanName -ResourceGroupName $RG -Location $Location -AllowVnetToVnetTraffic -AllowBranchToBranchTraffic -VirtualWANType "Standard"
$Hub = New-AzVirtualHub -Name $HubName -ResourceGroupName $RG -VirtualWan $Vwan -Location $Location -AddressPrefix "192.168.1.0/24" -Sku "Standard"

创建两个虚拟网络并将其作为分支连接到中心:Create two virtual networks and connect them to the hub as spokes:

# Create Virtual Network
$Spoke1 = New-AzVirtualNetwork -Name "spoke1" -ResourceGroupName $RG -Location $Location -AddressPrefix "10.1.1.0/24"
$Spoke2 = New-AzVirtualNetwork -Name "spoke2" -ResourceGroupName $RG -Location $Location -AddressPrefix "10.1.2.0/24"
# Connect Virtual Network to Virtual WAN
$Spoke1Connection = New-AzVirtualHubVnetConnection -ResourceGroupName $RG -ParentResourceName  $HubName -Name "spoke1" -RemoteVirtualNetwork $Spoke1
$Spoke2Connection = New-AzVirtualHubVnetConnection -ResourceGroupName $RG -ParentResourceName  $HubName -Name "spoke2" -RemoteVirtualNetwork $Spoke2

这样就产生了一个功能齐全的虚拟 WAN,可提供任意连接性。At this point, you have a fully functional Virtual WAN providing any-to-any connectivity. 为了增强安全性,需要将 Azure 防火墙部署到每个虚拟中心。To enhance it with security, you need to deploy an Azure Firewall to each Virtual Hub. 防火墙策略可用于有效地管理虚拟 WAN Azure 防火墙实例。Firewall Policies can be used to efficiently manage the virtual WAN Azure Firewall instance. 所以在此示例中还创建了防火墙策略:So a firewall policy is created as well in this example:

# New Firewall Policy
$FWPolicy = New-AzFirewallPolicy -Name "VwanFwPolicy" -ResourceGroupName $RG -Location $Location
# New Firewall Public IP
$AzFWPIPs = New-AzFirewallHubPublicIpAddress -Count 1
$AzFWHubIPs = New-AzFirewallHubIpAddress -PublicIP $AzFWPIPs
# New Firewall
$AzFW = New-AzFirewall -Name "azfw1" -ResourceGroupName $RG -Location $Location `
            -VirtualHubId $Hub.Id -FirewallPolicyId $FWPolicy.Id `
            -Sku AZFW_Hub -HubIPAddress $AzFWHubIPs

启用从 Azure 防火墙到 Azure Monitor 的日志记录是一项可选操作,但在此示例中,将使用防火墙日志来证明流量正在遍历防火墙:Enabling logging from the Azure Firewall to Azure Monitor is optional, but in this example you use the Firewall logs to prove that traffic is traversing the firewall:

# Optionally, enable looging of Azure Firewall to Azure Monitor
$LogWSName = "vwan-" + (Get-Random -Maximum 99999) + "-" + $RG
$LogWS = New-AzOperationalInsightsWorkspace -Location $Location -Name $LogWSName -Sku Standard -ResourceGroupName $RG
Set-AzDiagnosticSetting -ResourceId $AzFW.Id -Enabled $True -Category AzureFirewallApplicationRule, AzureFirewallNetworkRule -WorkspaceId $LogWS.ResourceId

部署 Azure 防火墙并配置自定义路由Deploy Azure Firewall and configure custom routing

现在中心已具有 Azure 防火墙,但仍需要修改路由,以便让虚拟 WAN 通过防火墙发送来自虚拟网络和分支的流量。Now you have an Azure Firewall in the hub, but you still need to modify routing so the Virtual WAN sends the traffic from the virtual networks and from the branches through the firewall. 可以通过两个步骤达到此目的:You do this in two steps:

  1. 配置要传播到 None 路由表的所有虚拟网络连接(以及存在的所有分支连接)。Configure all virtual network connections (and branch connections if there were any) to propagate to the None Route Table. 此配置的效果是,其他虚拟网络和分支不会学习其前缀,因此没有路由来访问它们。The effect of this configuration is that other virtual networks and branches won't learn their prefixes, and so has no routing to reach them.
  2. 现在可以在 Default 路由表(默认情况下关联所有虚拟网络和分支)中插入静态路由,以便将所有流量发送到 Azure 防火墙。Now you can insert static routes in the Default Route Table (where all virtual networks and branches are associated by default), so that all traffic is sent to the Azure Firewall.

备注

这是在使用 Azure 防火墙管理器保护来自 Azure 门户的连接时部署的配置This is the configuration deployed when securing connectivity from the Azure Portal with Azure Firewall Manager

从第一步开始,将虚拟网络连接配置为传播到 None 路由表:Start with the first step, to configure your virtual network connections to propagate to the None Route Table:

# Configure Virtual Network connections in hub to propagate to None
$VnetRoutingConfig = $Spoke1Connection.RoutingConfiguration    # We take $Spoke1Connection as baseline for the future vnet config, all vnets will have an identical config
$NoneRT = Get-AzVhubRouteTable -ResourceGroupName $RG -HubName $HubName -Name "noneRouteTable"
$NewPropRT = @{}
$NewPropRT.Add('Id', $NoneRT.id)
$PropRTList = @()
$PropRTList += $NewPropRT
$VnetRoutingConfig.PropagatedRouteTables.Ids = $PropRTList
$VnetRoutingConfig.PropagatedRouteTables.Labels = @()
$Spoke1Connection = Update-AzVirtualHubVnetConnection -ResourceGroupName $RG -ParentResourceName  $HubName -Name "spoke1" -RoutingConfiguration $VnetRoutingConfig
$Spoke2Connection = Update-AzVirtualHubVnetConnection -ResourceGroupName $RG -ParentResourceName  $HubName -Name "spoke2" -RoutingConfiguration $VnetRoutingConfig

现在可以继续执行第二步,将静态路由添加到 Default 路由表。Now you can continue with the second step, to add the static routes to the Default route table. 此示例应用 Azure 防火墙管理器在保护虚拟 WAN 中的连接时生成的默认配置,但可以更改静态路由中的前缀列表以满足特定要求:In this example, you apply the default configuration that Azure Firewall Manager would generate when securing connectivity in a Virtual WAN, but you can change the list of prefixes in the static route to fit your specific requirements:

# Create static routes in default Route table
$AzFWId = $(Get-AzVirtualHub -ResourceGroupName $RG -name  $HubName).AzureFirewall.Id
$AzFWRoute = New-AzVHubRoute -Name "private-traffic" -Destination @("0.0.0.0/0", "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16") -DestinationType "CIDR" -NextHop $AzFWId -NextHopType "ResourceId"
$DefaultRT = Update-AzVHubRouteTable -Name "defaultRouteTable" -ResourceGroupName $RG -VirtualHubName  $HubName -Route @($AzFWRoute)

测试连接Test connectivity

现在,你已具有功能正常的安全中心。Now you have a fully operational secure hub. 若要测试连接性,需要在连接到中心的每个分支虚拟网络中都具有一个虚拟机:To test connectivity, you need one virtual machine in each spoke virtual network connected to the hub:

# Create VMs in spokes for testing
$VMLocalAdminUser = "lab-user"
$VMLocalAdminSecurePassword = ConvertTo-SecureString -AsPlainText -Force
$VMCredential = New-Object System.Management.Automation.PSCredential ($VMLocalAdminUser, $VMLocalAdminSecurePassword);
$VMSize = "Standard_B2ms"
# Spoke1
$Spoke1 = Get-AzVirtualNetwork -ResourceGroupName $RG -Name "spoke1"
Add-AzVirtualNetworkSubnetConfig -Name "vm" -VirtualNetwork $Spoke1 -AddressPrefix "10.1.1.0/26"
$Spoke1 | Set-AzVirtualNetwork
$VM1 = New-AzVM -Name "spoke1-vm" -ResourceGroupName $RG -Location $Location `
            -Image "UbuntuLTS" -credential $VMCredential `
            -VirtualNetworkName "spoke1" -SubnetName "vm" -PublicIpAddressName "spoke1-pip"
$NIC1 = Get-AzNetworkInterface -ResourceId $($VM1.NetworkProfile.NetworkInterfaces[0].Id)
$Spoke1VMPrivateIP = $NIC1.IpConfigurations[0].PrivateIpAddress
$Spoke1VMPIP = $(Get-AzPublicIpAddress -ResourceGroupName $RG -Name "spoke1-pip")
# Spoke2
$Spoke2 = Get-AzVirtualNetwork -ResourceGroupName $RG -Name "spoke2"
Add-AzVirtualNetworkSubnetConfig -Name "vm" -VirtualNetwork $Spoke2 -AddressPrefix "10.1.2.0/26"
$Spoke2 | Set-AzVirtualNetwork
$VM2 = New-AzVM -Name "spoke2-vm" -ResourceGroupName $RG -Location $Location `
            -Image "UbuntuLTS" -credential $VMCredential `
            -VirtualNetworkName "spoke2" -SubnetName "vm" -PublicIpAddressName "spoke2-pip"
$NIC2 = Get-AzNetworkInterface -ResourceId $($VM2.NetworkProfile.NetworkInterfaces[0].Id)
$Spoke2VMPrivateIP = $NIC2.IpConfigurations[0].PrivateIpAddress
$Spoke2VMPIP = $(Get-AzPublicIpAddress -ResourceGroupName $RG -Name "spoke2-pip")

防火墙策略中的默认配置是删除所有内容。The default configuration in the firewall policy is to drop everything. 因此需要配置一些规则。So you need to configure some rules. 首先是配置 DNAT 规则,以便能通过防火墙的公共 IP 地址访问测试虚拟机:Start with DNAT rules, so that the test virtual machines are accessible over the Firewall's public IP address:

# Adding DNAT rules for virtual machines in the spokes
$AzFWPublicAddress = $AzFW.HubIPAddresses.PublicIPs.Addresses[0].Address
$NATRuleSpoke1 = New-AzFirewallPolicyNatRule -Name "Spoke1SSH" -Protocol "TCP" `
        -SourceAddress "*" -DestinationAddress $AzFWPublicAddress -DestinationPort 10001 `
        -TranslatedAddress $Spoke1VMPrivateIP -TranslatedPort 22
$NATRuleSpoke2 = New-AzFirewallPolicyNatRule -Name "Spoke2SSH" -Protocol "TCP" `
        -SourceAddress "*" -DestinationAddress $AzFWPublicAddress -DestinationPort 10002 `
        -TranslatedAddress $Spoke2VMPrivateIP -TranslatedPort 22
$NATCollection = New-AzFirewallPolicyNatRuleCollection -Name "SSH" -Priority 100 `
        -Rule @($NATRuleSpoke1, $NATRuleSpoke2) -ActionType "Dnat"
$NATGroup = New-AzFirewallPolicyRuleCollectionGroup -Name "NAT" -Priority 100 -RuleCollection $NATCollection -FirewallPolicyObject $FWPolicy

现在可以配置一些示例规则。Now you can configure some example rules. 定义允许 SSH 流量的网络规则,以及允许通过 Internet 访问完全限定的域名 ifconfig.co 的应用程序规则。Define a network rule that allows SSH traffic, plus an application rule that allows Internet access to the Fully Qualified Domain Name ifconfig.co. 此 URL 返回它在 HTTP 请求中获取的源 IP 地址:This URL returns the source IP address it sees in the HTTP request:

# Add Network Rule
$SSHRule = New-AzFirewallPolicyNetworkRule -Name PermitSSH -Protocol TCP `
        -SourceAddress "10.0.0.0/8" -DestinationAddress "10.0.0.0/8" -DestinationPort 22
$NetCollection = New-AzFirewallPolicyFilterRuleCollection -Name "Management" -Priority 100 -ActionType Allow -Rule $SSHRule
$NetGroup = New-AzFirewallPolicyRuleCollectionGroup -Name "Management" -Priority 200 -RuleCollection $NetCollection -FirewallPolicyObject $FWPolicy
# Add Application Rul
$ifconfigRule = New-AzFirewallPolicyApplicationRule -Name PermitIfconfig -SourceAddress "10.0.0.0/8" -TargetFqdn "ifconfig.co" -Protocol "http:80","https:443"
$AppCollection = New-AzFirewallPolicyFilterRuleCollection -Name "TargetURLs" -Priority 300 -ActionType Allow -Rule $ifconfigRule
$NetGroup = New-AzFirewallPolicyRuleCollectionGroup -Name "TargetURLs" -Priority 300 -RuleCollection $AppCollection -FirewallPolicyObject $FWPolicy

在实际发送任何流量之前,可以检查虚拟机的有效路由。Before actually sending any traffic, you can inspect the effective routes of the virtual machines. 它们应包含从虚拟 WAN(0.0.0.0/0 加 RFC1918)获知的前缀,但不包含其他分支的前缀:They should contain the prefixes learned from the Virtual WAN (0.0.0.0/0 plus RFC1918), but not the prefix of the other spoke:

# Check effective routes in the VM NIC in spoke 1
# Note that 10.1.2.0/24 (the prefix for spoke2) should not appear
Get-AzEffectiveRouteTable -ResourceGroupName $RG -NetworkInterfaceName $NIC1.Name | ft
# Check effective routes in the VM NIC in spoke 2
# Note that 10.1.1.0/24 (the prefix for spoke1) should not appear
Get-AzEffectiveRouteTable -ResourceGroupName $RG -NetworkInterfaceName $NIC2.Name | ft

现在,生成从一个虚拟机到另一个虚拟机的流量,然后验证 Azure 防火墙中是否已删除该流量。Now generate traffic from one Virtual Machine to the other, and verify that it's dropped in the Azure Firewall. 在以下 SSH 命令中,需要接受虚拟机指纹,并提供在创建虚拟机时定义的密码。In the following SSH commands you need to accept the virtual machines fingerprints, and provide the password that you defined when you created the virtual machines. 在此示例中,将从 spoke1 中的虚拟机向 spoke2 发送五个 ICMP 回显请求数据包,并使用 Linux 实用工具 nc 在端口 22 上尝试 TCP 连接(使用 -vz 标志,只发送连接请求并显示结果)。In this example, you're going to send five ICMP echo request packets from the virtual machine in spoke1 to spoke2, plus a TCP connection attempt on port 22 using the Linux utility nc (with the -vz flags it just sends a connection request and shows the result). 结果应为 ping 失败,而端口 22 上的 TCP 连接尝试成功,因为之前配置的网络规则允许该连接:You should see the ping failing, and the TCP connection attempt on port 22 succeeding, since it's allowed by the network rule you configured previously:

# Connect to one VM and ping the other. It shouldnt work, because the firewall should drop the traffic, since no rule for ICMP is configured
ssh $AzFWPublicAddress -p 10001 -l $VMLocalAdminUser "ping $Spoke2VMPrivateIP -c 5"
# Connect to one VM and send a TCP request on port 22 to the other. It should work, because the firewall is configured to allow SSH traffic (port 22)
ssh $AzFWPublicAddress -p 10001 -l $VMLocalAdminUser "nc -vz $Spoke2VMPrivateIP 22"

还可以验证 Internet 流量。You can also verify Internet traffic. 通过实用工具 curl 对防火墙策略 (ifconfig.co) 中允许的 FQDN 的 HTTP 请求应成功,但对任何其他目标的 HTTP 请求应会失败(本示例使用 bing.com 进行测试):HTTP requests via the utility curl to the FQDN you allowed in the firewall policy (ifconfig.co) should work, but HTTP requests to any other destination should fail (in this example you test with bing.com):

# This HTTP request should succeed, since it is allowed in an app rule in the AzFW, and return the public IP of the FW
ssh $AzFWPublicAddress -p 10001 -l $VMLocalAdminUser "curl -s4 ifconfig.co"
# This HTTP request should fail, since the FQDN bing.com is not in any app rule in the firewall policy
ssh $AzFWPublicAddress -p 10001 -l $VMLocalAdminUser "curl -s4 bing.com"

若要验证防火墙是否删除了数据包,最简单的方法是检查日志。The easiest way to verify the packets are dropped by the firewall is to check the logs. 由于已将 Azure 防火墙配置为将日志发送到 Azure Monitor,因此可以使用 Kusto 查询语言从 Azure Monitor 检索相关日志:Since you configured the Azure Firewall to send logs to Azure Monitor, you can use the Kusto Query Language to retrieve the relevant logs from Azure Monitor:

备注

可能需要大约 1 分钟的时间才能看到日志被发送到 Azure MonitorIt can take around 1 minute for the logs to appear to be sent to Azure Monitor

# Getting Azure Firewall network rule Logs
$LogWS = Get-AzOperationalInsightsWorkspace -ResourceGroupName $RG
$LogQuery = 'AzureDiagnostics 
| where Category == "AzureFirewallNetworkRule" 
| where TimeGenerated >= ago(5m) 
| parse msg_s with Protocol " request from " SourceIP ":" SourcePortInt:int " to " TargetIP ":" TargetPortInt:int * 
| parse msg_s with * ". Action: " Action1a 
| parse msg_s with * " was " Action1b " to " NatDestination 
| parse msg_s with Protocol2 " request from " SourceIP2 " to " TargetIP2 ". Action: " Action2 
| extend SourcePort = tostring(SourcePortInt),TargetPort = tostring(TargetPortInt) 
| extend Action = case(Action1a == "", case(Action1b == "",Action2,Action1b), Action1a),Protocol = case(Protocol == "", Protocol2, Protocol),SourceIP = case(SourceIP == "", SourceIP2, SourceIP),TargetIP = case(TargetIP == "", TargetIP2, TargetIP),SourcePort = case(SourcePort == "", "N/A", SourcePort),TargetPort = case(TargetPort == "", "N/A", TargetPort),NatDestination = case(NatDestination == "", "N/A", NatDestination) 
| project TimeGenerated, Protocol, SourceIP,SourcePort,TargetIP,TargetPort,Action, NatDestination, Resource 
| take 25 '
$(Invoke-AzOperationalInsightsQuery -Workspace $LogWS -Query $LogQuery).Results | ft

在前面的命令中,应看到不同的条目:In the previous command you should see different entries:

  • 正在对 SSH 连接应用 DNAT 规则Your SSH connection being DNAT'ed
  • 已删除分支(10.1.1.4 和 10.1.2.4)中 VM 之间的 ICMP 数据包Dropped ICMP packets between the VMs in the spokes (10.1.1.4 and 10.1.2.4)
  • 允许在分支中的 VM 之间建立 SSH 连接Allowed SSH connections between the VMs in the spokes

下面是上述命令生成的输出示例:Here a sample output produced by the command above:

TimeGenerated            Protocol    SourceIP       SourcePort TargetIP      TargetPort Action  NatDestination Resource
-------------            --------    --------       ---------- --------      ---------- ------  -------------- --------
2020-10-04T20:53:02.41Z  TCP         109.125.122.99 62281      51.105.224.44 10001      DNAT'ed 10.1.1.4:22    AZFW1
2020-10-04T20:53:07.045Z TCP         10.1.1.4       35932      10.1.2.4      22         Allow   N/A            AZFW1
2020-10-04T20:53:50.119Z TCP         109.125.122.99 62293      51.105.224.44 10001      DNAT'ed 10.1.2.4:22    AZFW1
2020-10-04T20:52:47.475Z TCP         109.125.122.99 62273      51.105.224.44 10001      DNAT'ed 10.1.2.4:22    AZFW1
2020-10-04T20:51:04.682Z TCP         109.125.122.99 62200      51.105.224.44 10001      DNAT'ed 10.1.2.4:22    AZFW1
2020-10-04T20:51:17.031Z ICMP Type=8 10.1.1.4       N/A        10.1.2.4      N/A        Deny    N/A            AZFW1
2020-10-04T20:51:18.049Z ICMP Type=8 10.1.1.4       N/A        10.1.2.4      N/A        Deny    N/A            AZFW1
2020-10-04T20:51:19.075Z ICMP Type=8 10.1.1.4       N/A        10.1.2.4      N/A        Deny    N/A            AZFW1
2020-10-04T20:51:20.097Z ICMP Type=8 10.1.1.4       N/A        10.1.2.4      N/A        Deny    N/A            AZFW1
2020-10-04T20:51:21.121Z ICMP Type=8 10.1.1.4       N/A        10.1.2.4      N/A        Deny    N/A            AZFW1
2020-10-04T20:52:52.356Z TCP         10.1.1.4       53748      10.1.2.4      22         Allow   N/A            AZFW1

若要查看应用程序规则(描述允许和拒绝的 HTTP 连接)的日志或更改日志显示方式,可以尝试使用其他 KQL 查询。If you want to see the logs for the application rules (describing allowed and denied HTTP connections) or change the way that the logs are displayed, you can try with other KQL queries. 可以在 Azure 防火墙的 Azure Monitor 日志中找到一些示例。You can find some examples in Azure Monitor logs for Azure Firewall.

清理资源Clean up resources

若要删除测试环境,可以删除带有所有包含的对象的资源组:To delete the test environment, you can remove the resource group with all contained objects:

# Delete resource group and all contained resources
Remove-AzResourceGroup -Name $RG

后续步骤Next steps