パケット キャプチャを使用する Azure Functions とアラートでネットワークをプロアクティブに監視する

Azure Network Watcher のパケット キャプチャ機能は、仮想マシン (VM) との間のトラフィックを追跡するためのキャプチャ セッションを作成します。 キャプチャ ファイルには、監視するトラフィックのみを追跡するために定義したフィルターを設定できます。 このデータは、ストレージ BLOB に格納されるか、ローカルのゲスト マシンに格納されます。

この機能は、Azure Functions などの他の自動化シナリオからリモートで開始できます。 定義済みのネットワーク異常に基づいてプロアクティブ キャプチャを実行できます。 その他の用途には、ネットワーク統計の収集、ネットワークへの侵入に関する情報を取得、クライアント サーバー間の通信のデバッグがあります。

Azure でデプロイされたリソースは、継続的に実行されます。 すべてのリソースの状態を四六時中監視することは困難です。 たとえば、午前 2 00 時に問題が発生した場合はどうなりますか?

Azure エコシステム内部から Network Watcher のアラートと関数を使うことにより、データとツールでプロアクティブに対応してネットワークの問題を解決できます。

前提条件

シナリオ

この例では、仮想マシン (VM) の送信トラフィックが通常よりも多く、アラートを受け取る必要がある場合です。 同様のプロセスを使用して、任意の条件のアラートを作成できます。

インシデントによってアラートがトリガーされると、パケット レベルのデータは、送信トラフィックが増加した理由を分析するのに役立ちます。 仮想マシンを元の状態に戻すための手順を実行できます。

このシナリオでは、Network Watcher の既存のインスタンスと、有効な仮想マシンが含まれるリソース グループがあることを前提としています。

パケット キャプチャのワークフローを次に示します:

  1. インシデントによってお使いの VM でアラートがトリガーされます。
  2. アラートが Azure 関数を呼び出す。
  3. Azure 関数がアラートを処理し、Network Watcher のパケット キャプチャ セッションを開始する。
  4. パケット キャプチャが VM で実行され、データが収集される。
  5. パケット キャプチャ ファイルが確認と診断のためにストレージ アカウントにアップロードされる。

このプロセスを自動化するには、インシデントが発生したときにトリガーされるアラートをお使いの VM で作成して接続します。 また、Network Watcher を呼び出す関数を作成します。

このシナリオは次のとおりです。

  • パケット キャプチャを開始する Azure 関数を作成する。
  • 仮想マシンでアラート ルールを作成し、Azure 関数を呼び出すようにアラート ルールを構成する。

Azure 関数の作成

アラートを処理してパケット キャプチャを作成する Azure 関数を作成するには、まず関数アプリを作成する必要があります:

  1. Azure portal にサインインします。

  2. ポータルの上部にある検索ボックスに、「関数アプリ」と入力します。 検索結果から [関数アプリ] を選択します。

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

  3. [+ 作成] を選択します。

  4. [関数アプリの作成][基本] タブで、次の設定の値を入力または選択します:

    • [プロジェクトの詳細] で、関数アプリを作成するサブスクリプションと、そのアプリを含むリソース グループを選択します。
    • [インスタンスの詳細] で:
      • [関数アプリ名] に、関数アプリの名前を入力します。 この名前には .azurewebsites.net が追加されます。
      • [コードまたはコンテナー イメージをデプロイしますか?] では、発行モード ([コード] または [コンテナー イメージ]) を選択します。
      • ランタイム スタックの場合は、ランタイム スタックを選択します。
      • [バージョン] では、ランタイム スタックのバージョンを選択します。
      • [リージョン] では、関数アプリを作成するリージョンを選択します。
    • [オペレーティング システム] で、現在使用しているオペレーティング システムの種類を選択します。 Azure では、ランタイム スタックの選択に基づいて、オペレーティング システムの種類を提案します。
    • [ホスティング] で、関数アプリに使用するプランの種類を選択します。 次のオプションから選択します。
      • 従量課金 (サーバーレス): 最小コストでイベント駆動型のスケーリングを行う場合。
      • Functions Premium - イベントベースのスケーリングとネットワークの分離を備えた、エンタープライズレベルのサーバーレス アプリケーションの場合。
      • App Service プラン - 既存の App Service プランからコンピューティングを再利用する場合。

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

  5. [確認および作成] を選択してアプリを作成します。

これで、関数を作成できます:

  1. 作成した関数アプリの [関数] タブで、[作成] を選択して、次に [関数の作成] ペインを開きます。

    Screenshot of the Create function pane.

  2. [開発環境] で、[Develop in portal](ポータルで開発) を選択します。

  3. [テンプレートの選択] で、[HTTP トリガー] を選択します。

  4. [テンプレートの詳細] セクションで、次の操作を行います。

    • [新しい関数]には、関数の名前を入力します。
    • [認証レベル] では [関数] を選びます。
  5. [作成] を選択します

  6. 作成した関数に移動し、[コード + テスト ] を選択します。

    Screenshot of the Code + Test page for a function.

  7. スクリプトを更新し、[保存] を選択します。

認証を構成する

PowerShell コマンドレットを使用するには、関数アプリで認証を構成する必要があります。 認証を構成するには、環境変数を構成して、暗号化されたキー ファイルを Function App にアップロードする必要があります。

注意

このシナリオでは、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. 使うアプリケーションがまだない場合は、次のコマンドレットを実行してアプリケーションを作成します:

    $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
    

    Note

    アプリケーション作成時に使うパスワードは、前にキー ファイルを保存したときに作成したものと同じパスワードにする必要があります。

  2. Azure Portal で、 [サブスクリプション] を選びます。 使うサブスクリプションを選び、[アクセス制御 (IAM)] を選びます。

  3. 使うアカウントを選び、[プロパティ] を選びます。 アプリケーション 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. Function App に移動します。 [構成]>[アプリケーション設定] の順に選択します。

    Screenshot of the tab for application settings.

  2. 環境変数とその値をアプリの設定に追加し、[保存] を選びます。

関数への PowerShell の追加

ここで、Azure 関数の内部から Network Watcher を呼び出します。 この関数の実装は、要件によって異なる場合があります。 ただし、コードの一般的なフローは次のようになります。

  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 のアラートの構成

特定のメトリックが割り当てたしきい値を超えたときに個人に通知するようにアラートを構成できます。 この例では、アラートは送信された Network Out Total メトリック上にありますが、他の多くのメトリックに対してアラートをトリガーできます。

アラート ルールの作成

既存の仮想マシンに移動して、アラート ルールを追加します[アラート ルールの作成] ページで、次の手順を実行します:

  1. [シグナルの選択] ペインで、シグナルの名前を検索して選択します。 この例では、Network Out Total が選択されたシグナルです。 これは、すべてのネットワーク インターフェイスで仮想マシンが送信したバイト数を意味します。

  2. [条件] タブで、次の値を設定し、[次へ: アクション] を選択します。

    設定 Value
    しきい値 スタティック
    集計の種類 Average
    [オペレーター] より大きい
    しきい値 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. [共通アラート スキーマの有効化] スライダーで、[いいえ] を選択します。 [OK] をクリックします。

結果の確認

条件によってアラートがトリガーされると、Network Watcher によってパケット キャプチャが作成されます。 Network Watcher に移動し、[パケット キャプチャ] を選びます。 このページでは、パッケージ キャプチャをダウンロードするファイル リンクを選択することができます。

キャプチャ ファイルがローカルに格納されている場合は、仮想マシンにサインインすることで取得できます。

Azure ストレージ アカウントからファイルをダウンロードする手順については、.NET 用 Azure Blob Storage クライアント ライブラリのクイック スタートを参照してください。 Azure Storage Explorer ツールを使用することもできます。

キャプチャをダウンロードした後、.cap ファイルを読み取ることができる Wireshark などのツールを使用して表示できます。

次のステップ

パケット キャプチャを表示する方法については、「Network Watcher パケット キャプチャ ファイルの検査と分析」を参照してください。