Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Algumas APIs REST exigem chamadas sequenciais, em que a resposta de um ponto de extremidade fornece entrada que deve ser passada para outro ponto de extremidade. O Microsoft Sentinel Codeless Connector Framework (CCF) oferece suporte a esse padrão por meio de consulta aninhada à API para conectores RestApiPoller.
Importante
O polling de API aninhado está atualmente em pré-visualização pública. Os Termos Suplementares do Azure Preview incluem mais termos legais que se aplicam a recursos do Azure em beta, pré-visualização ou de outra forma ainda não lançados em disponibilidade geral.
Use a sondagem de API aninhada quando uma chamada da API pai exibir identificadores, cursores ou outros valores necessários para uma ou mais chamadas de API filho. O CCF extrai os valores necessários da resposta pai, os substitui na solicitação filho e envia as respostas filho para a tabela de destino configurada.
Configure o polling de API aninhado em um conector pull do CCF definindo a lógica de aninhamento nas regras de conexão RestApiPoller.
Para o processo de ponta a ponta para criar e empacotar um conector CCF, consulte Criar um conector sem código para Microsoft Sentinel. Você também pode usar a extensão Microsoft Sentinel para Visual Studio Code para implementar e testar fluxos de trabalho aninhados de pesquisa de APIs. Para informações sobre configuração e uso, veja Construir conectores personalizados com IA no Microsoft Sentinel. Para obter as propriedades padrão RestApiPoller de solicitação, resposta, autenticação, paginação e DCR, consulte a referência de regras de conexão do conector de dados RestApiPoller.
Note
Se você for um ISV (Fornecedor de Software Independente) criando uma integração Microsoft Sentinel usando o Codeless Connector Framework, a equipe do Microsoft App Assure poderá ajudar. Para envolver a equipe do App Assure, envie um email para azuresentinelpartner@microsoft.com.
Pré-requisitos
Antes de configurar a consulta aninhada de API, certifique-se de entender:
- Os pontos de extremidade da API de que o conector precisa chamar.
- Quais valores de resposta da chamada à API pai são exigidos pela chamada à API filho.
- O esquema de saída da tabela de destino.
- Como criar um conector CCF
RestApiPollerpadrão.
Um conector CCF completo inclui os seguintes componentes:
- Tabela: A tabela personalizada Log Analytics em que os dados ingeridos são armazenados.
- DCR: A regra de coleta de dados que define a transformação da ingestão.
- Interface do usuário do conector: a definição do conector de dados que aparece no hub de conteúdo do Microsoft Sentinel.
- Regras de conexão de dados: a configuração do conector que busca dados da API de origem.
A consulta de API aninhada está configurada nas regras de conexão de dados para um conector RestApiPoller.
O que é sondagem de API aninhada?
A sondagem de API aninhada é um padrão de sondagem do CCF que encadeia chamadas à API REST. A primeira chamada de API, chamada etapa pai, exibe valores que são necessários para chamadas posteriores de API, chamadas de etapas filho.
Por exemplo, uma API pode usar esse padrão:
-
GET /incidentsretorna uma lista de IDs de incidente. -
GET /incidents/{incidentId}/detailsretorna o registro de incidente completo para cada ID.
Uma única chamada à API não retorna os dados completos. O conector deve chamar o ponto de extremidade de lista, extrair cada incidentId e, em seguida, chamar o ponto de extremidade de detalhes uma vez para cada ID.
Use sondagem de API aninhada quando:
- Um ponto de extremidade de lista exibe IDs de recurso e um ponto de extremidade de detalhes requer cada ID no caminho do URL ou na cadeia de caracteres de consulta.
- Uma resposta pai exibe um cursor, um token de sessão, um ID de consulta ou um ID de referência que uma solicitação filho precisa.
- Uma resposta contém uma matriz de valores que devem ser passados individualmente para outro ponto de extremidade.
- A resposta pai contém os campos que você deseja manter, e a resposta filho adiciona dados de enriquecimento que devem ser combinados na mesma linha de saída.
Se uma única chamada à API retornar todos os dados necessários, a sondagem de API aninhada não será necessária. Use a propriedade padrão eventsJsonPaths para extrair registros da resposta.
Como funciona o polling aninhado de API
A sondagem de API aninhada está configurada com estas seções:
| Seção | Localidade | Purpose |
|---|---|---|
request |
Etapa pai | Define a solicitação de API principal. As propriedades da janela de tempo estão configuradas aqui. |
response |
Etapa pai | Define como os registros são extraídos da resposta pai. |
stepInfo |
Etapa pai | Ativa a sondagem aninhada e define as etapas filho a serem executadas em seguida. |
stepCollectorConfigs |
Etapa pai | Define cada etapa filho, incluindo a solicitação filho e o tratamento de resposta. |
shouldJoinNestedData |
Etapa filho | Define se a resposta filho substitui a saída pai ou se é unida ao registro pai. |
O fluxo de sondagem aninhado funciona da seguinte maneira:
- A solicitação pai é executada.
- A resposta principal é dividida em registros usando
response.eventsJsonPaths. -
stepPlaceholdersParsingKqlextrai os valores dos marcadores de cada registro pai. - O CCF substitui os marcadores na configuração da etapa secundária.
- O CCF executa as solicitações filho.
- A resposta filho é enviada como a linha de saída ou unida ao registro pai, dependendo do valor de
shouldJoinNestedData.
Modelo de configuração de sondagem aninhada
O exemplo a seguir mostra a estrutura de um conector RestApiPoller aninhado. As propriedades padrão do CCF são abreviadas com ....
{
"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 sondagem aninhadas
| Propriedade | Localidade | Descrição |
|---|---|---|
stepInfo.stepType |
Etapa pai | Deve ser definido como Nested para habilitar consultas aninhadas à API. |
stepInfo.nextSteps[].stepId |
Etapa pai | O nome da etapa filho. Esse valor deve corresponder a uma chave em stepCollectorConfigs. |
stepInfo.nextSteps[].stepPlaceholdersParsingKql |
Etapa pai | KQL que extrai valores da resposta pai. A consulta é executada em source, onde a coluna data contém cada registro pai como uma string JSON bruta. Cada coluna projetada se torna um marcador de posição. |
stepCollectorConfigs |
Etapa pai | Um mapa de definições de etapa filho, chaveada pelos stepId valores declarados em stepInfo.nextSteps. |
shouldJoinNestedData |
Etapa filho | Controla como a resposta filho é entregue à transmissão. Definida como false quando a resposta filho contém o registro de saída completo. Defina como true quando você precisar de campos das respostas pai e filho na mesma linha de saída. |
joinedDataStepName |
Etapa filho | O nome da coluna dynamic que armazena a resposta filho combinada quando shouldJoinNestedData é true. Não usado quando shouldJoinNestedData é false. |
Substituição do espaço reservado
Os placeholders são extraídos por stepPlaceholdersParsingKql e referenciados usando a sintaxe $placeholderName$.
Por exemplo, esse KQL cria um espaço reservado chamado incidentId:
source
| project res = parse_json(data)
| project incidentId = res.incidentId
A etapa filho pode então fazer referência ao espaço reservado como $incidentId$:
"apiEndpoint": "https://api.example.com/incidents/$incidentId$/details"
A substituição do espaço reservado é compatível com toda a configuração da etapa filho, incluindo a solicitação filho apiEndpoint, headers, queryParameters e queryParametersTemplate.
Configurar propriedades de solicitação filho
O bloco request dentro de uma etapa filho comporta as propriedades comuns de solicitação usadas para consulta periódica à API.
As propriedades comuns das solicitações filho incluem:
| Propriedade | Descrição |
|---|---|
apiEndpoint |
O ponto de extremidade filho da API. Você pode incluir marcadores como $incidentId$. |
httpMethod |
O método HTTP para a solicitação filha, como GET ou POST. |
headers |
Solicitar cabeçalhos para a chamada à API filho. Há suporte para substituição de espaço reservado. |
queryParameters |
Consultar parâmetros de cadeia de caracteres para a chamada à API filho. Há suporte para substituição de espaço reservado. |
queryParametersTemplate |
Modelo usado para cenários de conteúdo de consulta ou corpo da solicitação. Há suporte para substituição de espaço reservado. |
isPostPayloadJson |
Defina como true quando o conteúdo POST deve ser enviado como JSON. |
rateLimitQPS |
O número máximo de solicitações por segundo. |
rateLimitConfig |
Configuração de limite de taxa que pode usar cabeçalhos de limite de taxa retornados pela API. |
retryCount |
Número de tentativas de repetição. Padrão: 3. Intervalo com suporte: 1 para 6. |
timeoutInSeconds |
Tempo limite da solicitação em segundos. Padrão: 20. Intervalo com suporte: 1 para 180. |
A solicitação pai controla a janela de tempo da sondagem. Configure as propriedades da janela de tempo, como queryWindowInMin, queryTimeFormat, startTimeAttributeName e endTimeAttributeName, somente na solicitação principal. As etapas filho geralmente são orientadas por valores de espaço reservado extraídos da resposta pai.
Configurar o paralelismo das solicitações filho
maxParallelism controla quantas chamadas filho podem ser executadas simultaneamente. O valor padrão é 15.
maxParallelism não faz parte da configuração padrão do conector pai e não pode ser definida na etapa pai. Como as etapas filhas são transmitidas sem tradução dos nomes de campo, você pode definir maxParallelism dentro do bloco request de uma etapa filha, se algum ajuste for necessário.
"stepCollectorConfigs": {
"fetchIncidentDetails": {
"shouldJoinNestedData": false,
"request": {
"httpMethod": "GET",
"apiEndpoint": "https://api.contoso.com/incidents/$incidentId$/details",
"maxParallelism": 15
},
"response": {
"eventsJsonPaths": [ "$" ],
"format": "json"
}
}
}
Escolha se deseja unir dados pai e filho
Use shouldJoinNestedData para controlar como as respostas filho são entregues à transmissão.
Utilize shouldJoinNestedData: false
Defina shouldJoinNestedData como false quando a resposta pai fornecer apenas os valores necessários para a solicitação filho, e a resposta filho contiver o registro completo que você deseja ingerir.
Por exemplo, use false quando:
- A chamada pai exibe apenas os IDs dos incidentes.
- A chamada filho exibe os registros completos dos incidentes.
- Você não precisa preservar nenhum campo 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 para true quando você precisar de campos da resposta pai e da resposta filho na mesma linha de destino.
Por exemplo, use true quando:
- A chamada principal retorna campos de alerta, como ID do alerta, gravidade e hora da detecção.
- A chamada filho exibe campos de enriquecimento, como usuário afetado, IP de origem ou localização geográfica.
- A transformação DCR precisa associar ambos os campos pai e filho na tabela de destino.
Quando shouldJoinNestedData for true, defina joinedDataStepName como o nome da coluna dynamic que armazena a resposta filho.
"stepCollectorConfigs": {
"fetchAlertEnrichment": {
"shouldJoinNestedData": true,
"joinedDataStepName": "enrichment",
"request": {
"httpMethod": "GET",
"apiEndpoint": "https://api.contoso.com/alerts/$alertId$/enrichment"
},
"response": {
"eventsJsonPaths": [ "$" ],
"format": "json"
}
}
}
Exemplo: solicitação filho GET
Este exemplo usa uma API de incidentes da Contoso em duas etapas:
- A solicitação pai chama
GET /incidentse recebe uma lista de IDs de incidentes. -
stepPlaceholdersParsingKqlextraiincidentIdde cada registro pai. - A solicitação filho chama
GET /incidents/$incidentId$/detailsuma vez por ID de incidente. - As respostas filho são enviadas à transmissão como registros simples.
Resposta pai
{
"incidents": [
{ "incidentId": "INC-001" },
{ "incidentId": "INC-002" },
{ "incidentId": "INC-003" }
]
}
Resposta filho
{
"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: solicitação filho POST com corpo JSON
Algumas APIs exigem que os identificadores da resposta principal sejam enviados no corpo de uma requisição POST em vez do caminho da URL ou da string de consulta. Use queryParametersTemplate com isPostPayloadJson para este padrão.
Neste exemplo, a resposta pai exibe um incidentId, e a solicitação filho envia esse valor em um corpo POST 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 registro filho ao registro pai
Este exemplo usa uma API de alertas da Contoso em que a resposta principal contém campos que devem ser preservados, e a resposta secundária contém dados de enriquecimento.
Resposta pai
{
"alerts": [
{
"alertId": "ALT-001",
"severity": "High",
"detectedAt": "2026-05-30T14:22:00Z",
"riskScore": 92
}
]
}
Resposta filho
{
"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 registro pai quanto da resposta filho 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 e de paginação da etapa filho
A tradução do nome do campo se aplica somente à etapa pai. Cada entrada em stepCollectorConfigs é passada literalmente e não é remapeada. Como resultado, qualquer bloco auth ou paging dentro de uma etapa filha deve usar os nomes dos campos da etapa filha mostrados nas tabelas a seguir.
Campos de autenticação
| Nome do campo de etapa pai | Nome do campo de etapa filho |
|---|---|
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 |
UsernameAttributeName e UsernameAttributeValue / PasswordAttributeName e PasswordAttributeValue |
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 de etapa pai | Nome do campo de etapa filho |
|---|---|
pageSizeParameterName |
pageSizeParaName |
Todos os outros nomes dos campos de paginação e de resposta são os mesmos para etapas pai e filho.
Limits
A sondagem de API aninhada tem os seguintes limites:
| Limit | Descrição |
|---|---|
Etapas filho em stepCollectorConfigs |
Uma configuração aninhada comporta até quatro entradas em stepCollectorConfigs. |
Entradas em stepInfo.nextSteps |
stepInfo.nextSteps dá suporte a até três entradas. |
| Referências circulares | Não há suporte para referências de etapa circular e são rejeitadas durante a validação. |
Conclua o conector
Depois de configurar as regras de conexão aninhadas RestApiPoller, conclua os demais componentes do conector CCF:
- Crie ou atualize a tabela de destino.
- Crie o DCR e a transformação.
- Crie a definição da interface do conector.
- Empacote o conector em um modelo de implantação do ARM.
- Implante e teste o conector.
Para o processo de ponta a ponta, consulte Criar um conector sem código para Microsoft Sentinel.