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

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

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

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

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

注意

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

先决条件

场景

在本示例中,虚拟机 (VM) 的传出流量比平常多,并且你希望收到相关警报。 同样,可以为任何条件创建警报。

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

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

触发警报时发生的以下工作流:

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

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

此方案执行以下任务:

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

创建 Azure 函数应用

如需创建一个 Azure 函数来处理警报并创建数据包捕获,请执行以下步骤:

  1. 登录 Azure 门户

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

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

  3. 选择“+ 新建”。

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

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

    Screenshot of the Create function app page in the Azure portal.

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

创建 Azure 函数

  1. 在创建的函数应用中的“函数”选项卡中,选择“创建”以打开“创建函数”窗格。

    Screenshot of the Create function screen.

  2. 在门户中,从“开发环境”下拉列表中选择“在门户中开发”。

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

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

    • 在“新建函数”字段中输入函数的名称。
    • 选择“函数”作为“授权级别”,然后选择“创建”。
  5. 创建函数后,转到函数并选择“代码 + 测试”。

    Screenshot of the Code + Test screen.

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

身份验证

若要使用 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

检索环境变量的值

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

  • AzureClientID
  • AzureTenant
  • AzureCredPassword

如果已有应用程序 ID,请使用该应用程序的 AzureClientID、AzureTenant 和 AzureCredPassword。 如果没有,请继续存储环境变量

AzureClientID

客户端 ID 是 Azure Active Directory 中应用程序的应用程序 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 Application settings screen.

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

将 PowerShell 添加到函数

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

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

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

# Input bindings are passed in via param 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 vars 
$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 -Environment AzureChinaCloud -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 in the VM's region 
    $networkWatcher = Get-AzNetworkWatcher -Location $vm.Location  

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

    # Remove 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 param 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 vars 
$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 -Environment AzureChinaCloud -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 in the VM's region 
    $networkWatcher = Get-AzNetworkWatcher -Location $vm.Location  

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

    # Remove 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 Create action group screen.

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

查看结果

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

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

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

下载捕获后,可以使用可读取 .cap 文件的工具(例如 Microsoft 消息分析器WireShark)进行查看。

下一步

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