てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Azure] Azure CLI が叩いてる REST API のリクエストやレスポンスを確認する方法(--debug、ログファイル有効化)

はじめに

Azure 情報さまざまなリソースをコマンドラインで操作できる Azure CLI というツールがあります。

裏では Azure REST API を叩いていたりするようです。ときどき、Azure CLI による操作がどういう API を叩いてるのか(エンドポイント、ボディ)、どういうレスポンスが返ってきているのか気になることがあります。

プロキシ的なツールを挟んでパケットキャプチャする方法もありますが、もっと手軽に確認する方法ないかなと思って調べてみると、Azure CLI 側のデバッグ的な機能でできるようでした。

調べた限り --debug オプションによる方法と、ログファイルの有効化の 2つの方法がありました。

それぞれ試してみた結果をまとめます。

  • 環境
    • azure-cli 2.43.0

方法1: --debug オプションの利用

az hogehoge コマンドに --debug オプションを付けると、さまざまなデバッグ情報が表示されその中に、リクエストやレスポンスの情報がありました。

--debug 使用例

以下のコマンドは、既存のネットワークセキュリティグループ nsg01 に対して、description を設定する例です。表面上はマージ的な操作です。例によって --debug もつけます。

az network nsg rule update -g sakana --nsg-name nsg01 \
    -n rule999 --description desc999 --debug

(参考: az network nsg rule のリファレンス

以下、実行して表示されたログを抜粋して、部分ごとに考察します。

(GET のリクエスト、レスポンス、PUT のリクエスト、レスポンス)

GET のリクエス

以下のように、ネットワークセキュリティグループ nsg01 のルール rule999 の情報を GET する様子を確認しました。

cli.azure.cli.core.sdk.policies: Request URL: 'https://management.azure.com/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/sakana/providers/Microsoft.Network/networkSecurityGroups/nsg01/securityRules/rule999?api-version=2022-01-01'
cli.azure.cli.core.sdk.policies: Request method: 'GET'
cli.azure.cli.core.sdk.policies: Request headers:
cli.azure.cli.core.sdk.policies:     'Accept': 'application/json'
cli.azure.cli.core.sdk.policies:     'x-ms-client-request-id': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
cli.azure.cli.core.sdk.policies:     'CommandName': 'network nsg rule update'
cli.azure.cli.core.sdk.policies:     'ParameterSetName': '-g --nsg-name -n --description --debug'
cli.azure.cli.core.sdk.policies:     'User-Agent': 'AZURECLI/2.43.0 (PIP) (AAZ) azsdk-python-core/1.26.2 Python/3.9.16 (macOS-12.6-x86_64-i386-64bit)'
cli.azure.cli.core.sdk.policies:     'Authorization': '*****'
cli.azure.cli.core.sdk.policies: Request body:
cli.azure.cli.core.sdk.policies: This request has no body
urllib3.connectionpool: Starting new HTTPS connection (1): management.azure.com:443

なぜ 事前に GET するかの考察

対応する API リファレンスは Security Rules - Get

セキュリティルールに関するリファレンスを確認すると、特定の設定項目のみをマージ、つまり PATCH する方法はありませんでした。できるのは PUTです。

PUT するには設定差分の情報だけでなく、該当ルールの情報一式(directionpriority など)が必要です。そうしないと、API 使用上必須のパラメーターが不足して設定できなかったり(400 Bad Request)、設定がデフォルトに戻ったりしてしまいます。

一方で、az network nsg rule update コマンドとしては、キーとなる情報(-g--nsg-name-n )以外は、設定差分(今回は --description )しか指定していません。そのため、他の必要な情報一式を取得するために事前に GET しているのかなと思いました。

ヘッダーについての補足

リクエストヘッダーについては、あくまで Azure CLI 側が付加するものだけが表示されてるようでした。プロキシツールを併用してパケットキャプチャしたところ、他にもたとええば以下のような基本的なヘッダーも付加されてることを確認しました。

Host: management.azure.com
Connection: keep-alive

なお、'Authorization': '*****' は、ブログ用にマスクしたのではなく、もともとマスクされて表示されました。

GET に対するレスポンス

先ほどの GET するリクエストに続いて、以下のレスポンスのログが表示されました。Response content のところで、レスポンスのボディがあります。

urllib3.connectionpool: https://management.azure.com:443 "GET /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/sakana/providers/Microsoft.Network/networkSecurityGroups/nsg01/securityRules/rule999?api-version=2022-01-01 HTTP/1.1" 200 None
cli.azure.cli.core.sdk.policies: Response status: 200
cli.azure.cli.core.sdk.policies: Response headers:
cli.azure.cli.core.sdk.policies:     'Cache-Control': 'no-cache'
cli.azure.cli.core.sdk.policies:     'Pragma': 'no-cache'
cli.azure.cli.core.sdk.policies:     'Transfer-Encoding': 'chunked'
cli.azure.cli.core.sdk.policies:     'Content-Type': 'application/json; charset=utf-8'
cli.azure.cli.core.sdk.policies:     'Content-Encoding': 'gzip'
cli.azure.cli.core.sdk.policies:     'Expires': '-1'
cli.azure.cli.core.sdk.policies:     'ETag': 'W/"XXXXXXXX-xxxx-xxxx-xxxx-xxxxxxxxxxxx"'
cli.azure.cli.core.sdk.policies:     'Vary': 'Accept-Encoding'
cli.azure.cli.core.sdk.policies:     'x-ms-request-id': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
cli.azure.cli.core.sdk.policies:     'x-ms-correlation-request-id': 'xxxxxxxx-XXXX-xxxx-xxxx-xxxxxxxxxxxx'
cli.azure.cli.core.sdk.policies:     'x-ms-arm-service-request-id': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
cli.azure.cli.core.sdk.policies:     'Strict-Transport-Security': 'max-age=31536000; includeSubDomains'
cli.azure.cli.core.sdk.policies:     'Server': 'Microsoft-HTTPAPI/2.0, Microsoft-HTTPAPI/2.0'
cli.azure.cli.core.sdk.policies:     'x-ms-ratelimit-remaining-subscription-reads': '11999'
cli.azure.cli.core.sdk.policies:     'x-ms-routing-request-id': 'JAPANEAST:20230108T132147Z:xxxxxxxx-XXXX-xxxx-xxxx-xxxxxxxxxxxx'
cli.azure.cli.core.sdk.policies:     'X-Content-Type-Options': 'nosniff'
cli.azure.cli.core.sdk.policies:     'Date': 'Sun, 08 Jan 2023 13:21:46 GMT'
cli.azure.cli.core.sdk.policies: Response content:
cli.azure.cli.core.sdk.policies: {
  "name": "rule999",
  "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/sakana/providers/Microsoft.Network/networkSecurityGroups/nsg01/securityRules/rule999",
  "etag": "W/\"XXXXXXXX-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"",
  "type": "Microsoft.Network/networkSecurityGroups/securityRules",
  "properties": {
    "provisioningState": "Succeeded",
    "protocol": "Tcp",
    "sourcePortRange": "*",
    "destinationPortRange": "443",
    "sourceAddressPrefix": "203.0.113.0/24",
    "destinationAddressPrefix": "*",
    "access": "Allow",
    "priority": 999,
    "direction": "Inbound",
    "sourcePortRanges": [],
    "destinationPortRanges": [],
    "sourceAddressPrefixes": [],
    "destinationAddressPrefixes": []
  }
}

update 前の設定情報なので、まだ description はありません。

PUT のリクエス

いよいよ、実際の設定変更のための PUT です。

cli.azure.cli.core.sdk.policies: Request URL: 'https://management.azure.com/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/sakana/providers/Microsoft.Network/networkSecurityGroups/nsg01/securityRules/rule999?api-version=2022-01-01'
cli.azure.cli.core.sdk.policies: Request method: 'PUT'
cli.azure.cli.core.sdk.policies: Request headers:
cli.azure.cli.core.sdk.policies:     'Content-Type': 'application/json'
cli.azure.cli.core.sdk.policies:     'Accept': 'application/json'
cli.azure.cli.core.sdk.policies:     'Content-Length': '496'
cli.azure.cli.core.sdk.policies:     'x-ms-client-request-id': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
cli.azure.cli.core.sdk.policies:     'CommandName': 'network nsg rule update'
cli.azure.cli.core.sdk.policies:     'ParameterSetName': '-g --nsg-name -n --description --debug'
cli.azure.cli.core.sdk.policies:     'User-Agent': 'AZURECLI/2.43.0 (PIP) (AAZ) azsdk-python-core/1.26.2 Python/3.9.16 (macOS-12.6-x86_64-i386-64bit)'
cli.azure.cli.core.sdk.policies:     'Authorization': '*****'
cli.azure.cli.core.sdk.policies: Request body:
cli.azure.cli.core.sdk.policies: {"id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/sakana/providers/Microsoft.Network/networkSecurityGroups/nsg01/securityRules/rule999", "name": "rule999", "properties": {"access": "Allow", "description": "desc999", "destinationAddressPrefix": "*", "destinationPortRange": "443", "direction": "Inbound", "priority": 999, "protocol": "Tcp", "sourceAddressPrefix": "203.0.113.0/24", "sourcePortRange": "*"}, "type": "Microsoft.Network/networkSecurityGroups/securityRules"}

対応する API リファレンスは Security Rules - Create Or Update

Request body のところで設定値が確認できます。わかりやすいようにここだけ整形して再掲します。

{
  "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/sakana/providers/Microsoft.Network/networkSecurityGroups/nsg01/securityRules/rule999",
  "name": "rule999",
  "properties": {
    "access": "Allow",
    "description": "desc999",
    "destinationAddressPrefix": "*",
    "destinationPortRange": "443",
    "direction": "Inbound",
    "priority": 999,
    "protocol": "Tcp",
    "sourceAddressPrefix": "203.0.113.0/24",
    "sourcePortRange": "*"
  },
  "type": "Microsoft.Network/networkSecurityGroups/securityRules"
}

事前に GET した情報に対して、az network nsg rule update コマンドの --description で指定した description をマージしたような内容になっています。

PUT に対するレスポンス

続いて、先ほどの PUT のに対するレスポンスが表示されました。

urllib3.connectionpool: https://management.azure.com:443 "PUT /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/sakana/providers/Microsoft.Network/networkSecurityGroups/nsg01/securityRules/rule999?api-version=2022-01-01 HTTP/1.1" 200 None
cli.azure.cli.core.sdk.policies: Response status: 200
cli.azure.cli.core.sdk.policies: Response headers:
cli.azure.cli.core.sdk.policies:     'Cache-Control': 'no-cache'
cli.azure.cli.core.sdk.policies:     'Pragma': 'no-cache'
cli.azure.cli.core.sdk.policies:     'Transfer-Encoding': 'chunked'
cli.azure.cli.core.sdk.policies:     'Content-Type': 'application/json; charset=utf-8'
cli.azure.cli.core.sdk.policies:     'Content-Encoding': 'gzip'
cli.azure.cli.core.sdk.policies:     'Expires': '-1'
cli.azure.cli.core.sdk.policies:     'Retry-After': '10'
cli.azure.cli.core.sdk.policies:     'Vary': 'Accept-Encoding'
cli.azure.cli.core.sdk.policies:     'x-ms-request-id': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
cli.azure.cli.core.sdk.policies:     'Azure-AsyncOperation': 'https://management.azure.com/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/providers/Microsoft.Network/locations/japaneast/operations/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx?api-version=2022-01-01'
cli.azure.cli.core.sdk.policies:     'x-ms-correlation-request-id': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
cli.azure.cli.core.sdk.policies:     'Azure-AsyncNotification': 'Enabled'
cli.azure.cli.core.sdk.policies:     'x-ms-arm-service-request-id': 'xxxxxxxx-xxxx-xxxx-XXXX-xxxxxxxxxxxx'
cli.azure.cli.core.sdk.policies:     'Strict-Transport-Security': 'max-age=31536000; includeSubDomains'
cli.azure.cli.core.sdk.policies:     'Server': 'Microsoft-HTTPAPI/2.0, Microsoft-HTTPAPI/2.0'
cli.azure.cli.core.sdk.policies:     'x-ms-ratelimit-remaining-subscription-writes': '1199'
cli.azure.cli.core.sdk.policies:     'x-ms-routing-request-id': 'JAPANEAST:20230108T132147Z:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
cli.azure.cli.core.sdk.policies:     'X-Content-Type-Options': 'nosniff'
cli.azure.cli.core.sdk.policies:     'Date': 'Sun, 08 Jan 2023 13:21:46 GMT'
cli.azure.cli.core.sdk.policies: Response content:
cli.azure.cli.core.sdk.policies: {
  "name": "rule999",
  "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/sakana/providers/Microsoft.Network/networkSecurityGroups/nsg01/securityRules/rule999",
  "etag": "W/\"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"",
  "type": "Microsoft.Network/networkSecurityGroups/securityRules",
  "properties": {
    "provisioningState": "Updating",
    "description": "desc999",
    "protocol": "Tcp",
    "sourcePortRange": "*",
    "destinationPortRange": "443",
    "sourceAddressPrefix": "203.0.113.0/24",
    "destinationAddressPrefix": "*",
    "access": "Allow",
    "priority": 999,
    "direction": "Inbound",
    "sourcePortRanges": [],
    "destinationPortRanges": [],
    "sourceAddressPrefixes": [],
    "destinationAddressPrefixes": []
  }
}

レスポンスコードは 200 でした。リファレンスによると 200 が更新、201 が作成とのことです。今回は既存のルールに description を設定するという更新なので 200 なのでしょう。

レスポンスボディには、更新後の結果が返ってきました。description も設定されています。

その他のリクエスト(処理の完了待ち)

ここまでのログでは省略しましたが、設定が完了したかどうか調べるようなリクエストもされていました。

--no-wait オプションをつけると、このリクエストをしなくなりました。

ここまでで、--debug オプションによるリクエストの内容を確認できました。

方法2: ログファイルの有効化

次は、az コマンドのオプションではなく、設定ファイルでログファイルを有効にして、そのファイルを確認する方法です。

ひと手間かかりますが、通常の出力とデバッグ出力を分けられる点では便利です。

設定の準備

デフォルトでは、az コマンドのログ情報はファイルに出力されません。出力させるには構成ファイル(デフォルト ~/.azure/config)での仕込みが必要です。

~/.azure/config:

[logging]
enable_log_file = true

上記の設定で、ファイル出力が有効になります。出力先ファイルはデフォルトでは ~/.azure/logs/ ディレクトリの az.log でした。ディレクトリは [logging] セクションの log_dir という設定項目で変更できます。

構成ファイル内の全項目はドキュメントを参照してください。

ログファイル有効化状態での実行例

前述のログファイル出力を有効化した状態で、az コマンドを実行します。

内容は --debug オプション利用時と同じく、既存のネットワークセキュリティグループ nsg01 に対して、description を設定する例です。

違いは --debug オプションを指定しないことです。

az network nsg rule update -g sakana --nsg-name nsg01 \
    -n rule999 --description desc999

実行結果の確認

コマンドの実行結果自体は通常と同じです。

~/.azure/logs/az.log を確認するとログが書き込まれていました。リクエストやレスポンスの内容の表示は --debug オプション利用時とおなじような感じなので、説明は省略します。時刻も載ってるところが特徴かなと思います。

...(略)...
2419 : 2023-01-09 20:09:04,748 : DEBUG : cli.azure.cli.core.sdk.policies : Request URL: 'https://management.azure.com/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/sakana/providers/Microsoft.Network/networkSecurityGroups/nsg01/securityRules/rule999?api-version=2022-01-01'
2419 : 2023-01-09 20:09:04,748 : DEBUG : cli.azure.cli.core.sdk.policies : Request method: 'GET'
2419 : 2023-01-09 20:09:04,748 : DEBUG : cli.azure.cli.core.sdk.policies : Request headers:
2419 : 2023-01-09 20:09:04,748 : DEBUG : cli.azure.cli.core.sdk.policies :     'Accept': 'application/json'
2419 : 2023-01-09 20:09:04,748 : DEBUG : cli.azure.cli.core.sdk.policies :     'x-ms-client-request-id': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
2419 : 2023-01-09 20:09:04,748 : DEBUG : cli.azure.cli.core.sdk.policies :     'CommandName': 'network nsg rule update'
2419 : 2023-01-09 20:09:04,748 : DEBUG : cli.azure.cli.core.sdk.policies :     'ParameterSetName': '-g --nsg-name -n --description'
2419 : 2023-01-09 20:09:04,748 : DEBUG : cli.azure.cli.core.sdk.policies :     'User-Agent': 'AZURECLI/2.43.0 (PIP) (AAZ) azsdk-python-core/1.26.2 Python/3.9.16 (macOS-12.6-x86_64-i386-64bit)'
2419 : 2023-01-09 20:09:04,748 : DEBUG : cli.azure.cli.core.sdk.policies :     'Authorization': '*****'
2419 : 2023-01-09 20:09:04,748 : DEBUG : cli.azure.cli.core.sdk.policies : Request body:
2419 : 2023-01-09 20:09:04,749 : DEBUG : cli.azure.cli.core.sdk.policies : This request has no body
...(略)...

おわりに

Azure CLI が裏で叩いてる REST API のリクエストとレスポンスを確認する方法として、

  • --debug オプションの利用
  • ログファイルの有効化

を試してみました。

Azure CLI を使っていて、これどうやってだろう?というときになったときに使っていきたいと思います。