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

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

可以通过 Azure Functions 等其他自动化方案远程启动此功能。 数据包捕获提供基于定义的网络异常运行主动捕获的功能。 其他用途包括收集网络统计信息、获取有关网络入侵的信息、调试客户端通信等等。

Azure 中部署的资源全天候运行。 但你和你的同事无法全天候主动监视所有资源的状态。 例如,如果凌晨 2 点出现问题,会发生什么情况?

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

关系图显示了虚拟机上的网络观察程序扩展,该扩展流向“发送的TCP 段数 > 100”错误,该错误流向 Azure Functions,后者流向网络观察程序扩展。

备注

本文已经过更新,以便使用 Azure Az PowerShell 模块。 若要与 Azure 交互,建议使用的 PowerShell 模块是 Az PowerShell 模块。 若要开始使用 Az PowerShell 模块,请参阅安装 Azure PowerShell。 若要了解如何迁移到 Az PowerShell 模块,请参阅 将 Azure PowerShell 从 AzureRM 迁移到 Az

先决条件

方案

在本示例中,VM 发送的 TCP 段数比平常多,因此你希望收到相关警报。 此处所示的 TCP 段只是用作示例,但可以使用任何警报条件。

收到警报时,希望收到数据包级别的数据,了解通信量为何提高。 然后,便可以采取措施让虚拟机恢复日常通信。

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

以下列表了提供发生的工作流概述:

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

为了自动完成此过程,我们在 VM 上创建并连接了一个发生事件时要触发的警报。 还创建了用于调入网络观察程序的函数。

此方案执行以下任务:

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

创建 Azure 函数

第一步是创建一个 Azure 函数来处理警报并创建数据包捕获。

  1. Azure 门户中,选择“创建资源” > “虚拟机” > “函数应用”。

    创建一个函数应用

  2. 在“Function App”边栏选项卡中输入以下值,然后选择“确定”以创建应用 :

    设置 详细信息
    应用名称 PacketCaptureExample 函数应用的名称。
    订阅 [订阅]要为其创建函数应用的订阅。
    资源组 PacketCaptureRG 包含函数应用的资源组。
    托管计划 消耗计划 函数应用使用的计划类型。 选项包括“使用计划”或“Azure 应用服务计划”。
    位置 中国北部 要在其中创建函数应用的区域。
    存储帐户 {autogenerated} Azure Functions 需用于常规存储的存储帐户。
  3. 在 Function Apps 的“PacketCaptureExample”边栏选项卡上,选择“函数” > “自定义函数” >“+” 。

  4. 选择“HttpTrigger-Powershell”,然后输入其余信息。 最后,选择“创建”以创建函数。

    设置 详细信息
    方案 实验 方案的类型
    为函数命名 AlertPacketCapturePowerShell 函数的名称
    授权级别 函数 函数的授权级别

    函数示例

备注

PowerShell 模板处于试验阶段且没有完全支持。

自定义项是此示例所必需的,并在以下步骤中说明。

添加模块

若要使用网络观察程序 PowerShell cmdlet,将最新 PowerShell 模块上传到函数应用。

  1. 在已安装最新 Azure PowerShell 模块的本地计算机上,运行以下 PowerShell 命令:

    (Get-Module Az.Network).Path
    

    该示例提供 Azure PowerShell 模块的本地路径。 在稍后的步骤中将使用这些文件夹。 此方案中使用的模块包括:

    • Az.Network

    • Az.Accounts

    • Az.Resources

      PowerShell 文件夹

  2. 选择“函数应用设置” > “转到应用服务编辑器” 。

    函数应用设置

  3. 右键单击 AlertPacketCapturePowershell 文件夹,然后创建一个名为 azuremodules 的文件夹 。

  4. 为每个所需模块创建子文件夹。

    文件夹和子文件夹

    • Az.Network

    • Az.Accounts

    • Az.Resources

  5. 右键单击“Az.Network”子文件夹,然后选择“上传文件” 。

  6. 转到 Azure 模块。 在本地“Az.Network”文件夹中,选择文件夹中的所有文件。 然后选择“确定”。

  7. Az.AccountsAz.Resources 重复执行上述步骤。

    上传文件

  8. 完成后,每个文件夹应具有来自本地计算机的 PowerShell 模块文件。

    PowerShell 文件

身份验证

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

备注

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

加密凭据

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

#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

在函数应用的应用服务编辑器中,在 AlertPacketCapturePowerShell 下创建一个名为 keys 的文件夹 。 然后上传在之前的 PowerShell 示例中创建的 PassEncryptKey.key。

函数密钥

检索环境变量的值

最后一项要求是设置访问用于身份验证的值所必需的环境变量。 以下列表显示创建的环境变量:

  • AzureClientID

  • AzureTenant

  • AzureCredPassword

AzureClientID

客户端 ID 是 Azure Active Directory 中应用程序的应用程序 ID。

  1. 如果还没有可使用的应用程序,请运行以下示例创建应用程序。

    $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)”。

    函数 IAM

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

    函数应用程序 ID

AzureTenant

通过运行以下 PowerShell 示例获取租户 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. 转到函数应用。 然后选择“函数应用设置” > “配置应用设置” 。

    配置应用设置

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

    应用设置

将 PowerShell 添加到函数

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

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

以下示例为 PowerShell 代码,可在函数中使用。 存在需要为 subscriptionId、resourceGroupName 和 storageAccountName 替换的值 。

#Import Azure PowerShell modules required to make calls to Network Watcher
Import-Module "D:\home\site\wwwroot\AlertPacketCapturePowerShell\azuremodules\Az.Accounts\Az.Accounts.psd1" -Global
Import-Module "D:\home\site\wwwroot\AlertPacketCapturePowerShell\azuremodules\Az.Network\Az.Network.psd1" -Global
Import-Module "D:\home\site\wwwroot\AlertPacketCapturePowerShell\azuremodules\Az.Resources\Az.Resources.psd1" -Global

#Process alert request body
$requestBody = Get-Content $req -Raw | ConvertFrom-Json

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

#Packet capture vars
$packetcapturename = "PSAzureFunction"
$packetCaptureLimit = 10
$packetCaptureDuration = 10

#Credentials
$tenant = $env:AzureTenant
$pw = $env:AzureCredPassword
$clientid = $env:AzureClientId
$keypath = "D:\home\site\wwwroot\AlertPacketCapturePowerShell\keys\PassEncryptKey.key"

#Authentication
$secpassword = $pw | ConvertTo-SecureString -Key (Get-Content $keypath)
$credential = New-Object System.Management.Automation.PSCredential ($clientid, $secpassword)
Connect-AzAccount -Environment AzureChinaCloud -ServicePrincipal -Tenant $tenant -Credential $credential #-WarningAction SilentlyContinue | out-null

#Get the VM that fired the alert
if($requestBody.context.resourceType -eq "Microsoft.Compute/virtualMachines")
{
    Write-Output ("Subscription ID: {0}" -f $requestBody.context.subscriptionId)
    Write-Output ("Resource Group:  {0}" -f $requestBody.context.resourceGroupName)
    Write-Output ("Resource Name:  {0}" -f $requestBody.context.resourceName)
    Write-Output ("Resource Type:  {0}" -f $requestBody.context.resourceType)

    #Get the Network Watcher in the VM's region
    $networkWatcher = Get-AzResource | Where {$_.ResourceType -eq "Microsoft.Network/networkWatchers" -and $_.Location -eq $requestBody.context.resourceRegion}

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

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

    #Initiate packet capture on the VM that fired the alert
    if ((Get-AzNetworkWatcherPacketCapture -NetworkWatcher $networkWatcher).Count -lt $packetCaptureLimit){
        echo "Initiating Packet Capture"
        New-AzNetworkWatcherPacketCapture -NetworkWatcher $networkWatcher -TargetVirtualMachineId $requestBody.context.resourceId -PacketCaptureName $packetCaptureName -StorageAccountId $storageaccountid -TimeLimitInSeconds $packetCaptureDuration
        Out-File -Encoding Ascii -FilePath $res -inputObject "Packet Capture created on ${requestBody.context.resourceID}"
    }
} 

检索函数 URL

  1. 创建函数后,请将警报配置为调用与该函数相关联的 URL。 若要获取此值,请从 Function App 中复制函数 URL。

    查找函数 URL

  2. 复制函数应用的函数 URL。

    复制函数 URL

如果需要在 webhook POST 请求的有效负载中使用自定义属性,请参阅针对 Azure 指标警报配置 webhook

在 VM 上配置警报

可以配置警报,以便在特定的指标超过分配的阈值时通知相关人员。 在本示例中,警报是针对 TCP 段发送的,但也可以从其他许多指标触发该警报。 在本示例中,已将某个警报配置为调用 Webhook 来调用函数。

创建警报规则

转到现有虚拟机,然后添加警报规则。 有关配置警报的更详细文档,请参阅在 Azure Monitor 中为 Azure 服务创建警报 - Azure 门户。 在“警报规则”边栏选项卡中输入以下值,然后选择“确定” 。

设置 详细信息
名称 TCP_Segments_Sent_Exceeded 警报规则的名称。
说明 发送的 TCP 段已超出阈值 警报规则的说明。
指标 发送的 TCP 段 用于触发警报的指标。
条件 大于 评估指标时要使用的条件。
阈值 100 触发警报的指标值。 此值应设置为环境的有效值。
时间段 过去五分钟 确定要在其中查找指标阈值的时间段。
Webhook [函数应用中的 Webhook URL] 来自前面步骤创建的函数应用的 Webhook URL。

备注

默认情况下不启用 TCP 段计量。 请访问启用监视和诊断,详细了解如何启用其他指标。

查看结果

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

查看数据包捕获

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

有关从 Azure 存储帐户下载文件的说明,请参阅通过 .NET 开始使用 Azure Blob 存储。 另一个可以使用的工具是存储资源管理器

下载捕获后,可以使用能够读取 .cap 文件的任何工具来查看捕获。 下面提供了其中两个工具的链接:

后续步骤

访问使用 Wireshark 分析数据包捕获,了解如何查看数据包捕获