Description: Canary supports outgoing Webhooks from your Console to an endpoint of your choice. This event-driven approach ensures that alerts are sent to you as they happen!
In this guide, we’ll send data to your Microsoft Sentinel instance, using an Azure Logic App deployed with ARM templates.
Note: This guide assumes that you have set up Sentinel as well as a Log Analytics Workspace. If not please follow the guide here.
Please ensure that all the ARM templates below are run in the same region and subscription as your workspace.
- Jump to setting up webhook alert logging by clicking here.
- If you are already receiving logs and would like a Sentinel Analytics Rule to create incidents from alerts, click here.
- For an example incident playbook to automatically ignore source IPs, click here.
Configuring Canary Webhooks to Sentinel.
Step 1: Deploy a log analytics API connection.
First, we’ll need to prepare the authentication connection between the Logic App and your workspace.
Head over to "Deploy a custom template" in your Azure portal and select Build your own template in the editor.
Paste the following schema into the editor and click Save.
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.Web/connections",
"apiVersion": "2016-06-01",
"name": "thinkstcanary_azureloganalyticsdatacollector",
"location": "[resourceGroup().location]",
"kind": "V1",
"properties": {
"api": {
"name": "thinkstcanary_azureloganalyticsdatacollector",
"displayName": "Azure Log Analytics Data Collector",
"description": "Azure Log Analytics Data Collector will send data to any Azure Log Analytics workspace.",
"iconUri": "https://connectoricons-prod.azureedge.net/releases/v1.0.1683/1.0.1683.3680/azureloganalyticsdatacollector/icon.png",
"brandColor": "#0072C6",
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/azureloganalyticsdatacollector')]",
"type": "Microsoft.Web/locations/managedApis"
}
}
}
]
}
Finally enter your preferred resource group name, and select Review + create when done.
After the validation has completed, and the resource is created, select the Go to resource button.
Step 2: Configure the log analytics API connection.
You'll now have landed on your newly created API connection. From here we want to authenticate the connection with your Log Analytics Workspace ID and Workspace Key. Once you’ve entered the ID and key, click Save to complete the setup.
If you're unsure of where to find your ID and key, head over to your Log Analytics Workspaces blade, then find them under the Agents UI as shown below.
Step 3: Deploy the webhook Logic App.
With your API connection all setup, let's head back over to "Deploy a custom template" in your Azure portal and select Build your own template in the editor once more.
Paste the following schema into the editor and click "save".
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"canaryConsoleDomain": {
"type": "String",
"defaultValue": "ABC123.canary.tools",
"metadata": {
"description": "The domain of your Canary console."
}
},
"canaryConsoleAnalystKey": {
"type": "SecureString",
"defaultValue": "ABC123",
"metadata": {
"description": "The analyst API key for your Canary Console."
}
}
},
"variables": {},
"resources": [
{
"type": "Microsoft.Logic/workflows",
"apiVersion": "2017-07-01",
"name": "Thinkst-Canary-Webhooks",
"location": "[resourceGroup().location]",
"properties": {
"state": "Enabled",
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"Canary_Console_Domain": {
"defaultValue": "[parameters('canaryConsoleDomain')]",
"type": "String"
},
"Canary_Console_Analyst_Key": {
"defaultValue": "[parameters('canaryConsoleAnalystKey')]",
"type": "String"
},
"$connections": {
"defaultValue": {},
"type": "Object"
}
},
"triggers": {
"Canary_Console_Webhook": {
"type": "Request",
"kind": "Http",
"inputs": {
"method": "POST"
}
}
},
"actions": {
"Parse_Webhook_Data": {
"runAfter": {},
"type": "ParseJson",
"inputs": {
"content": "@triggerBody()",
"schema": {
"type": "object",
"properties": {
"AdditionalDetails": {
"type": "array"
},
"AlertType": {
"type": "string"
},
"CanaryID": {
"type": "string"
},
"CanaryIP": {
"type": "string"
},
"CanaryLocation": {
"type": "string"
},
"CanaryName": {
"type": "string"
},
"CanaryNote": {
"type": "string"
},
"CanaryPort": {
"type": "integer"
},
"CanaryPublicIP": {
"type": "integer"
},
"Description": {
"type": "string"
},
"Flock": {
"type": "string"
},
"IncidentHash": {
"type": "string"
},
"IncidentKey": {
"type": "string"
},
"Intro": {
"type": "string"
},
"MatchedAnnotations": {
"type": "string"
},
"NumberOfDevices": {
"type": "integer"
},
"Reminder": {
"type": "string"
},
"ReverseDNS": {
"type": "string"
},
"SourceIP": {
"type": "string"
},
"Timestamp": {
"type": "string"
},
"TimestampGlobalTZ": {
"type": "string"
},
"Token": {
"type": "string"
},
"Triggered": {
"type": "string"
}
}
}
}
},
"Check_if_the_alert_is_a_test": {
"actions": {},
"runAfter": {
"Parse_Webhook_Data": [
"Succeeded"
]
},
"else": {
"actions": {
"Acknowledge_Incident_on_Console": {
"runAfter": {
"Send_Alert_to_Sentinel": [
"Succeeded"
]
},
"type": "Http",
"inputs": {
"uri": "@concat('https://', parameters('Canary_Console_Domain'), '/api/v1/incident/acknowledge')",
"method": "POST",
"headers": {
"X-Canary-Auth-Token": "@{parameters('Canary_Console_Analyst_Key')}"
},
"queries": {
"incident": "@{body('Parse_Webhook_Data')?['IncidentKey']}"
}
},
"runtimeConfiguration": {
"contentTransfer": {
"transferMode": "Chunked"
}
}
},
"Send_acknowledge_failure_to_Sentinel": {
"runAfter": {
"Acknowledge_Incident_on_Console": [
"TimedOut",
"Skipped",
"Failed"
]
},
"type": "ApiConnection",
"inputs": {
"host": {
"connection": {
"name": "@parameters('$connections')['azureloganalyticsdatacollector']['connectionId']"
}
},
"method": "post",
"body": "[[\n {\n \"Description\": \"Canary Logic App Failure.\",\n \"Intro\": \"Your Canary Webhook Logic App has experienced a failure, please check recent runs for any failures or contact support@canary.tools.\",\n \"AdditionalDetails\": \"Acknowledge API Operation Error Code: @{outputs('Acknowledge_Incident_on_Console')?['statusCode']}\",\n \"IncidentKey\": \"@{body('Parse_Webhook_Data')?['IncidentKey']}\"\n }\n ]",
"headers": {
"Log-Type": "Thinkst_Canary",
"time-generated-field": "@body('Parse_Webhook_Data')?['Timestamp']"
},
"path": "/api/logs"
}
},
"Send_Alert_to_Sentinel": {
"type": "ApiConnection",
"inputs": {
"host": {
"connection": {
"name": "@parameters('$connections')['azureloganalyticsdatacollector']['connectionId']"
}
},
"method": "post",
"body": "@triggerBody()",
"headers": {
"Log-Type": "Thinkst_Canary_Webhooks"
},
"path": "/api/logs"
}
}
}
},
"expression": {
"and": [
{
"equals": [
"@body('Parse_Webhook_Data')?['Flock']",
"flock:dummyincidentflock"
]
}
]
},
"type": "If"
}
},
"outputs": {}
},
"parameters": {
"$connections": {
"value": {
"azureloganalyticsdatacollector": {
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/azureloganalyticsdatacollector')]",
"connectionId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Web/connections/thinkstcanary_azureloganalyticsdatacollector')]",
"connectionName": "thinkstcanary_azureloganalyticsdatacollector"
}
}
}
}
}
}
]
}
Select the same resource group as before, and enter your Console domain and Analyst API Key —We'll use this to automatically acknowledge alerts later on. To find your domain and API Key, follow our guide here.
Select "Review + create" when done.
Note: If you'd prefer not to acknowledge incidents, you can leave these as their defaults.
After the validation has completed, and the resource is created, select the "Go to resource" button.
Step 4: (Optional) Disable Alert Acknowledgement.
If you prefer to not automatically acknowledge alerts in your Console, simply head over to the logic app designer screen and delete the 2 steps shown below.
Step 5: Configure your Console.
Head over to your new Logic App's overview screen and grab a copy of the webhook URL.
Head over to your Console’s webhook settings at the following URL and add the webhook:
https://EXAMPLE.canary.tools/nest/settings/webhooks
You're done! ;)
Analytics Rule to create incidents from alerts.
With Canary alert data now flowing into your Sentinel instance, you may want to generate incidents from new alerts, this is entirely optional and below we'll create an analytics rule to automatically make that happen.
Step 1: Import the Analytics Rule
Head over to your Azure Sentinel blade here. From here select your Sentinel instance, and import a predefined Analytics Rule.
Note:You’ll need at least one Canary —not CanaryToken— alert sent to Sentinel before this rule can be successfully imported.
The below schema can be saved as a file locally and uploaded using the Import option.
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"workspace": {
"type": "String"
}
},
"resources": [
{
"id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/06360572-94a7-42a4-add7-58fb933b2353')]",
"name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/06360572-94a7-42a4-add7-58fb933b2353')]",
"type": "Microsoft.OperationalInsights/workspaces/providers/alertRules",
"kind": "NRT",
"apiVersion": "2023-12-01-preview",
"properties": {
"displayName": "Canary Alerts To Incidents",
"description": "Creates Sentinel Incidents from Thinkst Canary Alerts",
"severity": "High",
"enabled": true,
"query": "Thinkst_Canary_Webhooks_CL\n| where Description_s <> \"Canary Disconnected\"\n| where Description_s <> \"Canary Reconnected\"\n| where Description_s <> \"Canary Settings Changed\"\n| where Description_s <> \"Fake Location\"\n| where Description_s <> \"Network Settings Roll-back\"",
"suppressionDuration": "PT5H",
"suppressionEnabled": false,
"tactics": [
"LateralMovement",
"Exfiltration"
],
"techniques": [],
"subTechniques": [],
"alertRuleTemplateName": null,
"incidentConfiguration": {
"createIncident": true,
"groupingConfiguration": {
"enabled": false,
"reopenClosedIncident": false,
"lookbackDuration": "PT5H",
"matchingMethod": "AllEntities",
"groupByEntities": [],
"groupByAlertDetails": [],
"groupByCustomDetails": []
}
},
"eventGroupingSettings": {
"aggregationKind": "AlertPerResult"
},
"alertDetailsOverride": {
"alertDisplayNameFormat": "{{{Description_s}}",
"alertDescriptionFormat": "{{Intro_s}}",
"alertDynamicProperties": []
},
"customDetails": {
"Events": "AdditionalDetails_s"
},
"entityMappings": [
{
"entityType": "IP",
"fieldMappings": [
{
"identifier": "Address",
"columnName": "SourceIP"
}
]
},
{
"entityType": "Host",
"fieldMappings": [
{
"identifier": "HostName",
"columnName": "ReverseDNS_s"
}
]
}
],
"sentinelEntitiesMappings": null,
"templateVersion": null
}
}
]
}
You'll now find the rule has been added.
Incidents will now be automatically created on new Canary alerts.
You're done! ;)
Sentinel Incident Playbooks.
You can also automate certain actions from incidents using other logic apps.
Below, we’ll walk through an example playbook that will ignore the source IP of an alert in your Canary Console.
Step 1: Deploy a Sentinel API connection.
First we'll need to prepare an authenticated connection between the logic app and your Sentinel instance.
Head over to "Deploy a custom template" in your Azure portal and select Build your own template in the editor.
Paste the following schema into the editor and click "save".
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.Web/connections",
"apiVersion": "2016-06-01",
"name": "thinkstcanary_azuresentinel",
"location": "[resourceGroup().location]",
"kind": "V1",
"properties": {
"api": {
"name": "thinkst_canary_azuresentinel",
"displayName": "Microsoft Sentinel",
"description": "Cloud-native SIEM with a built-in AI so you can focus on what matters most",
"iconUri": "https://connectoricons-prod.azureedge.net/releases/v1.0.1715/1.0.1715.3906/azuresentinel/icon.png",
"brandColor": "#0072C6",
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/azuresentinel')]",
"type": "Microsoft.Web/locations/managedApis"
}
}
}
]
}
Finally enter your preferred resource group name, and select "Review + create" when done.
After the validation has completed, and the resource is created, select the "Go to resource" button.
Step 2: Configure the Sentinel API connection.
You'll now have landed on your Sentinel API connection. Head over to Edit API connection and authorize the connection using your currently signed in account. Remember to select Save when you're done.
Step 3: Deploy the Sentinel Playbook.
With your API connection all setup, let's head back over to "Deploy a custom template" in your Azure portal and select Build your own template in the editor once more.
Paste the following schema into the editor and click "save".
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"canaryConsoleDomain": {
"type": "String",
"defaultValue": "ABC123.canary.tools",
"metadata": {
"description": "The domain of your Canary console."
}
},
"canaryConsoleGlobalKey": {
"type": "SecureString",
"defaultValue": "ABC123",
"metadata": {
"description": "The Global API key for your Canary Console."
}
}
},
"resources": [
{
"type": "Microsoft.Logic/workflows",
"apiVersion": "2017-07-01",
"name": "Thinkst-Canary-IgnoreIP",
"location": "[resourceGroup().location]",
"properties": {
"state": "Enabled",
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"Canary_Console_Global_Key": {
"defaultValue": "[parameters('canaryConsoleGlobalKey')]",
"type": "String"
},
"Canary_Console_Domain": {
"defaultValue": "[parameters('canaryConsoleDomain')]",
"type": "String"
},
"$connections": {
"defaultValue": {},
"type": "Object"
}
},
"triggers": {
"Microsoft_Sentinel_incident": {
"type": "ApiConnectionWebhook",
"inputs": {
"host": {
"connection": {
"name": "@parameters('$connections')['azuresentinel']['connectionId']"
}
},
"body": {
"callback_url": "@listCallbackUrl()"
},
"path": "/incident-creation"
}
}
},
"actions": {
"Entities_-_Get_IPs": {
"runAfter": {},
"type": "ApiConnection",
"inputs": {
"host": {
"connection": {
"name": "@parameters('$connections')['azuresentinel']['connectionId']"
}
},
"method": "post",
"body": "@triggerBody()?['object']?['properties']?['relatedEntities']",
"path": "/entities/ip"
}
},
"For_each": {
"foreach": "@body('Entities_-_Get_IPs')?['IPs']",
"actions": {
"Enable_Ignore_List": {
"type": "Http",
"inputs": {
"uri": "@concat('https://', parameters('Canary_Console_Domain'), '/api/v1/settings/whitelisting/enable')",
"method": "POST",
"headers": {
"X-Canary-Auth-Token": "@{parameters('Canary_Console_Global_Key')}"
}
},
"runtimeConfiguration": {
"contentTransfer": {
"transferMode": "Chunked"
}
}
},
"Ignore_IP": {
"runAfter": {
"Enable_Ignore_List": [
"Succeeded"
]
},
"type": "Http",
"inputs": {
"uri": "@concat('https://', parameters('Canary_Console_Domain'), '/api/v1/settings/whitelist_ip_port')",
"method": "POST",
"headers": {
"X-Canary-Auth-Token": "@{parameters('Canary_Console_Global_Key')}"
},
"queries": {
"src_ip": "@{item()?['Address']}"
}
},
"runtimeConfiguration": {
"contentTransfer": {
"transferMode": "Chunked"
}
}
}
},
"runAfter": {
"Entities_-_Get_IPs": [
"Succeeded"
]
},
"type": "Foreach"
}
},
"outputs": {}
},
"parameters": {
"$connections": {
"value": {
"azuresentinel": {
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/azuresentinel')]",
"connectionId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Web/connections/thinkstcanary_azuresentinel')]",
"connectionName": "thinkstcanary_azuresentinel"
}
}
}
}
}
}
]
}
Select your prefered resource group, and enter your Console domain, however this time we'll need a Global API Key in order to make changes to our Console. Follow our guide here, if you're not familiar with our key types.
Select "Review + create" when done.
Step 4: Try out your Sentinel Playbook.
With the playbook deployed, head over to your Azure Sentinel blade here, and navigate to your incidents. A playbook will now be available to run against incidents as shown below.
This particular playbook will add the alerts source IP to your Console's global ignore list here.
https://EXAMPLE.canary.tools/nest/settings/ignorelist