一部の REST API にはシーケンシャル呼び出しが必要です。この呼び出しでは、あるエンドポイントからの応答によって、別のエンドポイントに渡す必要がある入力が提供されます。 Microsoft Sentinel Codeless Connector Framework (CCF) は、RestApiPoller コネクタの入れ子になった API ポーリングを通じてこのパターンをサポートします。
Von Bedeutung
ネストAPIポーリングは現在パブリックプレビュー中です。 Azureプレビュー補足条項には、ベータ版、プレビュー版、またはまだ一般公開されていないAzure機能に適用される法的用語が含まれています。
親 API 呼び出しが 1 つ以上の子 API 呼び出しで必要な識別子、カーソル、またはその他の値を返す場合は、入れ子になった API ポーリングを使用します。 CCF は、親応答から必要な値を抽出し、子要求に置き換えて、構成済みの宛先テーブルに子応答を送信します。
CCFプルコネクタでネストされたAPIポーリングを設定し、 RestApiPoller 接続ルールでネストロジックを定義します。
CCF コネクタを作成してパッケージ化するエンドツーエンドのプロセスについては、「Microsoft Sentinel用のコードレス コネクタの作成」を参照してください。 また、Visual Studio Code用のMicrosoft Sentinel拡張機能を使って、ネストされたAPIポーリングワークフローを実装・テストすることもできます。 セットアップおよび使用方法については、「Microsoft SentinelでAIでカスタムコネクタを構築」をご覧ください。 標準の RestApiPoller 要求、応答、認証、ページング、および DCR プロパティについては、 RestApiPoller データ コネクタの接続規則のリファレンスを参照してください。
Note
コードレス コネクタ フレームワークを使用してMicrosoft Sentinel統合を構築している独立系ソフトウェア ベンダー (ISV) の場合、Microsoft App Assure チームが支援できる場合があります。 App Assure チームと連携するには、 azuresentinelpartner@microsoft.comにメールを送信します。
前提条件
入れ子になった API ポーリングを構成する前に、次の内容を理解しておく必要があります。
- コネクタが呼び出す必要がある API エンドポイント。
- 子 API 呼び出しで必要な親 API 呼び出しからの応答値。
- 出力先テーブルの出力スキーマ。
- 標準の CCF
RestApiPollerコネクタを作成する方法。
完全な CCF コネクタには、次のコンポーネントが含まれています。
- テーブル: 取り込まれたデータが格納されるLog Analyticsカスタム テーブル。
- DCR: インジェスト変換を定義するデータ収集ルール。
- コネクタ UI: Microsoft Sentinel コンテンツ ハブに表示されるデータ コネクタ定義。
- データ接続規則: ソース API からデータをフェッチするコネクタ構成。
入れ子になった API ポーリングは、 RestApiPoller コネクタのデータ接続規則で構成されます。
ネストされた API ポーリングとは?
入れ子になった API ポーリングは、REST API 呼び出しをチェーンする CCF ポーリング パターンです。 親ステップと呼ばれる最初の API 呼び出しは、子ステップと呼ばれる、後の API 呼び出しで必要な値を返します。
たとえば、API では次のパターンを使用できます。
-
GET /incidentsはインシデント ID の一覧を返します。 -
GET /incidents/{incidentId}/detailsは、各 ID の完全なインシデント レコードを返します。
1 つの API 呼び出しでは、完全なデータは返されません。 コネクタは、リスト エンドポイントを呼び出し、各 incidentIdを抽出してから、ID ごとに詳細エンドポイントを 1 回呼び出す必要があります。
入れ子になった API ポーリングは、次の場合に使用します。
- リスト エンドポイントはリソース ID を返し、詳細エンドポイントには URL パスまたはクエリ文字列の各 ID が必要です。
- 親応答は、子要求に必要なカーソル、セッション トークン、クエリ ID、または参照 ID を返します。
- 応答には、それぞれ別のエンドポイントに個別に渡す必要がある値の配列が含まれています。
- 親応答には保持するフィールドが含まれており、子応答は同じ出力行に結合する必要があるエンリッチメント データを追加します。
1 つの API 呼び出しで必要なすべてのデータが返される場合、入れ子になった API ポーリングは必要ありません。 標準の eventsJsonPaths プロパティを使用して、応答からレコードを抽出します。
ネストされた API ポーリングの仕組み
入れ子になった API ポーリングは、次のセクションで構成されます。
| セクション | 場所 | Purpose |
|---|---|---|
request |
親手順 | 親 API 要求を定義します。 ここでは、時間枠のプロパティを構成します。 |
response |
親手順 | 親応答からレコードを抽出する方法を定義します。 |
stepInfo |
親手順 | ネストされたポーリングを有効にし、次に実行する子ステップを定義します。 |
stepCollectorConfigs |
親手順 | 子要求と応答の処理を含む、各子ステップを定義します。 |
shouldJoinNestedData |
子ステップ | 子応答が親の出力を置き換えるか、親レコードに結合するかを定義します。 |
入れ子になったポーリング フローは次のように動作します。
- 親リクエストが実行されます。
- 親応答は、
response.eventsJsonPathsを使用してレコードに分割されます。 -
stepPlaceholdersParsingKqlは、各親レコードからプレースホルダー値を抽出します。 - CCF はプレースホルダーを子ステップ構成に置き換えます。
- CCF は子リクエストを処理します。
- 子応答は、
shouldJoinNestedDataの値に応じて、出力行として送信されるか、親レコードに結合されます。
入れ子になったポーリング構成スケルトン
次の例は、入れ子になった RestApiPoller コネクタの構造を示しています。 標準 CCF プロパティは、 ...で省略されています。
{
"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"
}
}
}
}
}
入れ子になったポーリング プロパティ
| 財産 | 場所 | Description |
|---|---|---|
stepInfo.stepType |
親手順 | 入れ子になった API ポーリングを有効にするには、 Nested に設定する必要があります。 |
stepInfo.nextSteps[].stepId |
親手順 | 子手順の名前。 この値は、 stepCollectorConfigsのキーと一致する必要があります。 |
stepInfo.nextSteps[].stepPlaceholdersParsingKql |
親手順 | 親応答から値を抽出する KQL。 クエリは sourceに対して実行されます。 data 列には、生の JSON 文字列として各親レコードが含まれます。 投影された各列はプレースホルダーになります。 |
stepCollectorConfigs |
親手順 |
stepIdで宣言されたstepInfo.nextSteps値によってキー指定された子ステップ定義のマップ。 |
shouldJoinNestedData |
子ステップ | 子応答をストリームに配信する方法を制御します。 子応答に完全な出力レコードが含まれている場合に false に設定します。 同じ出力行に親応答と子応答の両方のフィールドが必要な場合は、 true に設定します。 |
joinedDataStepName |
子ステップ |
dynamicがshouldJoinNestedDataされたときに結合された子応答を格納するtrue列の名前。
shouldJoinNestedDataがfalseされている場合は使用されません。 |
プレースホルダーの置換
プレースホルダーは stepPlaceholdersParsingKql によって抽出され、 $placeholderName$ 構文で参照されます。
たとえば、次の KQL では、 incidentIdという名前のプレースホルダーが作成されます。
source
| project res = parse_json(data)
| project incidentId = res.incidentId
その後、子ステップはプレースホルダーを $incidentId$として参照できます。
"apiEndpoint": "https://api.example.com/incidents/$incidentId$/details"
プレースホルダーの置換は、子要求の apiEndpoint、 headers、 queryParameters、 queryParametersTemplateなど、子ステップ構成全体でサポートされます。
子リクエストのプロパティを設定
子ステップ内の request ブロックは、API ポーリングに使用される一般的な要求プロパティをサポートします。
一般的な子リクエストのプロパティには、次のものがあります。
| 財産 | Description |
|---|---|
apiEndpoint |
子 API エンドポイント。
$incidentId$などのプレースホルダーを含めることができます。 |
httpMethod |
GETやPOSTなど、子要求の HTTP メソッド。 |
headers |
子 API の呼び出し用のリクエスト ヘッダー。 プレースホルダーの置換がサポートされています。 |
queryParameters |
子 API 呼び出し用のクエリ文字列パラメーター。 プレースホルダーの置換がサポートされています。 |
queryParametersTemplate |
要求本文またはクエリ ペイロードのシナリオに使用されるテンプレート。 プレースホルダーの置換がサポートされています。 |
isPostPayloadJson |
POST ペイロードを JSON として送信する必要がある場合に true に設定します。 |
rateLimitQPS |
1 秒あたりの要求の最大数。 |
rateLimitConfig |
API によって返されるレート制限ヘッダーを使用できるレート制限構成。 |
retryCount |
再試行回数。 既定値: 3。 サポート範囲: 1 ~ 6。 |
timeoutInSeconds |
要求タイムアウト (秒単位)。 既定値: 20。 サポート範囲: 1 ~ 180。 |
親要求はポーリングの時間範囲を制御します。 親要求でのみ、 queryWindowInMin、 queryTimeFormat、 startTimeAttributeName、 endTimeAttributeName などの時間枠のプロパティを構成します。 子ステップは、通常、親応答から抽出されたプレースホルダー値によって駆動されます。
子リクエストの並列実行を設定する
maxParallelism は、同時に実行できる子呼び出しの数を制御します。 既定値は 15 です。
maxParallelism は標準の親コネクタ構成の一部ではなく、親ステップでは設定できません。 子ステップはフィールド名の変換なしで渡されるため、調整が必要な場合は、子ステップのmaxParallelism ブロック内でrequestを設定できます。
"stepCollectorConfigs": {
"fetchIncidentDetails": {
"shouldJoinNestedData": false,
"request": {
"httpMethod": "GET",
"apiEndpoint": "https://api.contoso.com/incidents/$incidentId$/details",
"maxParallelism": 15
},
"response": {
"eventsJsonPaths": [ "$" ],
"format": "json"
}
}
}
親データと子データを結合するかどうかを選択する
shouldJoinNestedDataを使用して、子応答をストリームに配信する方法を制御します。
shouldJoinNestedData: false を使用する
親応答が子要求に必要な値のみを提供し、子応答に取り込む完全なレコードが含まれている場合に、 shouldJoinNestedData を false に設定します。
たとえば、次の場合に false を使用します。
- 親呼び出しでは、インシデント ID のみが返されます。
- 子呼び出しは、完全なインシデント レコードを返します。
- 宛先の行に親フィールドを保持しておく必要はありません。
"stepCollectorConfigs": {
"fetchIncidentDetails": {
"shouldJoinNestedData": false,
"request": {
"httpMethod": "GET",
"apiEndpoint": "https://api.contoso.com/incidents/$incidentId$/details"
},
"response": {
"eventsJsonPaths": [ "$" ],
"format": "json"
}
}
}
shouldJoinNestedData: true を使用する
親応答と子応答の両方からのフィールドが同じ宛先行内に必要な場合は、shouldJoinNestedData を true に設定します。
たとえば、次の場合に true を使用します。
- 親呼び出しは、アラート ID、重大度、検出時間などのアラート フィールドを返します。
- 子呼び出しは、影響を受けるユーザー、ソース IP、位置情報などのエンリッチメント フィールドを返します。
- DCR 変換では、親フィールドと子フィールドの両方を変換先テーブルにマップする必要があります。
shouldJoinNestedDataがtrueされたら、子応答を格納するjoinedDataStepName列の名前にdynamicを設定します。
"stepCollectorConfigs": {
"fetchAlertEnrichment": {
"shouldJoinNestedData": true,
"joinedDataStepName": "enrichment",
"request": {
"httpMethod": "GET",
"apiEndpoint": "https://api.contoso.com/alerts/$alertId$/enrichment"
},
"response": {
"eventsJsonPaths": [ "$" ],
"format": "json"
}
}
}
例: GET 子要求
この例では、次の 2 ステップの Contoso インシデント API を使用します。
- 親リクエストは
GET /incidentsを呼び出し、インシデントIDの一覧を受け取ります。 -
stepPlaceholdersParsingKqlは、各親レコードからincidentIdを抽出します。 - 子リクエストは、インシデント ID ごとに一度
GET /incidents/$incidentId$/detailsを呼び出します。 - 子レスポンスは、フラットレコードとしてストリームに送信されます。
親応答
{
"incidents": [
{ "incidentId": "INC-001" },
{ "incidentId": "INC-002" },
{ "incidentId": "INC-003" }
]
}
子応答
{
"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"
}
ポーリング構成
{
"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"
}
}
}
}
}
例: JSON ボディを含む POST 子リクエスト
一部の API では、URL パスまたはクエリ文字列ではなく、親応答からの識別子を POST 本文で送信する必要があります。 このパターンでは、queryParametersTemplateをisPostPayloadJsonと一緒に使用します。
この例では、親応答は incidentIdを返し、子要求はその値を JSON POST 本文で送信します。
"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"
}
}
}
例: 子のエンリッチメント データを親レコードに結合する
この例では、親応答に保持する必要があるフィールドが含まれており、子応答にエンリッチメント データが含まれている Contoso アラート API を使用します。
親応答
{
"alerts": [
{
"alertId": "ALT-001",
"severity": "High",
"detectedAt": "2026-05-30T14:22:00Z",
"riskScore": 92
}
]
}
子応答
{
"alertId": "ALT-001",
"affectedUser": "bob@contoso.com",
"sourceIp": "198.51.100.77",
"geolocation": "US/Virginia",
"relatedIncidentId": "INC-042"
}
ポーリング構成
{
"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"
}
}
}
}
}
その後、DCR 変換では、親レコードと結合された子応答の両方のフィールドを投影できます。
例えば次が挙げられます。
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)
子手順認証用およびページング用のフィールド名
フィールド名の変換は、親ステップにのみ適用されます。
stepCollectorConfigs内の各エントリは逐語的に渡され、再マップされません。 その結果、子ステップ内の auth または paging ブロックでは、次の表に示す子ステップ フィールド名を使用する必要があります。
認証フィールド
| 親手順のフィールド名 | 子手順のフィールド名 |
|---|---|
type |
AuthType |
apiKey |
APIKey |
apiKeyName |
APIKeyName |
redirectUri OAuth2 の場合 |
RedirectionEndpoint |
isCredentialsInHeaders OAuth2 または JWT の場合 |
IsClientSecretInHeader |
grantType OAuth2 の場合 |
FlowName |
queryParameters JWT の場合 |
TokenEndpointQueryParameters |
isJsonRequest JWT の場合 |
IsTokenEndpointPostPayloadJson |
userName
/
password JWT またはセッション認証のキーと値のペア |
UsernameAttributeName と UsernameAttributeValue / PasswordAttributeName と PasswordAttributeValue |
OAuth2 の場合、 FlowName 値も変換されます。 たとえば、ClientCredentialsではなくclient_credentialsを使用し、AuthCodeの代わりにauthorization_codeを使用します。
ページング フィールド
| 親手順のフィールド名 | 子手順のフィールド名 |
|---|---|
pageSizeParameterName |
pageSizeParaName |
他のすべてのページングおよび応答フィールド名は、親ステップと子ステップで同じです。
Limits
入れ子になった API ポーリングには、次の制限があります。
| Limit | Description |
|---|---|
stepCollectorConfigs 内の子手順 |
入れ子になった構成では、 stepCollectorConfigsで最大 4 つのエントリがサポートされます。 |
stepInfo.nextSteps 内のエントリ |
stepInfo.nextSteps では、最大 3 つのエントリがサポートされます。 |
| 循環参照 | 循環ステップ参照はサポートされておらず、検証中は拒否されます。 |
コネクタを完成させます
入れ子になった RestApiPoller 接続規則を構成したら、残りの CCF コネクタ コンポーネントを完了します。
- コピー先テーブルを作成または更新します。
- DCR と変換を作成します。
- コネクタ UI 定義を作成します。
- ARM デプロイ テンプレートにコネクタをパッケージ化します。
- コネクタをデプロイしてテストします。
エンド ツー エンドプロセスについては、「Microsoft Sentinel用のコードレス コネクタを作成する」を参照してください。