你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

使用警报和 Azure Functions 通过数据包捕获主动监视网络

Azure 网络观察程序的数据包捕获功能可创建捕获会话,以跟踪进出虚拟机 (VM) 的流量。 你可在捕获文件中定义一个筛选器,使其只跟踪要监视的流量。 将此数据存储在存储 Blob 中或来宾计算机本地。

你可以从其他自动化方案(例如从 Azure Functions)远程启动此功能。 而且可以根据定义的网络异常运行主动捕获。 其他用途包括收集网络统计信息、获取有关网络入侵的信息以及调试客户端/服务器通信。

在 Azure 中部署的资源将持续运行。 很难时时主动监视所有资源的状态。 例如,如果在凌晨 2:00 发生问题,会出现什么情况?

通过在 Azure 生态系统中使用网络观察程序警报和函数,可以主动使用数据和工具做出响应,解决网络中的问题。

先决条件

场景

在本示例中,虚拟机的传出流量比平常多,并且你希望收到相关警报。 你可以使用类似的过程为任何条件创建警报。

当事件触发警报时,数据包级数据可帮助你分析传出流量增加的原因。 可以采取措施让虚拟机恢复到初始状态。

本方案假设已具有网络观察程序的现有实例,以及一个包含有效虚拟机的资源组。

下面是数据包捕获的工作流:

  1. 事件在 VM 上触发警报。
  2. 警报调用 Azure 函数。
  3. Azure 函数处理警报,并启动网络观察程序数据包捕获会话。
  4. 数据包捕获在 VM 上运行并收集数据。
  5. 将数据包捕获文件上传到存储帐户进行审查和诊断。

为了自动执行此过程,你将在 VM 上创建并连接一个警报,以便在事件发生时触发。 你还将创建用于调用网络观察程序的函数。

在此方案中:

  • 创建一个启动数据包捕获的 Azure 函数。
  • 在虚拟机上创建警报规则,并将警报规则配置为调用该 Azure 函数。

创建 Azure 函数

若要创建一个 Azure 函数来处理警报并创建数据包捕获,你首先需要创建函数应用:

  1. 登录 Azure 门户

  2. 在门户顶部的搜索框中,输入“函数应用”。 从搜索结果中选择“函数应用”

    Screenshot that shows how to search for function apps in the Azure portal.

  3. 选择“+ 新建”。

  4. 在“创建函数应用”的“基本信息”选项卡中,为以下设置输入或选择值:

    • 在“项目详细信息”下,选择要为其创建函数应用的订阅以及要包含该应用的资源组
    • 在“实例详细信息”下:
      • 对于“函数应用名称”,请输入函数应用的名称。 此名称的后面将附加“.azurewebsites.net”
      • 对于“是要部署代码还是容器映像?”,请选择发布模式:“代码”或“容器映像”
      • 对于“运行时堆栈”,请选择一个运行时堆栈。
      • 对于“版本”,请选择运行时堆栈的版本。
      • 对于“区域”,请选择要在其中创建函数应用的区域。
    • 在“操作系统”下,选择当前使用的操作系统的类型。 Azure 将根据你选择的运行时堆栈来建议操作系统的类型。
    • 在“托管”下,选择要用于函数应用的计划类型。 从以下选项中选择:
      • 消耗(无服务器):用于事件驱动的缩放,成本最低。
      • 函数高级 - 用于具有基于事件的缩放和网络隔离的企业级无服务器应用程序。
      • 应用服务计划 - 用于重复使用现有 Azure 应用服务计划中的计算。

    Screenshot of the Create Function App page in the Azure portal.

  5. 选择“查看 + 创建”以创建应用。

现在可以创建函数:

  1. 在创建的函数应用中,选择“函数”,然后选择“创建”来打开“创建函数”窗格

    Screenshot of the Create function pane.

  2. 对于“开发环境”,请选择“在门户中开发”。

  3. 在“选择模板”下,选择“HTTP 触发器”。

  4. 在“模板详细信息”部分中,执行以下操作:

    • 对于“新建函数”,请输入函数的名称。
    • 对于“授权级别”,请选择“函数”
  5. 选择创建

  6. 转到创建的函数并选择“代码 + 测试”

    Screenshot of the Code + Test page for a function.

  7. 更新脚本并选择“保存”。

配置身份验证

若要使用 PowerShell cmdlet,必须在函数应用中配置身份验证。 若要配置身份验证,必须配置环境变量,并将加密密钥文件上传到函数应用。

注意

此方案仅提供如何使用 Azure Functions 实现身份验证的一个示例。 还有其他方法可以执行相同的操作。

以下 PowerShell 脚本创建名为 PassEncryptKey.key 的密钥文件。 它还提供所提供密码的加密版本。 此密码与为用于身份验证的 Microsoft Entra 应用程序定义的密码相同。

#Variables
$keypath = "C:\temp\PassEncryptKey.key"
$AESKey = New-Object Byte[] 32
$Password = "<insert a password here>"

#Keys
[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($AESKey) 
Set-Content $keypath $AESKey

#Get encrypted password
$secPw = ConvertTo-SecureString -AsPlainText $Password -Force
$AESKey = Get-content $KeyPath
$Encryptedpassword = $secPw | ConvertFrom-SecureString -Key $AESKey
$Encryptedpassword

检索环境变量的值

设置以下环境变量,这是访问身份验证值所必需的:

  • AzureClientID
  • AzureTenant
  • AzureCredPassword

如果已获得应用程序 ID,请使用该应用程序的 AzureClientIDAzureTenantAzureCredPassword 值。 如果未获得,请转到“存储环境变量”部分。

AzureClientID

客户端 ID 是 Microsoft Entra ID 中应用程序的 ID。 若要获取客户端 ID,请执行以下操作:

  1. 如果还没有可使用的应用程序,请运行以下 cmdlet 来创建应用程序:

    $app = New-AzADApplication -DisplayName "ExampleAutomationAccount_MF" -HomePage "https://exampleapp.com" -IdentifierUris "https://exampleapp1.com/ExampleFunctionsAccount" -Password "<same password as defined earlier>"
    New-AzADServicePrincipal -ApplicationId $app.ApplicationId
    Start-Sleep 15]
    New-AzRoleAssignment -RoleDefinitionName Contributor -ServicePrincipalName $app.ApplicationId
    

    注意

    创建该应用程序时使用的密码应与之前保存密钥文件时创建的密码相同。

  2. 在 Azure 门户中,选择“订阅”。 选择要使用的订阅,然后选择“访问控制(IAM)”

  3. 选择要使用的帐户,然后选择“属性”。 复制应用程序 ID。

AzureTenant

请通过运行以下 PowerShell cmdlet 来获取租户 ID:

(Get-AzSubscription -SubscriptionName "<subscriptionName>").TenantId

AzureCredPassword

AzureCredPassword 环境变量的值是通过运行以下 PowerShell 示例获得的值。 此示例与之前配置身份验证部分所示的示例相同。 所需的值是 $Encryptedpassword 变量的输出。 此输出是使用 PowerShell 脚本加密的服务主体密码。

#Variables
$keypath = "C:\temp\PassEncryptKey.key"
$AESKey = New-Object Byte[] 32
$Password = "<insert a password here>"

#Keys
[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($AESKey) 
Set-Content $keypath $AESKey

#Get encrypted password
$secPw = ConvertTo-SecureString -AsPlainText $Password -Force
$AESKey = Get-content $KeyPath
$Encryptedpassword = $secPw | ConvertFrom-SecureString -Key $AESKey
$Encryptedpassword

存储环境变量

若要存储环境变量,请执行以下操作:

  1. 转到函数应用。 选择“配置”>“应用程序设置”。

    Screenshot of the tab for application settings.

  2. 将环境变量及其值添加到应用设置,然后选择“保存”

将 PowerShell 添加到函数

现在,从 Azure 函数内部调用网络观察程序。 根据要求,此函数的实现有所不同。 但是,代码的常规流程如下所示:

  1. 处理输入参数。
  2. 查询现有的数据包捕获,验证限制并解决名称冲突。
  3. 使用适当的参数创建数据包捕获。
  4. 定期轮询数据包捕获,直到完成。
  5. 通知用户数据包捕获会话已完成。

以下示例是可在函数中使用的 PowerShell 代码。 你需要替换 subscriptionIdresourceGroupNamestorageAccountName 的值。

# Input bindings are passed in via parameter block 
param($Request, $TriggerMetadata) 

$essentials = $Request.body.data.essentials
$alertContext = $Request.body.data.alertContext 


# Storage account ID to save captures in 
$storageaccountid = "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Storage/storageAccounts/{storageAccountName}" 

# Packet capture variables 
$packetCaptureName = "PSAzureFunction" 
$packetCaptureLimit = 100
$packetCaptureDuration = 30 

# Credentials 
# Set the credentials in the configurations
$tenant = $env:AzureTenant 
$pw = $env:AzureCredPassword 
$clientid = $env:AzureClientId 
$password = ConvertTo-SecureString $pw -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential ($clientid, $password)

Connect-AzAccount -ServicePrincipal -Tenant $tenant -Credential $credential #-WarningAction SilentlyContinue | out-null

if ($alertContext.condition.allOf.metricNamespace -eq "Microsoft.Compute/virtualMachines") { 

    # Get the VM firing this alert 
    $vm = Get-AzVM -ResourceId $essentials.alertTargetIDs[0] 

    # Get the Network Watcher instance in the VM's region 
    $networkWatcher = Get-AzNetworkWatcher -Location $vm.Location  

    # Get existing packet captures 
    $packetCaptures = Get-AzNetworkWatcherPacketCapture -NetworkWatcher $networkWatcher 

    # Remove an existing packet capture created by the function (if it exists) 
    $packetCaptures | ForEach-Object { if ($_.Name -eq $packetCaptureName) 
        {  
            Remove-AzNetworkWatcherPacketCapture -NetworkWatcher $networkWatcher -PacketCaptureName $packetCaptureName 
        } 
    } 
  
    # Initiate packet capture on the VM that fired the alert 
    if ($packetCaptures.Count -lt $packetCaptureLimit) { 
        Write-Output "Initiating Packet Capture" 
        New-AzNetworkWatcherPacketCapture -NetworkWatcher $networkWatcher -TargetVirtualMachineId $vm.Id -PacketCaptureName $packetCaptureName -StorageAccountId $storageaccountid -TimeLimitInSeconds $packetCaptureDuration 
    } 
} 

如果使用的是旧架构,请使用以下 PowerShell 代码:

# Input bindings are passed in via parameter block 
param($Request, $TriggerMetadata)
$details = $Request.RawBody | ConvertFrom-Json


# Process alert request body 
$requestBody = $Request.Body.data

# Storage account ID to save captures in 
$storageaccountid = "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Storage/storageAccounts/{storageAccountName}" 

# Packet capture variables 
$packetCaptureName = "PSAzureFunction" 
$packetCaptureLimit = 100
$packetCaptureDuration = 30 

# Credentials 
# Set the credentials in the configurations
$tenant = $env:AzureTenant 
$pw = $env:AzureCredPassword 
$clientid = $env:AzureClientId 

$password = ConvertTo-SecureString $pw -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential ($clientid, $password)

Connect-AzAccount -ServicePrincipal -Tenant $tenant -Credential $credential #-WarningAction SilentlyContinue | out-null

if ($requestBody.context.resourceType -eq "Microsoft.Compute/virtualMachines") { 

    # Get the VM firing this alert 
    $vm = Get-AzVM -ResourceGroupName $requestBody.context.resourceGroupName -Name $requestBody.context.resourceName 

    # Get the Network Watcher instance in the VM's region 
    $networkWatcher = Get-AzNetworkWatcher -Location $vm.Location  

    # Get existing packet captures 
    packetCaptures = Get-AzNetworkWatcherPacketCapture -NetworkWatcher $networkWatcher 

    # Remove an existing packet capture created by the function (if it exists) 
    $packetCaptures | ForEach-Object { if ($_.Name -eq $packetCaptureName) 
        {  
            Remove-AzNetworkWatcherPacketCapture -NetworkWatcher $networkWatcher -PacketCaptureName $packetCaptureName 
        } 
    } 

    # Initiate packet capture on the VM that fired the alert 
    if ($packetCaptures.Count -lt $packetCaptureLimit) { 
        Write-Output "Initiating Packet Capture" 
        New-AzNetworkWatcherPacketCapture -NetworkWatcher $networkWatcher -TargetVirtualMachineId $requestBody.context.resourceId -PacketCaptureName $packetCaptureName -StorageAccountId $storageaccountid -TimeLimitInSeconds $packetCaptureDuration 
    } 
}                               

在 VM 上配置警报

你可以配置警报,以便在特定的指标超过分配的阈值时通知相关人员。 在此示例中,警报位于已发送的“网络流出量总计”指标上,但你也可以针对许多其他指标触发该警报

创建警报规则

转到现有虚拟机并添加警报规则。 在“创建警报规则”页面上,执行以下步骤:

  1. 在“选择信号”窗格中,搜索信号的名称并将其选中。 在此示例中,“网络流出量总计”是所选信号。 它表示虚拟机在所有网络接口上传出的字节数。

  2. 在“条件”选项卡中,设置以下值,然后选择“下一步: 操作”。

    设置
    阈值 静态
    聚合类型 平均值
    “运算符” 大于
    阈值 3
    检查间隔 1 分钟
    回溯期间 5 分钟
  3. 在“操作”选项卡中,选择“创建操作组”

  4. 在“创建操作组”页面上,选择“订阅”、“资源组”和“区域”的值。 另请输入操作组名称和显示名称,然后选择“下一步: 通知”

  5. 在“通知”选项卡上,对于“操作类型”,请选择“Azure 函数”

  6. 在“Azure 函数”窗格中,选择“订阅”、“资源组”、“函数应用”和“Azure 函数”的值

    Screenshot of the page for creating an action group and the pane for details about an Azure function.

  7. 在“启用常见警报架构”滑块中,选择“否”。 然后选择确定

查看结果

在相应条件触发警报后,网络观察程序将创建数据包捕获。 转到网络观察程序,然后选择“数据包捕获”。 在此页面上,可以选择文件链接以下载数据包捕获。

如果捕获文件存储在本地,可以通过登录到虚拟机来获取该文件。

有关通过 Azure 存储帐户下载文件的说明,请参阅有关适用于 .NET 的 Azure Blob 存储客户端库的快速入门。 你也可以使用 Azure 存储资源管理器工具。

下载捕获后,可以使用 Wireshark 等可以读取 .cap 文件的工具来查看捕获。

下一步

请参阅检查和分析网络观察程序数据包捕获文件,了解如何查看数据包捕获。