Kusto Query Language (KQL) est un langage conçu pour interroger et explorer de grandes quantités de données. Initialement développé pour Microsoft Azure Data Explorer, il est utilisé dans plusieurs services Microsoft, notamment, Log Analytics Microsoft Sentinel et Microsoft Defender..
Sa syntaxe permet de :
- Filtrer et trier les données.
- Effectuer des agrégations complexes (somme, moyenne, maximum, etc.).
- Générer des visualisations, comme des graphiques.
- Corréler et analyser les logs pour détecter des anomalies ou des incidents de sécurité.
Ce premier article présente les concepts de ce langage ainsi que les opérateurs de base. Dons un second article, on trouvera des fonctionnalités avancées. Enfin un troisième article présente l’usage de KQL avec Microsoft Defender
Un peu d’histoire :
Kusto est le nom de code d’Azure Data Explorer (ADX): une plateforme complète d’analyse Big Data managée et un service d’exploration de donné, permettant d’explorer l’océan de données. Il est ainsi nommé d’après le célèbre officier de marine Français, explorateur, écologiste, cinéaste, scientifique, photographe, auteur et chercheur qui a étudié la mer et toutes les formes de vie dans l’eau
Afin d’être utilisable avec Log Analytics et Microsoft Sentinel, les données sont stockées dans un « Workspace » (service Azure). Un Workspace est l’équivalent d’une base de données dans ADX.
Ce Workspace est ainsi interrogeable via un lange de requête structuré : KQL qui permet de faire des requêtes en lecture seule pour traiter les données et renvoyer les résultats de l’espace de travail Log Analytics (mais pas seulement…).
Structuration et utilisation des données :
Les données se trouvent dans un ou plusieurs espaces de travail Log Analytics. Elles sont structurées en tableaux avec des colonnes et des lignes :

Bien que réalisables directement via KQL, les requêtes peuvent aussi être directement utilisées depuis les solutions de sécurité Microsoft telles que Microsoft Sentinel, Microsoft Defender, Azure Log Analytics, …
Il est ainsi possible d’utiliser l’interface KQL composée :
- D’une zone Schéma indiquant la liste des tables interrogeables dans le Workspace
- La zone d’écriture de la requête
- La zone de résultats
- La zone de filtres
- Ainsi eu la possibilité de paramétrer la fenêtre de temps, de générer des alertes, d’exporter la requête ou d’épingler le résultat sur un tableau de bord

Autre solution : utiliser les interfaces des solutions de sécurité, comprenant des requêtes pré-paramétrées, comme ci-dessous dans Microsoft Sentinel

Pour commencer avec le langage KQL
Structuration d’une requête :
- Une requête KQL est une requête en lecture seule
- La demande est formulée en texte brut
- La demande utilise un modèle de flux de données
- Les résultats circulent à travers le pipe « | »
- Elle commence par la table qui va être requêtée
- Les commentaires sont précédés sur signe « // »

Le résultat apparait dans la zone idoine, les colonnes peuvent être triées et filtrées

Utilisation des premiers opérateurs :
Dans ce premier article nous allons découvrir comment utiliser les opérateurs les plus courants tels que : WHERE, EXTEND, PROJECT, LET, ORDER By et SUMMARIZE
WHERE :
- Where filtre une table sur le sous-ensemble de lignes
- Plusieurs Where peuvent être utilisés
- Peut contenir un opérateur logique (AND, OR, …)
Il est complété par des opérateurs permettant de définir les filtres :
Operator | CS | Description |
== | Yes | Equals |
!= | Yes | Not equals |
=~ | No | Equals |
contains | No | R occurs as a subsequence of L |
contains_cs | Yes | R occurs as a subsequence of L |
Has | No | R a whole term in L |
In | Yes | Equals to one of the elements |
startswith | No | R is an initial subsequence of L |
matches regex | Yes | L contains a match for R |
Exemple de syntaxe permettant de poser la question : « Dans la table Security Event, donne la liste des utilisateurs dont la connexion a échoué (event ID 4625) au cours de la dernière heure »
SecurityEvent
| where TimeGenerated > ago(1d)
| where EventID == 4625
EXTEND et PROJECT
- Extend : Créer des colonnes calculées et ajouter les nouvelles colonnes au résultat
- Project : Contrôler les colonnes à inclure, ajouter, supprimer ou renommer
Operateurs pour PROJECT :
Operator | Description |
project | Select the columns to include, rename or drop. |
project-away | Select what to exclude. |
project-keep | Select what columns to keep. |
project-rename | Select the columns to rename |
project-reorder | Set the column order |
Exemple de syntaxe permettant de poser la question : « Existe-t-il une connexion au portail Azure depuis l’extérieur de FR. Afficher l’application, le pays et l’identité »
SigninLogs
|where AppDisplayName contains « azure »
|extend Country = iff(LocationDetails.countryOrRegion == », ‘Unknown country’, tostring(LocationDetails.countryOrRegion))
|where Country != « FR »
|project AppDisplayName, Country, Identity
LET
- Permet de définir un nom de variable égal à une expression ou une fonction, ou de créer des vues
Exemple de syntaxe permettant de poser la question : « rechercher un événement de sécurité spécifique au cours d’une période spécifique »
let startDatetime = todatetime(« 2024-11-24 00:00:00 »);
let endDatetime = todatetime(« 2024-11-30 00:00:00 »);
let SecurityEventID = 4625;
SecurityEvent
|where EventID == SecurityEventID
|where TimeGenerated between(startDatetime .. endDatetime)
|project Computer, Account, TimeGenerated
ORDER BY, SUMMARIZE et TAKE
- ORDER BY : Utilisé pour trier les lignes. Possibilité d’utiliser n’importe quelle colonne ou plusieurs colonnes à l’aide d’un séparateur de virgules
- SUMMARIZE: regroupe les lignes qui ont les mêmes valeurs dans la clause by, puis utilise une fonction d’agrégation pour combiner chaque groupe dans une seule ligne
- TAKE : permet de ne sélectionner qu’une partie des réponses (par exemple les 10 premiers de la liste)
Opérateurs associés à SUMMARIZE:
Operator | Description |
count() | Returns a count of the records |
dcount() | Returns an estimate for the number of distinct values |
avg() | Calculates the average |
Max() | Returns the maximum value |
sum() | Calculates the sum |
count(), | Returns a count of the records |
Exemple de syntaxe permettant de poser la question : « Quels sont les comptes les plus courants (top 10) utilisés avec un échec de connexion au cours de la dernière semaine de novembre «
SecurityEvent
|where TimeGenerated between (datetime(2024-11-24) .. datetime(2024-11-30))
|where EventID == 4625
|summarize count() by Account
|order by count_ desc
|take 10
Afficher les résultats sous forme graphique
Afin d’intégrer le résultat dans un tableau de bord il peut être préférable d’obtenir un rendu sous la forme d’un graphique. Pour cela il faut utiliser RENDER
En complément ; on peut utiliser BIN afin de regrouper les données dans un ensemble plus petit de valeurs spécifiques dans une taille de compartiment (« bucket »)
Exemple de syntaxe permettant de poser la question : « Obtenir un graphique montrant le nombre total d’erreurs de connexion par jour au cours des deux dernières semaines »
SecurityEvent
|where TimeGenerated > ago(14d)
|where EventID == 4625
|summarize count() by tostring(EventID), bin(Timegenerated, 1d)
|render Timechart
Le résultat :

Cette requête peut être utilisée afin de créer un Workbook dans Microsoft Sentinel
–
–
–
Suite de l’article : Introduction à KQL : Kusto Query Language (2/2)
Exemples de requêtes KQL pour le Hunting dans Microsoft Defender : Exemples de requêtes KQL pour le Hunting dans Microsoft Defender