Fonctions du Graphe IRQL — Des Résultats de Requête à la Visualisation
Applique la famille de fonctions du graphe IRQL à des résultats tabulaires. Étant donné une requête KQL ou IRQL et la description du graphe par l'utilisateur, génère un mapping Lift_To_Graph et compose uniquement les fonctions de graphe stockées nécessaires pour visualiser, plier, extraire ou enrichir le graphe dans Kusto Explorer. La requête source n'a pas besoin d'utiliser IRQL.
Portée et Aiguillage
| Requête | Utilisation |
|---|---|
| Transformer des lignes KQL/IRQL fournies en un graphe visuel décoré d'icônes | Cette compétence : Lift_To_Graph + Graph_Render_View |
Plier des nœuds ou appliquer Extract_Node_*, Enrich_Node_* ou Enrich_Graph_* | Cette compétence |
Utiliser make-graph, graph-match, les plus courts chemins, les composants connexes, les modèles de graphe ou les instantanés | azure-kusto-graph |
| Rédiger une investigation KQL/IRQL non triviale à partir du langage naturel | Une compétence de génération de requête Kusto ou IRQL, puis cette compétence |
Si une requête mélange visualisation et analyse de graphe native, utilisez cette compétence pour la partie levée/rendu et azure-kusto-graph pour la sémantique des opérateurs. Ne remplacez pas les fonctions de levée de graphe par un graphe construit manuellement arêtes d'abord, sauf si l'utilisateur demande des opérateurs de graphe natifs.
Contrat d'Entrée
- Entrée préférée : une requête KQL/IRQL fonctionnelle qui produit des résultats tabulaires, plus une description en langage naturel des nœuds, arêtes, étiquettes, icônes, extractions, enrichissements ou pliages souhaités.
- Cette compétence n'est pas un convertisseur langage-naturel-vers-KQL ou NL-vers-IRQL. Elle transforme des résultats de requête existants en visualisations de graphe. Pour une conversion générale NL-vers-KQL ou NL-vers-IRQL, utilisez une compétence dédiée de génération de requête (disponible séparément).
- Préservez les récupérations, jointures, filtres et agrégations de la requête fournie. Ajoutez uniquement les projections ou ID synthétiques requis par le mapping du graphe.
- Une requête source basique en langage naturel n'est prise en charge que lorsqu'elle correspond directement à une table connue ou à un sélecteur IRQL
Get_*avec des colonnes évidentes et des filtres simples. Indiquez la source supposée et n'inventez pas de jointures, de schéma ou de logique d'investigation. - Pour une construction de requête non triviale, utilisez d'abord une compétence séparée de génération de requête Kusto/IRQL, puis appliquez cette compétence à sa sortie.
- Si aucune requête ou schéma de sortie n'est disponible et que la source n'est pas triviale, demandez la requête KQL ou ses colonnes de résultat avant de générer un mapping.
Déclencheurs d'Activation
Utilisez cette compétence lorsque l'utilisateur :
- Fournit des résultats KQL/IRQL et demande une visualisation ou un mapping de graphe IRQL
- Mentionne
Lift_To_Graph,Graph_Render_ViewouGraph_Fold_By_Property - Demande des mappings de nœuds/arêtes décorés d'icônes dans Kusto Explorer
- Souhaite plier/contracter des nœuds par une propriété partagée
- Demande une extraction ou un enrichissement de graphe via
Extract_Node_*,Enrich_Node_*ouEnrich_Graph_*
N'activez pas cette compétence uniquement pour graph-match, les chemins/composants de graphe, les graphes persistants ou la construction générique make-graph ; ceux-ci relèvent de azure-kusto-graph.
N'est pas un convertisseur langage-naturel-vers-KQL/IRQL. L'entrée doit généralement être une requête KQL ou IRQL fonctionnelle dont les résultats ont besoin d'une visualisation en graphe. Les requêtes sources basiques en NL ne fonctionnent que pour les cas triviaux à table/sélecteur unique. Pour une conversion générale NL-vers-KQL ou NL-vers-IRQL, utilisez une compétence dédiée de génération de requête (disponible séparément).
Environnement
- Cluster :
https://kc7001.eastus.kusto.windows.net - Bases de données :
ValdyTimes,JoJosHospital(fonctions de graphe pré-déployées) - Rendu : Application bureau Kusto Explorer (fenêtre de visualisation make-graph)
- Outil :
kusto_query(via Azure MCP Server)
Vérification Préalable des Fonctions
Lift_To_Graph et Graph_Render_View sont des fonctions stockées, pas des opérateurs Kusto intégrés. Avant de générer ou d'exécuter un pipeline de levée sur une base de données cible, vérifiez ce qui est déployé :
.show functions
| where Name in~ ("Lift_To_Graph", "Graph_Render_View", "Graph_Fold_By_Property")
| project Name
Lift_To_GraphetGraph_Render_Viewsont requis.Graph_Fold_By_Propertyest requis uniquement lorsqu'un pliage est demandé.- Vérifiez toute fonction
Extract_Node_*,Enrich_Node_*ouEnrich_Graph_*avant de l'utiliser ; omettez l'enrichissement optionnel lorsqu'il n'est pas disponible, sauf si l'utilisateur souhaite son déploiement. - Si une fonction requise est manquante et que vous avez l'autorisation de modifier la base de données, demandez la confirmation de l'utilisateur avant de la déployer. Utilisez ensuite les définitions
.create-or-alter functiondans references/DEPLOY_IRQL_FUNCTIONS.md. Exécutez le bloc.create-or-alterpertinent, puis relancez la vérification préalable pour confirmer. - Si vous n'avez pas les autorisations de modification, indiquez à l'utilisateur quelles fonctions manquent et orientez-le vers
references/DEPLOY_IRQL_FUNCTIONS.mdpour un déploiement manuel.
Famille de Fonctions du Graphe IRQL
Lift_To_Graph(T, mappingJson)
Transforme tout résultat tabulaire KQL en une table unifiée nœuds + arêtes.
Entrée : Toute table T + une chaîne JSON de mapping.
Sortie : Lignes avec EntityType = "node" ou "edge", prêtes pour make-graph.
Graph_Render_View(T)
Prend la sortie de Lift_To_Graph, sépare les nœuds/arêtes et appelle make-graph pour ouvrir la fenêtre de graphe de Kusto Explorer.
Graph_Fold_By_Property(T, NodeType, PropertyName)
Contracte les nœuds d'un type donné partageant une valeur de propriété en un seul nœud. Reconnecte automatiquement les arêtes.
Fonctions d'Extraction et d'Enrichissement du Graphe
Ce sont des fonctions stockées supplémentaires qui doivent déjà être déployées sur la base de données cible. Elles ne sont pas incluses dans references/DEPLOY_IRQL_FUNCTIONS.md. Utilisez .show functions pour vérifier la disponibilité avant de les inclure dans un pipeline.
| Fonction | Opération | Propriété Clé |
|---|---|---|
Extract_Node_Email_Sender_Domain(T, displayName) | Ajoute Domain aux props du nœud | EmailSender |
Extract_Node_Employee_Firstname(T, displayName) | Ajoute Firstname aux props du nœud | Name |
Extract_Node_Event_Network_Domain(T, displayName) | Ajoute DomainName aux props du nœud | Url |
Enrich_Node_Ip_Employee(T, displayName) | Ajoute des infos employé aux nœuds IP | ClientIp |
Enrich_Node_Username_Employee(T, displayName) | Ajoute des infos employé aux nœuds utilisateur | Username |
Enrich_Node_Event_Authentication_Username(T, displayName) | Ajoute le contexte d'authentification | Username |
Enrich_Node_Ip_Domain(T, displayName) | Ajoute les domaines DNS | ClientIp |
Enrich_Node_Ip_Event_NetworkOutbound(T, displayName) | Ajoute les événements sortants | ClientIp |
Enrich_Graph_Ip_Employee(T, mappingJson) | Étend le graphe avec des nœuds employé | ClientIp |
Enrich_Graph_Username_Employee(T, mappingJson) | Étend le graphe avec des nœuds employé | Username |
Enrich_Graph_Event_Authentication_Username(T, mappingJson) | Étend avec des nœuds d'authentification | Username |
Schéma du JSON de Mapping
Le JSON de mapping comporte deux tableaux : node_types et edges.
node_types[]
| Champ | Requis | Description |
|---|---|---|
type | Oui | Étiquette du type de nœud (ex. "User", "Host", "IP") |
id | Oui | Préfixe pour l'ID du nœud ; généralement identique au type |
key | Oui | Nom de la colonne dont la valeur devient l'identité du nœud |
props | Oui | Tableau des colonnes à transporter comme propriétés du nœud |
defaults | Non | Objet des valeurs de repli pour les propriétés nulles/vides |
defIcon | Non | URL de l'icône par défaut pour ce type de nœud |
displayName | Non | Colonne à utiliser pour l'étiquette d'affichage (par défaut : id) |
color | Non | Colonne dont provient la couleur |
size | Non | Colonne dont provient la taille |
edges[]
| Champ | Requis | Description |
|---|---|---|
type | Oui | Étiquette du type d'arête (ex. "AuthenticatesTo", "SentEmail") |
source | Oui | {"id": "<préfixe>", "type": "<TypeDeNoeud>"} |
target | Oui | {"id": "<préfixe>", "type": "<TypeDeNoeud>"} |
props | Non | Tableau des colonnes à transporter comme propriétés de l'arête |
displayName | Non | Colonne pour l'étiquette de l'arête |
color | Non | Colonne pour la couleur de l'arête |
Répertoire d'Icônes
Utilisez les icônes de https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-icons/ :
- IP :
Public-IP-Addresses-(Classic).svg - Hôte/VM :
Virtual-Machine.svg - Utilisateur :
Users.svg - Email :
Mailbox.svg(ouazure-cds/command-1070-Mail.svg) - Processus :
App-Services.svg - Fichier :
Storage-Accounts.svg - Alerte :
Activity-Log.svg - Domaine :
DNS-Zones.svg
Règles de Génération du Mapping
Compte tenu des colonnes de la requête fournie et de la description du graphe par l'utilisateur, générez le JSON de mapping en :
- Identifier les entités -> chaque nom distinct devient un
node_type - Identifier les relations -> chaque verbe/préposition devient une
edge - Mapper aux colonnes -> utilisez les colonnes réelles produites par la requête fournie ; ne supposez jamais de colonnes indisponibles
- Définir la direction -> la source est l'acteur, la cible est l'élément subissant l'action
- Ajouter des propriétés -> incluez les colonnes pertinentes pour l'investigation (horodatages, résultats, hachages)
- Attribuer des icônes -> choisissez dans l'ensemble d'icônes ci-dessus en fonction du type d'entité
Référence des Colonnes (Schéma unifié IRQL)
| Entité | Colonne Clé | Propriétés Disponibles |
|---|---|---|
| Utilisateur | Username | Username, Name, Role, Email |
| Hôte | Hostname | Hostname |
| IP | ClientIp | ClientIp |
| Message Email | Subject | EnvTime, Subject, Verdict, Url |
| Expéditeur | EmailSender | EmailSender, Domain |
| Destinataire | EmailRecipient | EmailRecipient |
| Processus | ProcessName | EnvTime, ProcessName, ProcessCommandLine, ProcessHash |
| Fichier | Filename | EnvTime, Filename, Path, Sha256 |
| Domaine | DomainName | DomainName |
| Événement Auth | (ID synthétique) | EnvTime, UserAgent, Result, Description |
Sélection des Fonctions
- Commencez par le pipeline tabulaire KQL/IRQL fourni.
- Utilisez
Lift_To_Graph(mapping)pour créer les entités du graphe. - Ajoutez
Extract_Node_*,Enrich_Node_*ouEnrich_Graph_*uniquement lorsqu'ils sont demandés et compatibles avec les clés mappées. - Ajoutez
Graph_Fold_By_Property()uniquement lorsqu'un regroupement/pli est demandé. - Terminez la sortie visuelle par
Graph_Render_View(). - Vérifiez au préalable les fonctions stockées exactes sélectionnées pour le pipeline.
Modèle de Pipeline
// 1. Préservez la requête KQL ou IRQL fournie
<requête d'entrée>
// 2. Levez vers le graphe
| invoke Lift_To_Graph(<mapping_json>)
// 3. Extrayez ou enrichissez optionnellement les entités du graphe
| invoke <Extract_Node_* | Enrich_Node_* | Enrich_Graph_*>()
// 4. Pliez optionnellement les nœuds si demandé
| invoke Graph_Fold_By_Property("<TypeDeNoeud>", "<NomDePropriété>")
// 5. Rendu
| invoke Graph_Render_View()
Exemples
Pour des prompts supplémentaires et des exemples détaillés, consultez references/EXAMPLES.md.
Graphe d'authentification : IP -> AuthEvent -> Utilisateur -> Hôte
Requête d'entrée : Get_Event_Authentication_All | where Result == "Failed Login" | take 200
Demande de graphe : "Afficher les IP, les événements d'authentification, les utilisateurs et les hôtes ; plier les événements par résultat."
let auth_mapping = '{"node_types":[{"type":"SrcIp","id":"SrcIp","key":"ClientIp","props":["ClientIp"],"defaults":{},"defIcon":"https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-icons/Public-IP-Addresses-(Classic).svg"},{"type":"Host","id":"Host","key":"Hostname","props":["Hostname"],"defaults":{},"defIcon":"https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-icons/Virtual-Machine.svg"},{"type":"User","id":"User","key":"Username","props":["Username"],"defaults":{},"defIcon":"https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-icons/Users.svg"},{"type":"AuthEvent","id":"AuthEvent","key":"AuthEventId","props":["AuthEventId","EnvTime","UserAgent","Result","Description"],"defaults":{"Result":"unknown"},"defIcon":"https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-icons/Activity-Log.svg"}],"edges":[{"type":"RequestsAuth","source":{"id":"SrcIp","type":"SrcIp"},"target":{"id":"AuthEvent","type":"AuthEvent"},"props":["EnvTime"]},{"type":"TargetsUser","source":{"id":"AuthEvent","type":"AuthEvent"},"target":{"id":"User","type":"User"},"props":["EnvTime"]},{"type":"AgainstHost","source":{"id":"AuthEvent","type":"AuthEvent"},"target":{"id":"Host","type":"Host"},"props":["EnvTime"]}]}';
Get_Event_Authentication_All
| extend AuthEventId = strcat(Username, "_", Hostname, "_", EnvTime)
| where Result == "Failed Login"
| take 200
| invoke Lift_To_Graph(auth_mapping)
| invoke Graph_Fold_By_Property("AuthEvent", "Result")
| invoke Graph_Render_View()
Graphe d'email : Expéditeur -> Message -> Destinataire
Requête d'entrée : Get_Email_All | take 400
Demande de graphe : "Visualiser le flux expéditeur-à-message-à-destinataire et plier les messages par verdict."
let mail_mapping = '{"node_types":[{"type":"EmailMessage","id":"Message","key":"Subject","props":["EnvTime","Subject","Verdict"],"defaults":{},"defIcon":"https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-icons/Media-File.svg"},{"type":"Sender","id":"Email","key":"EmailSender","props":["EmailSender"],"defaults":{},"defIcon":"https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-cds/command-1070-Mail.svg"},{"type":"Recipient","id":"Email","key":"EmailRecipient","props":["EmailRecipient"],"defaults":{},"defIcon":"https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-cds/command-1070-Mail.svg"}],"edges":[{"type":"SentBy","source":{"id":"Message","type":"EmailMessage"},"target":{"id":"Email","type":"Sender"},"props":["EnvTime","Verdict"]},{"type":"DeliveredTo","source":{"id":"Message","type":"EmailMessage"},"target":{"id":"Email","type":"Recipient"},"props":["EnvTime","Verdict"]}]}';
Get_Email_All
| take 400
| invoke Lift_To_Graph(mail_mapping)
| invoke Graph_Fold_By_Property("EmailMessage", "Verdict")
| invoke Graph_Render_View()
Investigation de domaine suspect (de bout en bout)
Requête source basique : "Utiliser les événements réseau sortants pour ces domaines suspects et grapher les connexions IP-à-domaine enrichies avec les noms d'employés."
C'est le cas de repli limité : un sélecteur connu, un extracteur et un filtre direct.
let suspicious_domain_mapping = '{"node_types":[{"type":"IP","id":"IP","key":"ClientIp","props":["ClientIp"],"defaults":{},"defIcon":"https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-icons/Public-IP-Addresses-(Classic).svg"},{"type":"Domain","id":"Domain","key":"DomainName","props":["DomainName","Url"],"defaults":{},"defIcon":"https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-icons/DNS-Zones.svg"},{"type":"Employee","id":"Employee","key":"Name","props":["Name","Email"],"defaults":{},"defIcon":"https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-icons/Users.svg"}],"edges":[{"type":"ConnectsTo","source":{"id":"IP","type":"IP"},"target":{"id":"Domain","type":"Domain"},"props":["EnvTime"]},{"type":"HasEmployee","source":{"id":"IP","type":"IP"},"target":{"id":"Employee","type":"Employee"},"props":["EnvTime"]}]}';
let suspicious_domains = pack_array("malicious.com", "phishing.net");
Get_Event_Network_Outbound
| where DomainName in (suspicious_domains)
| invoke Lift_To_Graph(suspicious_domain_mapping)
| invoke Enrich_Graph_Ip_Employee(suspicious_domain_mapping)
| invoke Graph_Render_View()
Dépannage
| Symptôme | Action |
|---|---|
Lift_To_Graph échoue avec "Function not found" | Exécutez la vérification préalable ; si manquante, déployez via DEPLOY_IRQL_FUNCTIONS.md |
| Le rendu du graphe est vide | Vérifiez que la requête d'entrée produit des lignes ; le mapping a-t-il des correspondances de colonnes ? |
| Les icônes ne s'affichent pas | Vérifiez que les URL sont accessibles et que les noms de fichiers d'icônes correspondent au répertoire |
| Le pli ne contracte rien | Confirmez que Graph_Fold_By_Property est déployé et que le PropertyName existe dans les props du type de nœud |
| Les fonctions d'enrichissement ne sont pas trouvées | Utilisez .show functions pour lister les fonctions disponibles ; n'utilisez que celles qui existent |