🦑

Azure Resource GraphでKustoクエリを使いこなす!

2024/04/30に公開

はじめに

前回の記事では、Resource Graphを少しだけ触ってみました。
今回は、Resource Graphでよく使用するクエリ構文を紹介します。
前回の記事はこちら。
https://zenn.dev/choeurtap/articles/c1e231cd806882

Kustoとは

前回も紹介しましたが、Kusto Query Language(KQL)には以下の特徴があります。

  • 情報収集を目的とした、読み取り専用クエリ言語
  • 検索、結合、集計、グラフ化にも対応
  • 主にData Explorer、Resource Graph、Log Analyticsで使用

Kustoクエリをかく

今回はResource Graphでよく使用するクエリ構文を、レベル別に紹介します。
詳しく知りたい方はリファレンスをご覧になってください。
https://docs.microsoft.com/ja-jp/azure/data-explorer/kql-quick-reference

クエリ Lv.1

まずは基本。ほぼ必ず使うと言っていいでしょう。

where

  • 列(column)を指定し、条件に当てはまる行を抽出する
  • 構文:where <column> [演算子] "value"

文字列演算子

where構文は以下の文字列演算子をよく使います。

  • ===~
    • 等号。==はCase Strict(大文字小文字区別あり)、=~はなし
  • !=!~
    • 不等号。!=はCase Strict、!~はなし
  • has!has
    • 右辺の文字列を含む/含まない。has_cs!has_csとするとCase Strict

ほかにもいろいろありますが、上記3つを覚えておけば大丈夫でしょう。
https://docs.microsoft.com/ja-jp/azure/data-explorer/kusto/query/datatypes-string-operators

ケース判定は必要か?

Azureといえば大文字/小文字の区別をしなくて良い場合が多いですが、Resource Graphではばっちり区別されます。
ただし、小文字で定義したのにすべて大文字で出力されていることもよくあります。
理由がなければ=~を使いましょう。

sort

  • 列(column)を指定し、昇順(ascend)または降順(descend)に並び替える
  • 構文:sort by <column> <asc | dsc>

project

  • 列(column)を指定し、指定した列のみを表示する
    • project-away で指定以外の列を表示する
  • 構文:project <column1>, <column2>, <column3>, ...

実践 Lv.1

お題: 以下の条件でリソースを抽出しましょう

  • リソースタイプ:仮想マシン
    • typeが 'microsoft.compute/virtualmachines' であるものを抽出します。
  • リージョン:東日本リージョン
    • locationが 'japaneast' であるものを抽出します。
  • 名前:アルファベット順
    • sortで name を昇順に並べ替えます。
正解
1:  resources
2:  | where type =~ 'microsoft.compute/virtualmachines' //リソースタイプ:仮想マシン
3:  | where location =~ 'japaneast' //リージョン:東日本リージョン
4:  | sort by name asc //名前:アルファベット順

なお、リソースタイプとリージョンについては、and を使用することで1行にまとめることが可能です。

1:  resources
2:  | where type =~ 'microsoft.compute/virtualmachines' and location =~ 'japaneast'
3:  | sort by name asc

クエリ Lv.2

summarize

  • 列(column)を指定し、条件ごとに値をグループ化、集計する
  • : summerize [SummarizeParameters] by <column1>, <column2>, <column3>, ...

extend

  • 列の作成。propertyから取り出した値を定義する
  • : extend <newcolumn> = [definition]

propertyからの値取り出し

  • "."(ドット)でつなぎ、オブジェクト化された値を探索する
  • : <column>.<property1>.<property2>

実践 Lv.2

お題: 以下の条件でリソースを抽出しましょう

  • リソースタイプ:仮想マシン
  • リージョン:東日本リージョン
  • 順序:仮想マシンサイズ順
  • 仮想マシンサイズごとの台数を集計
    • 仮想マシンサイズをpropertyから取り出し、新規の列として定義します。

JSONを読み解く

propertyからの値取り出しは、ARMテンプレート(JSON)を読み解く必要があります。

クエリ実行結果右端の「詳細の表示」をクリック

仮想マシンサイズはproperties -> hardwareProfile -> vmSizeに格納されている。
properties.hardwareProfile.vmSizeとして取り出し可能。

正解
1:  resources
2:  | where type =~ 'microsoft.compute/virtualmachines'
3:  | where location =~ 'japaneast'
4:  | extend vmsize = properties.hardwareProfile.vmSize //仮想マシンサイズの列をvmsizeと定義
5:  | summarize count() by tostring(vmsize) //vmsizeを元に集計
6:  | sort by vmsize asc //並べ替え

クエリ Lv.3

mv-expand

  • 複数の値を含む列を展開し、データソースとして定義する。(Multi Value Expand)
  • : mv-expand <name> = <multi value column>

join

  • 2つのデータソース(table)を、共通の値をもつ列をキーに結合する
  • : join king=leftouter (<Table2>) on <CommonColumn>

作例(NSGのルールを展開)

mv-expand

 1:  // NSG - 送信元Anyの受信ルールを含む
 2:  resources
 3:  | where type =~ "microsoft.network/networksecuritygroups"
 4:  | mv-expand rules=properties.securityRules //セキュリティルールを展開
 5:  | extend direction = tostring(rules.properties.direction)
 6:  | extend priority = toint(rules.properties.priority)
 7:  | extend description = rules.properties.description
 8:  | extend destprefix = rules.properties.destinationAddressPrefix
 9:  | extend destport = rules.properties.destinationPortRange
10:  | extend sourceprefix = rules.properties.sourceAddressPrefix
11:  | extend sourceport = rules.properties.sourcePortRange
12:  | extend access = rules.properties.access
13:  | where sourceprefix =~ "*"
14:  | where direction =~ "Inbound"
15:  | where access =~ "Allow"
16:  | project resourceGroup, NsgName = name, direction, priority, destprefix, destport, sourceprefix, sourceport, access, description
17:  | sort by resourceGroup asc

作例(VMとNICの一覧)

join

 1:  resources
 2:  | where type =~ 'microsoft.compute/virtualmachines'
 3:  | extend nics=array_length(properties.networkProfile.networkInterfaces)
 4:  | mv-expand nic=properties.networkProfile.networkInterfaces
 5:  | where nics == 1 or nic.properties.primary =~ 'true' or isempty(nic)
 6:  | project vmId = id, vmName = name, vmSize=tostring(properties.hardwareProfile.vmSize), nicId = tostring(nic.id)
 7:  | join kind=leftouter ( //typeをNICに絞ったテーブルを作成
 8:      resources
 9:      | where type =~ 'microsoft.network/networkinterfaces'
10:      | extend ipConfigsCount=array_length(properties.ipConfigurations)
11:      | mv-expand ipconfig=properties.ipConfigurations
12:      | where ipConfigsCount == 1 or ipconfig.properties.primary =~ 'true'
13:      | project nicId = id, nicName=split(id, "/")[-1])
14:      on nicId //nicIdをキーにVMテーブルとNICテーブルを結合
15:  | project vmName, vmSize, nicName

Appendix

Discussion