Funções de Grafo IRQL -- Resultados de Consultas para Visualização
Aplique a família de funções de grafo IRQL a resultados tabulares. Dada uma consulta KQL ou IRQL e a descrição do grafo fornecida pelo usuário, gere um mapeamento Lift_To_Graph e componha apenas as funções de grafo armazenadas necessárias para visualizar, dobrar, extrair ou enriquecer o grafo no Kusto Explorer. A consulta de origem não precisa usar IRQL.
Escopo e Roteamento
| Solicitação | Uso |
|---|---|
| Transformar linhas KQL/IRQL fornecidas em um grafo visual decorado com ícones | Esta skill: Lift_To_Graph + Graph_Render_View |
Dobrar nós ou aplicar Extract_Node_*, Enrich_Node_* ou Enrich_Graph_* | Esta skill |
Usar make-graph, graph-match, caminhos mais curtos, componentes conectados, modelos de grafo ou snapshots | azure-kusto-graph |
| Escrever uma investigação não trivial em KQL/IRQL a partir de linguagem natural | Uma skill de geração de consultas Kusto ou IRQL, depois esta skill |
Se uma solicitação misturar visualização e análise nativa de grafos, use esta skill para a parte de lift/render e azure-kusto-graph para a semântica de operadores. Não substitua funções de lift de grafo por um grafo construído manualmente com arestas primeiro, a menos que o usuário solicite operadores de grafo nativos.
Contrato de Entrada
- Entrada preferida: uma consulta KQL/IRQL funcional que produza resultados tabulares, mais uma descrição em linguagem natural dos nós, arestas, rótulos, ícones, extrações, enriquecimentos ou dobras desejados.
- Esta skill não é um conversor de linguagem natural para KQL ou NL para IRQL. Ela transforma resultados de consultas existentes em visualizações de grafo. Para conversão geral de NL para KQL ou NL para IRQL, use uma skill dedicada de geração de consultas (disponível separadamente).
- Preserve a recuperação, junções, filtros e agregações da consulta fornecida. Adicione apenas projeções ou IDs sintéticos necessários para o mapeamento do grafo.
- Uma solicitação básica em linguagem natural é suportada apenas quando mapeia diretamente para uma tabela conhecida ou seletor IRQL
Get_*com colunas óbvias e filtros simples. Indique a origem assumida e não invente junções, esquemas ou lógica de investigação. - Para construção de consultas não triviais, use uma skill separada de geração de consultas Kusto/IRQL primeiro e, em seguida, aplique esta skill à sua saída.
- Se nenhuma consulta ou esquema de saída estiver disponível e a origem não for trivial, solicite a consulta KQL ou suas colunas de resultado antes de gerar um mapeamento.
Gatilhos de Ativação
Use esta skill quando o usuário:
- Fornecer resultados KQL/IRQL e solicitar uma visualização ou mapeamento de grafo IRQL
- Mencionar
Lift_To_Graph,Graph_Render_ViewouGraph_Fold_By_Property - Solicitar mapeamentos de nós/arestas decorados com ícones no Kusto Explorer
- Quiser dobrar/colapsar nós por uma propriedade compartilhada
- Solicitar extração ou enriquecimento de grafo por meio de
Extract_Node_*,Enrich_Node_*ouEnrich_Graph_*
Não ative esta skill apenas para graph-match, caminhos/componentes de grafo, grafos persistentes ou construção genérica de make-graph; esses pertencem a azure-kusto-graph.
Não é um conversor de linguagem natural para KQL/IRQL. A entrada geralmente deve ser uma consulta KQL ou IRQL funcional cujos resultados precisam de visualização de grafo. Solicitações básicas em NL funcionam apenas para casos triviais de tabela/seletor único. Para conversão geral de NL para KQL ou NL para IRQL, use uma skill dedicada de geração de consultas (disponível separadamente).
Ambiente
- Cluster:
https://kc7001.eastus.kusto.windows.net - Bancos de Dados:
ValdyTimes,JoJosHospital(funções de grafo pré-implantadas) - Renderização: Aplicativo de desktop Kusto Explorer (janela de visualização make-graph)
- Ferramenta:
kusto_query(via Azure MCP Server)
Verificação Preliminar de Funções
Lift_To_Graph e Graph_Render_View são funções armazenadas, não operadores Kusto internos. Antes de gerar ou executar um pipeline de lift em um banco de dados alvo, verifique o que está implantado:
.show functions
| where Name in~ ("Lift_To_Graph", "Graph_Render_View", "Graph_Fold_By_Property")
| project Name
Lift_To_GrapheGraph_Render_Viewsão obrigatórias.Graph_Fold_By_Propertyé obrigatória apenas quando a dobra é solicitada.- Verifique qualquer função
Extract_Node_*,Enrich_Node_*ouEnrich_Graph_*antes de usá-la; omita enriquecimentos opcionais quando indisponíveis, a menos que o usuário queira implantá-la. - Se uma função obrigatória estiver faltando e você tiver permissão para alterar o banco de dados, peça confirmação ao usuário antes de implantar. Em seguida, use as definições de
.create-or-alter functionem references/DEPLOY_IRQL_FUNCTIONS.md. Execute o bloco.create-or-alterrelevante e, em seguida, repita a verificação preliminar para confirmar. - Se você não tiver permissões de alteração, informe ao usuário quais funções estão faltando e aponte para
references/DEPLOY_IRQL_FUNCTIONS.mdpara implantação manual.
Família de Funções de Grafo IRQL
Lift_To_Graph(T, mappingJson)
Transforma qualquer resultado tabular KQL em uma tabela unificada de nós + arestas.
Entrada: Qualquer tabela T + uma string de mapeamento JSON.
Saída: Linhas com EntityType = "node" ou "edge", prontas para make-graph.
Graph_Render_View(T)
Pega a saída de Lift_To_Graph, divide nós/arestas e chama make-graph para abrir a janela de grafo do Kusto Explorer.
Graph_Fold_By_Property(T, NodeType, PropertyName)
Colapsa nós de um determinado tipo que compartilham um valor de propriedade em um único nó. Reconecta arestas automaticamente.
Funções de Extração e Enriquecimento de Grafo
Estas são funções armazenadas adicionais que já devem estar implantadas no banco de dados alvo. Elas não estão incluídas em references/DEPLOY_IRQL_FUNCTIONS.md. Use .show functions para verificar a disponibilidade antes de incluí-las em um pipeline.
| Função | Operação | Propriedade Chave |
|---|---|---|
Extract_Node_Email_Sender_Domain(T, displayName) | Adiciona Domain às props do nó | EmailSender |
Extract_Node_Employee_Firstname(T, displayName) | Adiciona Firstname às props do nó | Name |
Extract_Node_Event_Network_Domain(T, displayName) | Adiciona DomainName às props do nó | Url |
Enrich_Node_Ip_Employee(T, displayName) | Adiciona informações do funcionário aos nós IP | ClientIp |
Enrich_Node_Username_Employee(T, displayName) | Adiciona informações do funcionário aos nós de usuário | Username |
Enrich_Node_Event_Authentication_Username(T, displayName) | Adiciona contexto de autenticação | Username |
Enrich_Node_Ip_Domain(T, displayName) | Adiciona domínios DNS | ClientIp |
Enrich_Node_Ip_Event_NetworkOutbound(T, displayName) | Adiciona eventos de saída | ClientIp |
Enrich_Graph_Ip_Employee(T, mappingJson) | Expande o grafo com nós de funcionário | ClientIp |
Enrich_Graph_Username_Employee(T, mappingJson) | Expande o grafo com nós de funcionário | Username |
Enrich_Graph_Event_Authentication_Username(T, mappingJson) | Expande com nós de autenticação | Username |
Esquema JSON de Mapeamento
O mapeamento JSON tem dois arrays: node_types e edges.
node_types[]
| Campo | Obrigatório | Descrição |
|---|---|---|
type | Sim | Rótulo do tipo de nó (ex.: "User", "Host", "IP") |
id | Sim | Prefixo para o ID do nó; geralmente igual ao tipo |
key | Sim | Nome da coluna cujo valor se torna a identidade do nó |
props | Sim | Array de colunas para transportar como propriedades do nó |
defaults | Não | Objeto de valores de fallback para propriedades nulas/vazias |
defIcon | Não | URL do ícone padrão para este tipo de nó |
displayName | Não | Coluna a ser usada para o rótulo de exibição (padrão é id) |
color | Não | Coluna para obter a cor |
size | Não | Coluna para obter o tamanho |
edges[]
| Campo | Obrigatório | Descrição |
|---|---|---|
type | Sim | Rótulo do tipo de aresta (ex.: "AuthenticatesTo", "SentEmail") |
source | Sim | {"id": "<prefixo>", "type": "<TipoDoNo>"} |
target | Sim | {"id": "<prefixo>", "type": "<TipoDoNo>"} |
props | Não | Array de colunas para transportar como propriedades da aresta |
displayName | Não | Coluna para o rótulo da aresta |
color | Não | Coluna para a cor da aresta |
Repositório de Ícones
Use ícones de https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-icons/:
- IP:
Public-IP-Addresses-(Classic).svg - Host/VM:
Virtual-Machine.svg - Usuário:
Users.svg - Email:
Mailbox.svg(ouazure-cds/command-1070-Mail.svg) - Processo:
App-Services.svg - Arquivo:
Storage-Accounts.svg - Alerta:
Activity-Log.svg - Domínio:
DNS-Zones.svg
Regras de Geração de Mapeamento
Dadas as colunas da consulta fornecida e a descrição do grafo do usuário, gere o JSON de mapeamento:
- Identifique entidades -> cada substantivo distinto se torna um
node_type - Identifique relacionamentos -> cada verbo/preposição se torna uma
edge - Mapeie para colunas -> use colunas reais produzidas pela consulta fornecida; nunca assuma colunas indisponíveis
- Defina direção -> origem é o ator, destino é o alvo da ação
- Adicione propriedades -> inclua colunas relevantes para a investigação (carimbos de data/hora, resultados, hashes)
- Atribua ícones -> escolha do conjunto de ícones acima com base no tipo de entidade
Referência de Colunas (esquema unificado IRQL)
| Entidade | Coluna Chave | Propriedades Disponíveis |
|---|---|---|
| Usuário | Username | Username, Name, Role, Email |
| Host | Hostname | Hostname |
| IP | ClientIp | ClientIp |
| Mensagem de Email | Subject | EnvTime, Subject, Verdict, Url |
| Remetente | EmailSender | EmailSender, Domain |
| Destinatário | EmailRecipient | EmailRecipient |
| Processo | ProcessName | EnvTime, ProcessName, ProcessCommandLine, ProcessHash |
| Arquivo | Filename | EnvTime, Filename, Path, Sha256 |
| Domínio | DomainName | DomainName |
| Evento de Autenticação | (ID sintético) | EnvTime, UserAgent, Result, Description |
Seleção de Funções
- Comece com o pipeline tabular KQL/IRQL fornecido.
- Use
Lift_To_Graph(mapeamento)para criar entidades de grafo. - Adicione
Extract_Node_*,Enrich_Node_*ouEnrich_Graph_*apenas quando solicitado e compatível com as chaves mapeadas. - Adicione
Graph_Fold_By_Property()apenas quando o agrupamento/colapso for solicitado. - Termine a saída visual com
Graph_Render_View(). - Verifique previamente as funções armazenadas exatas selecionadas para o pipeline.
Padrão de Pipeline
// 1. Preserve a consulta KQL ou IRQL fornecida
<consulta de entrada>
// 2. Eleve para grafo
| invoke Lift_To_Graph(<json_de_mapeamento>)
// 3. Opcionalmente extraia ou enriqueça entidades de grafo
| invoke <Extract_Node_* | Enrich_Node_* | Enrich_Graph_*>()
// 4. Opcionalmente dobre nós quando solicitado
| invoke Graph_Fold_By_Property("<TipoDoNo>", "<NomeDaPropriedade>")
// 5. Renderize
| invoke Graph_Render_View()
Exemplos
Para prompts e exemplos práticos adicionais, consulte references/EXAMPLES.md.
Grafo de autenticação: IP -> AuthEvent -> Usuário -> Host
Consulta de entrada: Get_Event_Authentication_All | where Result == "Failed Login" | take 200
Solicitação de grafo: "Mostre IPs, eventos de autenticação, usuários e hosts; dobre eventos por resultado."
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()
Grafo de email: Remetente -> Mensagem -> Destinatário
Consulta de entrada: Get_Email_All | take 400
Solicitação de grafo: "Visualize o fluxo remetente-para-mensagem-para-destinatário e dobre mensagens por veredito."
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()
Investigação de domínio suspeito (ponta a ponta)
Solicitação básica de origem: "Use eventos de rede de saída para estes domínios suspeitos e faça um grafo das conexões IP-para-domínio enriquecidas com nomes de funcionários."
Este é o fallback limitado: um seletor conhecido, um extrator e um filtro direto.
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"],"defaults":{},"defIcon":"https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-icons/DNS-Zones.svg"}],"edges":[{"type":"ConnectedTo","source":{"id":"IP","type":"IP"},"target":{"id":"Domain","type":"Domain"},"props":["EnvTime"]}]}';
let suspicious_domains = dynamic(["malicious.com", "phishing.net"]);
Get_Event_Network_Outbound_All
| where DomainName in (suspicious_domains)
| project EnvTime, ClientIp, DomainName
| invoke Lift_To_Graph(suspicious_domain_mapping)
| invoke Enrich_Node_Ip_Employee()
| invoke Graph_Render_View()