日商エレクトロニクスのAzure テクニカルマーケティング担当の髙橋です。 今回は、前回の分析ルール設定編に続き調査編になります。前回の記事は以下をご覧ください。 過去のMicrosoft Sentinel でログ収集・分析基盤を構築してみた① 、Microsoft Sentinel でログ収集・分析基盤を構築してみた②を経て、Microsoft Sentinel 上にログがため込まれており、分析ルールでアラート通知が飛ぶようになっていると思います。 実際の運用時には、アラートが出た際にKQLを使ってログの詳細分析が必要になってきます。 Kusto Query Languageと呼ばれ、Microsoftのサービス内で動作する読み取り専用のリクエストとなり、データを処理して結果を返すものです。 Azure Data Explorer、Azure Resourcce Graph、Application Insightでも利用されているため、覚えておくと色々なサービスで活用できます。 公式リファレンス:Kusto 照会言語 (KQL) の概要 – Azure Data Explorer | Microsoft Learn ソースとなるテーブルに対して 演算子を| (パイプ) で並べていきます。 データは、演算子から次の演算子へと流れていき、その中で処理(フィルター処理、並べ替え、集計)が行われます。 この処理の順番はパフォーマンスにも影響してくるため、より効率的な演算を考える必要があります。 今回は以下のようなサンプルレコードを想定して、よく使うオペレーターを見ていきます。 サンプルテーブル – SigninLogs – サンプルテーブル – SigninLogs – クエリサンプル 特定のキーワードを含むレコードを検索します。 実行結果 “Tokyo, JP” というキーワードが含まれるレコードが結果として返ってきましたね。 サンプルテーブル – SigninLogs – クエリサンプル DeviceがiPhone かつ Location が Singapore, SGの条件でフィルター処理します。 実行結果 アンド条件で一致するレコードが結果として返ってきましたね。 サンプルテーブル – SigninLogs – クエリサンプル 対象のレコードから最新の2レコードを取得します。 実行結果 上から2つのレコードが返ってきました。 サンプルテーブル – SigninLogs – クエリサンプル 対象テーブルのレコード数をカウントします。 実行結果 レコード数として5が返ってきました。正しいですね。 サンプルテーブル – SigninLogs – クエリサンプル Status の値ごとに該当するレコードをカウントします。 実行結果 Status が「Success」は3レコード、「Fail」は2レコードという結果が返ってきました。 サンプルテーブル – SigninLogs – クエリサンプル ソーステーブルのLocation を split でカンマで区切りにし、配列に代入します。 Extend で Country カラムを追加し、配列の1つ目を入力しています。 | take 2 実行結果 サンプルテーブル – SigninLogs – クエリサンプル Location カラムを指定し出力します。 実行結果 サンプルテーブル – SigninLogs – クエリサンプル UserName と Location を指定しテーブルを作成 実行結果 変数を定義し、複雑な式、数字、文字を代入します。 サンプルテーブル Table クエリサンプル Numberが123 かつ Location がJapanのレコードを抽出します。 実行結果 Table1 Table2 クエリサンプル デフォルトでは、左側の重複を除去する内部結合となります。 結合キーの左側(Table1)が重複除去されてから内部結合が行われます。 ※重複がある場合、最初のレコードが維持されます。 | join (Table2) on Key 重複削除後のTable1は以下のようになります。 Table1 その後、Table2と結合されます。 Table2 実行結果 kind=innerを指定することで、左側の重複排除をすることなく、左右で一致するレコードの結合が可能です。(SQLでいう標準の内部結合) クエリサンプル | join kind=inner (Table2) on Key Table1 Table2 実行結果 サンプルテーブル T クエリサンプル Timestampの時刻が、現在の時刻から1時間以内のレコードを抽出します。 入力テーブルの行の順序を 1 つ以上の列で並べ替えます。 サンプルテーブル T クエリサンプル Number列を昇順にし行を並べ替えます。 実行結果 クエリサンプル 変数 date の日付に対して、day, week , month, year の開始日を取得します。 実行結果 以下のサンプルデータを元に解説します。 Event クエリサンプル まずはクエリサンプルの2行目「| parse EventText with * “resourceName=” resourceName “, totalSlices=” totalSlices:long * “, sliceNumber=” Garbage 」について解説します。 「EventText with * “resourceName=” resourceName」 ⇒元のEventTextの”resourceName=”の後ろにある文字列を、resourceName列に格納するといったクエリになっています。 「”, totalSlices=” totalSlices:long *」 ⇒同様に、”, totalSlices=” の後ろにある文字列を、 totalSlices 列に long値として格納しています。 「”, sliceNumber=” Garbage」 ⇒最後に、”, sliceNumber=” 以降の文字列を、Garbage列に格納しています。(使わない文字列はGarbage等の任意の名前を付けて分かりやすくしています。 実行結果 指定した文字列の後ろにあるデータが格納されていますね。 今回は、KQLの基本的な構文と、よく使うオペレーターを見てきました。 今回ご紹介したもの以外にもたくさんの演算子がありますので公式リファレンスもご参照ください。 公式リファレンス:Kusto 照会言語 (KQL) の概要 – Azure Data Explorer | Microsoft Learn これらを使って、アラートが発生した際にログの調査が可能となりますので是非ご活用ください。 今後も技術ブログをアップデートしていきますので、なにかご相談が御座いましたら下記フォームからお問い合わせください。
はじめに
今回のゴール
今回、このKQLの基本的な使い方を解説していきたいと思います。
1. KQLとは?
基本構文
2. よく使うオペレーター
Username
Device
Location
Status
Kazuki
Windows 11
Tokyo, JP
Success
Riku
Windows 7
Yamanashi, JP
Fail
Shingo
MAX OSX
Chiba, JP
Success
Kazuyuki
iPhone
Melbourne, AU
Success
Tomoko
iPhone
Singapore, SG
Fail
文字列の検索(Search)
Username
Device
Location
Status
Kazuki
Windows 11
Tokyo, JP
Success
Riku
Windows 7
Yamanashi, JP
Fail
Shingo
MAX OSX
Chiba, JP
Success
Kazuyuki
iPhone
Melbourne, AU
Success
Tomoko
iPhone
Singapore, SG
Fail
SigninLogs
| search “Tokyo, JP”
Username
Device
Location
Status
Kazuki
Windows 11
Tokyo, JP
Success
テーブルのフィルタ(Where)
Username
Device
Location
Status
Kazuki
Windows 11
Tokyo, JP
Success
Riku
Windows 7
Yamanashi, JP
Fail
Shingo
MAX OSX
Chiba, JP
Success
Kazuyuki
iPhone
Melbourne, AU
Success
Tomoko
iPhone
Singapore, SG
Fail
SigninLogs
| where Device == “iPhone” and Location ==”Singapore, SG”
Username
Device
Location
Status
Tomoko
iPhone
Singapore, SG
Fail
指定した行数のデータを取得(Take)
Username
Device
Location
Status
Kazuki
Windows 11
Tokyo, JP
Success
Riku
Windows 7
Yamanashi, JP
Fail
Shingo
MAX OSX
Chiba, JP
Success
Kazuyuki
iPhone
Melbourne, AU
Success
Tomoko
iPhone
Singapore, SG
Fail
SigninLogs
| take 2
Username
Device
Location
Status
Kazuki
Windows 11
Tokyo, JP
Success
Riku
Windows 7
Yamanashi, JP
Fail
入力したテーブルのレコード数を取得(Count)
Username
Device
Location
Status
Kazuki
Windows 11
Tokyo, JP
Success
Riku
Windows 7
Yamanashi, JP
Fail
Shingo
MAX OSX
Chiba, JP
Success
Kazuyuki
iPhone
Melbourne, AU
Success
Tomoko
iPhone
Singapore, SG
Fail
SigninLogs
| count
Count
5
入力テーブルの内容を集計(Summarize)
Username
Device
Location
Status
Kazuki
Windows 11
Tokyo, JP
Success
Riku
Windows 7
Yamanashi, JP
Fail
Shingo
MAX OSX
Chiba, JP
Success
Kazuyuki
iPhone
Melbourne, AU
Success
Tomoko
iPhone
Singapore, SG
Fail
SigninLogs
| summarize Total = count() by Status
Status
Total
Success
3
Fail
2
新しいフィールドを追加(Extend)
Username
Device
Location
Status
Kazuki
Windows 11
Tokyo, JP
Success
Riku
Windows 7
Yamanashi, JP
Fail
Shingo
MAX OSX
Chiba, JP
Success
Kazuyuki
iPhone
Melbourne, AU
Success
Tomoko
iPhone
Singapore, SG
Fail
SigninLogs
| extend Country = split(Location, “,”)[1]
Country
JP
JP
出力するフィールドを指定(Project)
Username
Device
Location
Status
Kazuki
Windows 11
Tokyo, JP
Success
Riku
Windows 7
Yamanashi, JP
Fail
Shingo
MAX OSX
Chiba, JP
Success
Kazuyuki
iPhone
Melbourne, AU
Success
Tomoko
iPhone
Singapore, SG
Fail
SigninLogs
| take 2
| project Location
Location
Tokyo, JP
Yamanashi, JP
指定された列のテーブルを作成(Distinct)
Username
Device
Location
Status
Kazuki
Windows 11
Tokyo, JP
Success
Riku
Windows 7
Yamanashi, JP
Fail
Shingo
MAX OSX
Chiba, JP
Success
Kazuyuki
iPhone
Melbourne, AU
Success
Tomoko
iPhone
Singapore, SG
Fail
SigninLogs
| take 2
| distinct UserName , Location
Username
Location
Kazuki
Tokyo, JP
Riku
Yamanashi, JP
変数の定義(Let)
Timestamp
Number
Location
2007-12-28T12:10:00Z
123
Japan
2007-12-28T04:30:00Z
872
Japan
2007-12-28T04:16:00Z
196
Singapore
let n = 123; // number
let location = “Japan”; // stringTableTable
| where Number == n and Location == location
Timestamp
Number
Location
2007-12-28T12:10:00Z
123
Japan
各テーブルの指定の列で値を照合し、2つのテーブルの行を結合(Join)
Key
Value
a
1
b
2
b
3
c
4
Key
Value2
b
10
c
20
c
30
d
40
Table1
Key
Value
a
1
b
2
c
4
Key
Value2
b
10
c
20
c
30
d
40
Key
Value
Key1
Value1
b
2
b
10
c
4
c
20
c
4
c
30
Table1
Key
Value
a
1
b
2
b
3
c
4
Key
Value2
b
10
c
20
c
30
d
40
Key
Value1
Key1
Value2
b
3
b
10
b
2
b
10
c
4
c
20
c
4
c
30
その他の演算子
現在のUTC時刻から指定された期間を減数(Ago)
T | where Timestamp > ago(1h)
並び替え(Sort)
Timestamp
Number
…
2007-12-28T12:10:00Z
123
…
2007-12-28T04:30:00Z
872
…
2007-12-28T04:16:00Z
196
…
T
| sort by Number asc
Timestamp
Number
…
2007-12-28T12:10:00Z
123
…
2007-12-28T04:16:00Z
196
…
2007-12-28T04:30:00Z
872
…
日付の開始日を取得(startofday, week, month, year)
let date = datetime(2023-01-27 15:44:17)
.
(省略)
.
| project dayStart = startofday(date)
| project weekStart = startofweek(date)
| project monthStart = startofmonth(date)
| project yearStart = startofyear(date)
dayStart
weekStart
monthStart
yearStart
2023-1-27 00:00:00.0000000
2023-1-22 00:00:00.0000000
2023-1-1 00:00:00.0000000
2023-1-1 00:00:00.0000000
データ解析(parse)
EventText
Event: NotifySliceRelease (resourceName=PipelineScheduler, totalSlices=27, sliceNumber=23, lockTime=02/17/2016 08:40:01, releaseTime=02/17/2016 08:40:01, previousLockTime=02/17/2016 08:39:01)
Event: NotifySliceRelease (resourceName=PipelineScheduler, totalSlices=25, sliceNumber=15, lockTime=02/17/2016 08:40:00, releaseTime=02/17/2016 08:40:00, previousLockTime=02/17/2016 08:39:00)
Event: NotifySliceRelease (resourceName=PipelineScheduler, totalSlices=15, sliceNumber=20, lockTime=02/17/2016 08:40:01, releaseTime=02/17/2016 08:40:01, previousLockTime=02/17/2016 08:39:01)
Event
| parse EventText with * “resourceName=” resourceName “, totalSlices=” totalSlices:long * “, sliceNumber=” Garbage
| project resourceName, totalSlices, sliceNumber, lockTime, releaseTime, previousLockTime
resourceName
totalSlices
Garbage
PipelineScheduler
27
23, lockTime=02/17/2016 08:40:01, releaseTime=02/17/2016 08:40:01, previousLockTime=02/17/2016 08:39:01)
PipelineScheduler
25
15, lockTime=02/17/2016 08:40:00, releaseTime=02/17/2016 08:40:00, previousLockTime=02/17/2016 08:39:00)
PipelineScheduler
15
20, lockTime=02/17/2016 08:40:01, releaseTime=02/17/2016 08:40:01, previousLockTime=02/17/2016 08:39:01)
さいごに
この記事を書いた人
学生時代はアプリ開発に興味がありましたが、インフラ、セキュリティ事業を経て、現在はクラウド屋さんになっております。
コロナ禍前は、月1で海外旅行にいくなどアクティブに活動していましたが、最近は家に引きこもってゲームが趣味になっています。
宜しくお願い致します!
この投稿者の最新の記事