Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Algumas APIs REST exigem chamadas sequenciais, onde a resposta de um endpoint fornece input que deve ser passado para outro endpoint. O Microsoft Sentinel Codeless Connector Framework (CCF) suporta este padrão por meio de sondagem aninhada da API para conectores RestApiPoller.
Importante
A consulta aninhada à API está atualmente em versão prévia pública. Os Termos Suplementares do Azure Preview incluem mais termos legais que se aplicam a funcionalidades do Azure em beta, pré-visualização ou de outra forma ainda não lançadas em disponibilidade geral.
Utilize a sondagem aninhada da API quando uma chamada à API principal retorna identificadores, cursores ou outros valores necessários para uma ou mais chamadas à API subordinadas. O CCF extrai os valores necessários da resposta do pai, substitui-os no pedido filho e envia as respostas do filho para a tabela de destinos configurada.
Configure a sondagem aninhada da API num conector pull do CCF, definindo a lógica de aninhamento nas regras de conexão RestApiPoller.
Para o processo de ponta a ponta de criação e empacotamento de um conector CCF, veja Criar um conector sem código para Microsoft Sentinel. Também pode usar a extensão Microsoft Sentinel para Visual Studio Code para implementar e testar fluxos de trabalho de sondagem de API aninhados. Para informações de configuração e uso, consulte Construir conectores personalizados com IA no Microsoft Sentinel. Para as propriedades padrão RestApiPoller de pedido, resposta, autenticação, paginação e DCR, consulte a referência das regras de ligação do conector de dados RestApiPoller.
Note
Se é um Fornecedor Independente de Software (ISV) a construir uma integração com o Microsoft Sentinel usando o Codeless Connector Framework, a equipa do Microsoft App Assure poderá ajudar. Para envolver a equipe do App Assure, envie um e-mail para azuresentinelpartner@microsoft.com.
Pré-requisitos
Antes de configurar o questionamento de API aninhado, certifique-se de que compreende:
- Os endpoints da API que o conector tem de chamar.
- Que valores de resposta da chamada à API principal são necessários para a chamada à API subordinada.
- O esquema de saída para a tabela de destino.
- Como criar um conector CCF
RestApiPollerpadrão.
Um conector CCF completo inclui os seguintes componentes:
- Tabela: A tabela personalizada do Log Analytics onde os dados ingeridos são armazenados.
- DCR: A regra de recolha de dados que define a transformação da ingestão.
- Interface do Conector: A definição de conector de dados que aparece no hub de conteúdos do Microsoft Sentinel.
- Regras de ligação de dados: A configuração do conector que recolhe dados da API de origem.
A sondagem aninhada da API é configurada nas regras de ligação de dados para um conector RestApiPoller.
O que é a consulta aninhada da API?
A sondagem encadeada de API é um padrão de sondagem CCF que encadeia chamadas à API REST. A primeira chamada à API, designada por etapa pai, devolve os valores necessários para chamadas posteriores à API, designadas por etapas filhas.
Por exemplo, uma API pode usar este padrão:
-
GET /incidentsdevolve uma lista de IDs de incidentes. -
GET /incidents/{incidentId}/detailsretorna o registo completo do incidente para cada ID.
Uma única chamada à API não retorna os dados completos. O conector deve chamar o endpoint da lista, extrair cada incidentId, e depois chamar o endpoint de detalhes uma vez para cada ID.
Utilize o sondamento de API aninhado quando:
- Um endpoint de lista devolve IDs de recursos, e um endpoint de detalhes exige cada ID no caminho do URL ou na string de consulta.
- Uma resposta principal retorna um cursor, um token de sessão, o identificador da consulta ou o identificador de referência, de que um pedido subordinado necessita.
- Uma resposta contém um array de valores que devem ser passados individualmente para outro endpoint.
- A resposta principal contém os campos que pretende manter, e a resposta subordinada adiciona dados de enriquecimento que devem ser combinados numa única linha de saída.
Se uma única chamada de API devolver todos os dados de que precisas, não é necessário sondamento de API aninhado. Use a propriedade padrão eventsJsonPaths para extrair registos da resposta.
Como funciona o polling aninhado de APIs
A consulta periódica aninhada da API é configurada com estas secções:
| Seção | Location | Purpose |
|---|---|---|
request |
Passo principal | Define o pedido principal da API. As propriedades da janela temporal estão configuradas aqui. |
response |
Passo principal | Define como os registos são extraídos da resposta principal. |
stepInfo |
Passo principal | Permite a sondagem encadeada e define as etapas subordinadas a executar em seguida. |
stepCollectorConfigs |
Passo principal | Define cada etapa do filho, incluindo o pedido e o tratamento da resposta do filho. |
shouldJoinNestedData |
Passo de criança | Determina se a resposta do filho substitui a saída do pai ou é associada ao registo do pai. |
O fluxo de sondagem aninhada funciona da seguinte forma:
- O pedido principal é executado.
- A resposta dos pais é dividida em registos usando
response.eventsJsonPaths. -
stepPlaceholdersParsingKqlextrai valores de marcador de posição de cada registo principal. - O CCF substitui os marcadores de posição na configuração da etapa subordinada.
- A CCF trata dos pedidos de crianças.
- A resposta do filho é enviada como linha de saída ou juntada ao registo pai, dependendo do valor de
shouldJoinNestedData.
Esqueleto de configuração de sondagem encaixada
O exemplo seguinte mostra a estrutura de um conector RestApiPoller aninhado. As propriedades CCF padrão são abreviadas por ....
{
"kind": "RestApiPoller",
"properties": {
"connectorDefinitionName": "...",
"dcrConfig": { },
"dataType": "...",
"auth": { },
"request": {
"apiEndpoint": "https://api.example.com/incidents",
"httpMethod": "GET",
"queryWindowInMin": 60,
"queryTimeFormat": "yyyy-MM-ddTHH:mm:ssZ",
"startTimeAttributeName": "startTime",
"endTimeAttributeName": "endTime"
},
"response": {
"eventsJsonPaths": [ "$.incidents" ],
"format": "json"
},
"stepInfo": {
"stepType": "Nested",
"nextSteps": [
{
"stepId": "fetchIncidentDetails",
"stepPlaceholdersParsingKql": "source | project res = parse_json(data) | project incidentId = res.incidentId"
}
]
},
"stepCollectorConfigs": {
"fetchIncidentDetails": {
"shouldJoinNestedData": false,
"request": {
"httpMethod": "GET",
"apiEndpoint": "https://api.example.com/incidents/$incidentId$/details"
},
"response": {
"eventsJsonPaths": [ "$" ],
"format": "json"
}
}
}
}
}
Propriedades de votação aninhada
| Property | Location | Description |
|---|---|---|
stepInfo.stepType |
Passo principal | Deve estar definido como Nested para permitir a sondagem aninhada da API. |
stepInfo.nextSteps[].stepId |
Passo principal | O nome do padrasto da criança. Este valor deve corresponder a uma chave em stepCollectorConfigs. |
stepInfo.nextSteps[].stepPlaceholdersParsingKql |
Passo principal | KQL que extrai valores da resposta principal. A consulta é executada em source, na qual a coluna data contém cada registo principal como uma cadeia JSON em bruto. Cada coluna projetada passa a ser um marcador de posição. |
stepCollectorConfigs |
Passo principal | Um mapa de definições de passos subordinados, indexado pelos valores stepId declarados em stepInfo.nextSteps. |
shouldJoinNestedData |
Passo de criança | Controla como a resposta da criança é entregue ao fluxo. Definido para false quando a resposta do filho contém o registo de saída completo. Define para true quando precisares de campos tanto das respostas do pai como do filho na mesma linha de saída. |
joinedDataStepName |
Passo de criança | O nome da coluna dynamic que armazena a resposta do elemento filho associada quando shouldJoinNestedData é true. Não usado quando shouldJoinNestedData é false. |
Substituição provisória
Os marcadores de posição são extraídos por stepPlaceholdersParsingKql e referenciados com a sintaxe $placeholderName$.
Por exemplo, este KQL cria um marcador de posição chamado incidentId:
source
| project res = parse_json(data)
| project incidentId = res.incidentId
O passo filho pode então referenciar o marcador como $incidentId$:
"apiEndpoint": "https://api.example.com/incidents/$incidentId$/details"
A substituição de marcadores de posição é suportada em toda a configuração das etapas subordinadas, incluindo o apiEndpointpedido subordinadoheaders, queryParameters e queryParametersTemplate.
Configurar propriedades de pedidos filhos
O request bloco dentro de um passo filho suporta as propriedades comuns de pedido usadas para o sondamento de APIs.
Propriedades comuns de pedido de filhos incluem:
| Property | Description |
|---|---|
apiEndpoint |
A extremidade filha da API. Pode incluir marcadores de posição, como $incidentId$. |
httpMethod |
O método HTTP para o pedido filho, como GET ou POST. |
headers |
Cabeçalhos do pedido para a chamada à API subordinada. A substituição provisória é suportada. |
queryParameters |
Consultar parâmetros de string para a chamada API filha. A substituição provisória é suportada. |
queryParametersTemplate |
Modelo usado para cenários de corpo do pedido ou payload de consulta. A substituição provisória é suportada. |
isPostPayloadJson |
Definido para true quando o payload POST deve ser enviado como JSON. |
rateLimitQPS |
O número máximo de pedidos por segundo. |
rateLimitConfig |
Configuração de limite de taxa que pode usar cabeçalhos de limite de taxa devolvidos pela API. |
retryCount |
Número de tentativas de repetição. Padrão: 3. Alcance suportado: 1 até 6. |
timeoutInSeconds |
Tempo limite de solicitação em segundos. Padrão: 20. Alcance suportado: 1 até 180. |
O pedido principal controla a janela temporal de sondagem. Configure propriedades da janela temporal como queryWindowInMin, queryTimeFormat, startTimeAttributeName, e endTimeAttributeName apenas no pedido pai. Os passos filhos são geralmente orientados por valores provisórios extraídos da resposta do pai.
Configurar paralelismo de pedidos filho
maxParallelism Controla quantas chamadas filhas podem ser executadas simultaneamente. O valor predefinido é 15.
maxParallelism não faz parte da configuração padrão do conector pai e não pode ser definido na etapa principal. Como as etapas subordinadas são transmitidas sem tradução dos nomes dos campos, pode definir maxParallelism no bloco request de uma etapa subordinada, se for necessário fazer um ajuste.
"stepCollectorConfigs": {
"fetchIncidentDetails": {
"shouldJoinNestedData": false,
"request": {
"httpMethod": "GET",
"apiEndpoint": "https://api.contoso.com/incidents/$incidentId$/details",
"maxParallelism": 15
},
"response": {
"eventsJsonPaths": [ "$" ],
"format": "json"
}
}
}
Escolha se quer juntar os dados pais e filhos
Use shouldJoinNestedData para controlar como as respostas da criança são entregues ao fluxo.
Utilize shouldJoinNestedData: false
Defina shouldJoinNestedData como false quando a resposta principal inclui apenas os valores necessários para o pedido subordinado, e a resposta subordinada contém o registo completo que pretende importar.
Por exemplo, use false quando:
- A chamada principal retorna apenas os IDs dos incidentes.
- A chamada da criança devolve os registos completos do incidente.
- Não é necessário manter quaisquer campos pai na linha de destino.
"stepCollectorConfigs": {
"fetchIncidentDetails": {
"shouldJoinNestedData": false,
"request": {
"httpMethod": "GET",
"apiEndpoint": "https://api.contoso.com/incidents/$incidentId$/details"
},
"response": {
"eventsJsonPaths": [ "$" ],
"format": "json"
}
}
}
Utilize shouldJoinNestedData: true
Defina shouldJoinNestedData como true quando precisar de campos tanto da resposta principal como da resposta secundária na mesma linha de destino.
Por exemplo, use true quando:
- A chamada principal devolve campos de alerta como ID do alerta, gravidade e tempo de deteção.
- A chamada subordinada retorna campos de enriquecimento, como o utilizador afetado, o IP de origem ou a geolocalização.
- A transformação DCR precisa de mapear tanto os campos pai como filho na tabela de destino.
Quando shouldJoinNestedData for true, defina joinedDataStepName como o nome da coluna dynamic que armazena a resposta subordinada.
"stepCollectorConfigs": {
"fetchAlertEnrichment": {
"shouldJoinNestedData": true,
"joinedDataStepName": "enrichment",
"request": {
"httpMethod": "GET",
"apiEndpoint": "https://api.contoso.com/alerts/$alertId$/enrichment"
},
"response": {
"eventsJsonPaths": [ "$" ],
"format": "json"
}
}
}
Exemplo: pedido de criança GET
Este exemplo utiliza uma API incidental Contoso em dois passos:
- O pedido principal chama
GET /incidentse recebe uma lista de IDs de incidente. -
stepPlaceholdersParsingKqlextraiincidentIdde cada registo principal. - O pedido da criança liga
GET /incidents/$incidentId$/detailsuma vez por cada identificação do incidente. - As respostas das crianças são enviadas para o fluxo como registos planos.
Resposta dos pais
{
"incidents": [
{ "incidentId": "INC-001" },
{ "incidentId": "INC-002" },
{ "incidentId": "INC-003" }
]
}
Resposta da criança
{
"incidentId": "INC-001",
"title": "Suspicious login attempt",
"severity": "High",
"status": "Active",
"createdAt": "2026-05-30T14:22:00Z",
"affectedUser": "alice@contoso.com",
"sourceIp": "198.51.100.42"
}
Configuração de sondagem
{
"kind": "RestApiPoller",
"properties": {
"connectorDefinitionName": "ContosoIncidentsConnector",
"dcrConfig": {
"dataCollectionEndpoint": "{{dataCollectionEndpoint}}",
"dataCollectionRuleImmutableId": "{{dataCollectionRuleImmutableId}}",
"streamName": "Custom-ContosoIncidents_CL"
},
"dataType": "ContosoIncidents_CL",
"auth": {
"type": "APIKey",
"ApiKey": "{{apiKey}}",
"ApiKeyName": "x-functions-key"
},
"request": {
"apiEndpoint": "https://api.contoso.com/incidents",
"httpMethod": "GET",
"queryWindowInMin": 60,
"queryTimeFormat": "yyyy-MM-ddTHH:mm:ssZ",
"startTimeAttributeName": "startTime",
"endTimeAttributeName": "endTime",
"headers": {
"Accept": "application/json"
}
},
"response": {
"eventsJsonPaths": [ "$.incidents" ],
"format": "json"
},
"stepInfo": {
"stepType": "Nested",
"nextSteps": [
{
"stepId": "fetchIncidentDetails",
"stepPlaceholdersParsingKql": "source | project res = parse_json(data) | project incidentId = res.incidentId"
}
]
},
"stepCollectorConfigs": {
"fetchIncidentDetails": {
"shouldJoinNestedData": false,
"request": {
"httpMethod": "GET",
"apiEndpoint": "https://api.contoso.com/incidents/$incidentId$/details",
"headers": {
"Accept": "application/json"
},
"retryCount": 3,
"timeoutInSeconds": 60
},
"response": {
"eventsJsonPaths": [ "$" ],
"format": "json"
}
}
}
}
}
Exemplo: pedido de criança POST com corpo JSON
Algumas APIs exigem que os identificadores da resposta principal sejam enviados no corpo de um pedido POST em vez de no caminho do URL ou na cadeia de consulta. Utilize queryParametersTemplate com isPostPayloadJson para este padrão.
Neste exemplo, a resposta principal retorna um incidentId, e o pedido dependente envia esse valor num corpo POST em JSON.
"stepCollectorConfigs": {
"fetchIncidentDetails": {
"shouldJoinNestedData": false,
"request": {
"httpMethod": "POST",
"apiEndpoint": "https://api.contoso.com/incidents/details:batchGet",
"headers": {
"Accept": "application/json",
"Content-Type": "application/json"
},
"queryParametersTemplate": "{'ids': ['$incidentId$']}",
"isPostPayloadJson": true,
"retryCount": 3,
"timeoutInSeconds": 60
},
"response": {
"eventsJsonPaths": [ "$.items" ],
"format": "json"
}
}
}
Exemplo: Associar dados de enriquecimento do registo filho ao registo pai
Este exemplo utiliza uma API de alerta Contoso onde a resposta principal contém campos que devem ser preservados, e a resposta filha contém dados de enriquecimento.
Resposta dos pais
{
"alerts": [
{
"alertId": "ALT-001",
"severity": "High",
"detectedAt": "2026-05-30T14:22:00Z",
"riskScore": 92
}
]
}
Resposta da criança
{
"alertId": "ALT-001",
"affectedUser": "bob@contoso.com",
"sourceIp": "198.51.100.77",
"geolocation": "US/Virginia",
"relatedIncidentId": "INC-042"
}
Configuração de sondagem
{
"kind": "RestApiPoller",
"properties": {
"connectorDefinitionName": "ContosoAlertsConnector",
"dcrConfig": {
"dataCollectionEndpoint": "{{dataCollectionEndpoint}}",
"dataCollectionRuleImmutableId": "{{dataCollectionRuleImmutableId}}",
"streamName": "Custom-ContosoAlerts_CL"
},
"dataType": "ContosoAlerts_CL",
"auth": {
"type": "APIKey",
"ApiKey": "{{apiKey}}",
"ApiKeyName": "x-functions-key"
},
"request": {
"apiEndpoint": "https://api.contoso.com/alerts",
"httpMethod": "GET",
"queryWindowInMin": 60,
"queryTimeFormat": "yyyy-MM-ddTHH:mm:ssZ",
"startTimeAttributeName": "startTime",
"endTimeAttributeName": "endTime"
},
"response": {
"eventsJsonPaths": [ "$.alerts" ],
"format": "json"
},
"stepInfo": {
"stepType": "Nested",
"nextSteps": [
{
"stepId": "fetchAlertEnrichment",
"stepPlaceholdersParsingKql": "source | project res = parse_json(data) | project alertId = res.alertId"
}
]
},
"stepCollectorConfigs": {
"fetchAlertEnrichment": {
"shouldJoinNestedData": true,
"joinedDataStepName": "enrichment",
"request": {
"httpMethod": "GET",
"apiEndpoint": "https://api.contoso.com/alerts/$alertId$/enrichment"
},
"response": {
"eventsJsonPaths": [ "$" ],
"format": "json"
}
}
}
}
}
A transformação DCR pode então projetar campos tanto do registo pai como da resposta filha associada.
Por exemplo:
source
| extend enrichment = todynamic(enrichment)
| project
TimeGenerated = todatetime(detectedAt),
AlertId = tostring(alertId),
Severity = tostring(severity),
RiskScore = toint(riskScore),
AffectedUser = tostring(enrichment.affectedUser),
SourceIp = tostring(enrichment.sourceIp),
Geolocation = tostring(enrichment.geolocation),
RelatedIncidentId = tostring(enrichment.relatedIncidentId)
Nomes dos campos de autenticação por passos e paginação dos filhos
A tradução de nomes de campo aplica-se apenas à etapa principal. Cada entrada em stepCollectorConfigs é transmitida textualmente e não é remapeada. Como resultado, qualquer bloco auth ou paging dentro de um passo filho deve usar os nomes dos campos do passo filho mostrados nas tabelas seguintes.
Campos de autenticação
| Nome do campo da etapa principal | Nome do campo da subetapa |
|---|---|
type |
AuthType |
apiKey |
APIKey |
apiKeyName |
APIKeyName |
redirectUri para OAuth2 |
RedirectionEndpoint |
isCredentialsInHeaders para OAuth2 ou JWT |
IsClientSecretInHeader |
grantType para OAuth2 |
FlowName |
queryParameters para JWT |
TokenEndpointQueryParameters |
isJsonRequest para JWT |
IsTokenEndpointPostPayloadJson |
userName
/
password pares chave-valor para JWT ou autenticação de sessão |
UsernameAttributeNamee UsernameAttributeValue / PasswordAttributeNamePasswordAttributeValue |
Para OAuth2, o FlowName valor também é transformado. Por exemplo, use ClientCredentials em vez de client_credentials, e AuthCode em vez de authorization_code.
Campos de paginação
| Nome do campo da etapa principal | Nome do campo da subetapa |
|---|---|
pageSizeParameterName |
pageSizeParaName |
Todos os outros nomes dos campos de paginação e resposta são iguais para os passos pais e filhos.
Limits
A consulta encadeada da API tem os seguintes limites:
| Limit | Description |
|---|---|
A criança intervém stepCollectorConfigs |
Uma configuração aninhada suporta até quatro entradas em stepCollectorConfigs. |
Entradas em stepInfo.nextSteps |
stepInfo.nextSteps suporta até três entradas. |
| Referências circulares | As referências circulares por passos não são suportadas e são rejeitadas durante a validação. |
Conclua o conector
Depois de configurar as regras de ligação aninhada RestApiPoller , complete os restantes componentes do conector CCF:
- Crie ou atualize a tabela de destinos.
- Crie o DCR e a transformação.
- Crie a definição da interface de utilizador do conector.
- Empacota o conector num modelo de implementação ARM.
- Desdobrar e testar o conector.
Para o processo de ponta a ponta, veja Criar um conector sem código para o Microsoft Sentinel.