Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
{
"name": "ContosoIncidentsConnector",
"apiVersion": "2022-09-01-preview",
"type": "Microsoft.SecurityInsights/dataConnectorDefinitions",
"location": "{{location}}",
"kind": "Customizable",
"availability": {
"isPreview": true
},
"properties": {
"connectorUiConfig": {
"id": "ContosoIncidentsConnector",
"title": "Contoso Incidents (CCF Nested API Accelerator)",
"publisher": "Contoso",
"descriptionMarkdown": "The **Contoso Incidents** connector demonstrates the CCF nested API polling pattern. It chains two REST API calls: a list endpoint that returns incident identifiers, followed by a detail endpoint called once per identifier. Deploy the included mock Contoso Incident API (Azure Function App) to observe the nested polling pattern end-to-end without a real data source.",
"graphQueriesTableName": "ContosoIncidents_CL",
"graphQueries": [
{
"metricName": "Incidents ingested",
"legend": "ContosoIncidents_CL",
"baseQuery": "{{graphQueriesTableName}}"
}
],
"sampleQueries": [
{
"description": "All ingested incidents",
"query": "ContosoIncidents_CL\n| sort by TimeGenerated desc"
},
{
"description": "High and Critical severity incidents",
"query": "ContosoIncidents_CL\n| where Severity in ('Critical', 'High')\n| sort by TimeGenerated desc"
},
{
"description": "Active incidents",
"query": "ContosoIncidents_CL\n| where Status == 'Active'\n| project TimeGenerated, IncidentId, Title, Severity, AffectedUser, SourceIp"
}
],
"dataTypes": [
{
"name": "ContosoIncidents_CL",
"lastDataReceivedQuery": "ContosoIncidents_CL\n| summarize Time = max(TimeGenerated)\n| where isnotempty(Time)"
}
],
"connectivityCriteria": [
{
"type": "IsConnectedQuery",
"value": [
"ContosoIncidents_CL\n| summarize LastLogReceived = max(TimeGenerated)\n| project IsConnected = LastLogReceived > ago(1d)"
]
}
],
"permissions": {
"resourceProvider": [
{
"provider": "Microsoft.OperationalInsights/workspaces",
"permissionsDisplayText": "Read and write permissions on the Log Analytics workspace are required.",
"providerDisplayName": "Workspace",
"scope": "Workspace",
"requiredPermissions": {
"write": true,
"read": true,
"delete": true
}
}
],
"customs": [
{
"name": "Contoso Mock API",
"description": "The Contoso Mock API Function App must be deployed before configuring this connector. After deployment, retrieve the Function App API key to use in Step 2."
}
]
},
"instructionSteps": [
{
"title": "STEP 1 — Deploy the Contoso Mock API",
"description": "Deploy the Azure Function App that serves as the mock Contoso Incident API:\n\n1. Deploy `MockApi/azuredeploy_MockApi.json` to a new resource group.\n2. Zip the `MockApi/` folder and run:\n```\naz functionapp deployment source config-zip --name <functionAppName> --resource-group <rg> --src contosoapi.zip\n```\n3. Retrieve the Function App API key:\n```\naz functionapp keys list --name <functionAppName> --resource-group <rg> --query functionKeys.default -o tsv\n```\n4. Note the `mockApiBaseUrl` deployment output (e.g. `https://contosomockapiXXXX.azurewebsites.net/api`).\n\nSee the [accelerator README](https://github.com/Azure/Azure-Sentinel/tree/master/Tools/CCF-Pull-Connector-Nested-Accelerator) for detailed steps or use GitHub Copilot agent mode with `agent-instructions.md` for fully automated deployment."
},
{
"title": "STEP 2 — Connect to the Contoso Mock API",
"description": "Enter the Mock API base URL and Function App API key, then click **Connect**.",
"instructions": [
{
"type": "Textbox",
"parameters": {
"label": "Mock API Base URL",
"placeholder": "https://contosomockapiXXXX.azurewebsites.net/api",
"type": "text",
"name": "mockApiBaseUrl"
}
},
{
"type": "Textbox",
"parameters": {
"label": "Function App API Key",
"placeholder": "Enter your Function App API key",
"type": "password",
"name": "ApiKey"
}
},
{
"type": "ConnectionToggleButton",
"parameters": {
"connectLabel": "connect",
"name": "connect"
}
}
]
}
]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"type": "Microsoft.Insights/dataCollectionRules",
"apiVersion": "2022-06-01",
"name": "ContosoIncidents-DCR",
"location": "{{location}}",
"properties": {
"dataCollectionEndpointId": "{{dataCollectionEndpoint}}",
"streamDeclarations": {
"Custom-ContosoIncidents_CL": {
"columns": [
{ "name": "TimeGenerated", "type": "datetime" },
{ "name": "incidentId", "type": "string" },
{ "name": "title", "type": "string" },
{ "name": "severity", "type": "string" },
{ "name": "status", "type": "string" },
{ "name": "affectedUser", "type": "string" },
{ "name": "sourceIp", "type": "string" }
]
}
},
"destinations": {
"logAnalytics": [
{
"workspaceResourceId": "{{workspaceResourceId}}",
"name": "sentinel-workspace"
}
]
},
"dataFlows": [
{
"streams": [ "Custom-ContosoIncidents_CL" ],
"destinations": [ "sentinel-workspace" ],
"transformKql": "source | extend TimeGenerated = now() | project TimeGenerated, IncidentId = ['incidentId'], Title = ['title'], Severity = ['severity'], Status = ['status'], AffectedUser = ['affectedUser'], SourceIp = ['sourceIp']",
"outputStream": "Custom-ContosoIncidents_CL"
}
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{
"type": "Microsoft.SecurityInsights/dataConnectors",
"apiVersion": "2024-09-01",
"name": "ContosoIncidents",
"location": "{{location}}",
"kind": "RestApiPoller",
"properties": {
"connectorDefinitionName": "ContosoIncidentsConnector",
"dataType": "ContosoIncidents_CL",
"dcrConfig": {
"streamName": "Custom-ContosoIncidents_CL",
"dataCollectionEndpoint": "{{dataCollectionEndpoint}}",
"dataCollectionRuleImmutableId": "{{dataCollectionRuleImmutableId}}"
},
"auth": {
"type": "APIKey",
"ApiKey": "{{ApiKey}}",
"ApiKeyName": "x-functions-key"
},
"request": {
"apiEndpoint": "{{mockApiBaseUrl}}/incidents",
"httpMethod": "GET",
"queryWindowInMin": 5,
"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": "{{mockApiBaseUrl}}/incidents/$incidentId$/details",
"headers": {
"Accept": "application/json"
}
},
"response": {
"eventsJsonPaths": [
"$"
],
"format": "json"
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
[
{
"name": "ContosoIncidents_CL",
"type": "Microsoft.OperationalInsights/workspaces/tables",
"apiVersion": "2022-10-01",
"properties": {
"plan": "Analytics",
"schema": {
"name": "ContosoIncidents_CL",
"columns": [
{
"name": "TimeGenerated",
"type": "datetime",
"description": "Ingestion timestamp, set to the time the record was received by the data collection endpoint."
},
{
"name": "IncidentId",
"type": "string",
"description": "Unique identifier of the incident (e.g. INC-001)."
},
{
"name": "Title",
"type": "string",
"description": "Short description of the incident."
},
{
"name": "Severity",
"type": "string",
"description": "Incident severity: Critical, High, Medium, or Low."
},
{
"name": "Status",
"type": "string",
"description": "Current status of the incident: Active, Investigating, Resolved, or Closed."
},
{
"name": "AffectedUser",
"type": "string",
"description": "UPN of the user associated with the incident."
},
{
"name": "SourceIp",
"type": "string",
"description": "Source IP address associated with the incident."
}
]
}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"Name": "ContosoIncidents",
"Author": "Microsoft",
"Logo": "<img src=\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Logos/Azure_Sentinel.svg\" width=\"75px\" height=\"75px\">",
"Description": "Demonstrates the CCF nested API polling pattern in Microsoft Sentinel. Includes a mock Contoso Incident API (Azure Function App) and a fully configured RestApiPoller connector that chains a list call to a detail call, ingesting complete incident records into the ContosoIncidents_CL table.",
"WorkbookDescription": [],
"Workbooks": [],
"Analytic Rules": [],
"Playbooks": [],
"Hunting Queries": [],
"Data Connectors": [
"Data Connectors/ContosoIncidents_CCF/ContosoIncidents_ConnectorDefinition.json"
],
"Parsers": [],
"Watchlists": [],
"BasePath": "C:\\GitHub\\Azure-Sentinel\\Tools\\CCF-Pull-Connector-Nested-Accelerator\\ContosoIncidents",
"Version": "1.0.0",
"Metadata": "SolutionMetadata.json",
"TemplateSpec": true,
"Is1PConnector": false
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
{
"$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#",
"handler": "Microsoft.Azure.CreateUIDef",
"version": "0.1.2-preview",
"parameters": {
"config": {
"isWizard": false,
"basics": {
"description": "<img src=\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Logos/Azure_Sentinel.svg\" width=\"75px\" height=\"75px\">\n\n**Note:** Please refer to the following before installing the solution: \n\n• Review the solution [Release Notes](https://github.com/Azure/Azure-Sentinel/tree/master/Solutions/ContosoIncidents/ReleaseNotes.md)\n\n • There may be [known issues](https://aka.ms/sentinelsolutionsknownissues) pertaining to this Solution, please refer to them before installing.\n\nDemonstrates the CCF nested API polling pattern in Microsoft Sentinel. Includes a mock Contoso Incident API (Azure Function App) and a fully configured RestApiPoller connector that chains a list call to a detail call, ingesting complete incident records into the ContosoIncidents_CL table.\n\n**Data Connectors:** 1\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)",
"subscription": {
"resourceProviders": [
"Microsoft.OperationsManagement/solutions",
"Microsoft.OperationalInsights/workspaces/providers/alertRules",
"Microsoft.Insights/workbooks",
"Microsoft.Logic/workflows"
]
},
"location": {
"metadata": {
"hidden": "Hiding location, we get it from the log analytics workspace"
},
"visible": false
},
"resourceGroup": {
"allowExisting": true
}
}
},
"basics": [
{
"name": "getLAWorkspace",
"type": "Microsoft.Solutions.ArmApiControl",
"toolTip": "This filters by workspaces that exist in the Resource Group selected",
"condition": "[greater(length(resourceGroup().name),0)]",
"request": {
"method": "GET",
"path": "[concat(subscription().id,'/providers/Microsoft.OperationalInsights/workspaces?api-version=2020-08-01')]"
}
},
{
"name": "workspace",
"type": "Microsoft.Common.DropDown",
"label": "Workspace",
"placeholder": "Select a workspace",
"toolTip": "This dropdown will list only workspace that exists in the Resource Group selected",
"constraints": {
"allowedValues": "[map(filter(basics('getLAWorkspace').value, (filter) => contains(toLower(filter.id), toLower(resourceGroup().name))), (item) => parse(concat('{\"label\":\"', item.name, '\",\"value\":\"', item.name, '\"}')))]",
"required": true
},
"visible": true
}
],
"steps": [
{
"name": "dataconnectors",
"label": "Data Connectors",
"bladeTitle": "Data Connectors",
"elements": [
{
"name": "dataconnectors1-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "This Solution installs the data connector for Contoso Incidents (CCF Nested API Accelerator). You can get Contoso Incidents (CCF Nested API Accelerator) data in your Microsoft Sentinel workspace. After installing the solution, configure and enable this data connector by following guidance in Manage solution view."
}
},
{
"name": "dataconnectors-link1",
"type": "Microsoft.Common.TextBlock",
"options": {
"link": {
"label": "Learn more about connecting data sources",
"uri": "https://docs.microsoft.com/azure/sentinel/connect-data-sources"
}
}
}
]
}
],
"outputs": {
"workspace-location": "[first(map(filter(basics('getLAWorkspace').value, (filter) => and(contains(toLower(filter.id), toLower(resourceGroup().name)),equals(filter.name,basics('workspace')))), (item) => item.location))]",
"location": "[location()]",
"workspace": "[basics('workspace')]"
}
}
}
Loading
Loading