diff --git a/.script/tests/KqlvalidationsTests/CustomTables/ThinkstCanaryIncidents_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/ThinkstCanaryIncidents_CL.json
new file mode 100644
index 00000000000..9d43d5a36fd
--- /dev/null
+++ b/.script/tests/KqlvalidationsTests/CustomTables/ThinkstCanaryIncidents_CL.json
@@ -0,0 +1,121 @@
+{
+ "Name": "ThinkstCanaryIncidents_CL",
+ "Properties": [
+ {
+ "Name": "TimeGenerated",
+ "Type": "datetime"
+ },
+ {
+ "Name": "IncidentId",
+ "Type": "string"
+ },
+ {
+ "Name": "Description",
+ "Type": "string"
+ },
+ {
+ "Name": "Acknowledged",
+ "Type": "string"
+ },
+ {
+ "Name": "Created",
+ "Type": "real"
+ },
+ {
+ "Name": "CreatedPrintable",
+ "Type": "string"
+ },
+ {
+ "Name": "DestinationIP",
+ "Type": "string"
+ },
+ {
+ "Name": "DestinationPort",
+ "Type": "string"
+ },
+ {
+ "Name": "EventsCount",
+ "Type": "string"
+ },
+ {
+ "Name": "Events",
+ "Type": "dynamic"
+ },
+ {
+ "Name": "FlockId",
+ "Type": "string"
+ },
+ {
+ "Name": "FlockName",
+ "Type": "string"
+ },
+ {
+ "Name": "HashId",
+ "Type": "string"
+ },
+ {
+ "Name": "Host",
+ "Type": "dynamic"
+ },
+ {
+ "Name": "IpAddress",
+ "Type": "string"
+ },
+ {
+ "Name": "IncidentUpdated",
+ "Type": "datetime"
+ },
+ {
+ "Name": "LocalTime",
+ "Type": "string"
+ },
+ {
+ "Name": "Memo",
+ "Type": "string"
+ },
+ {
+ "Name": "RawEvent",
+ "Type": "dynamic"
+ },
+ {
+ "Name": "LogType",
+ "Type": "string"
+ },
+ {
+ "Name": "NodeId",
+ "Type": "string"
+ },
+ {
+ "Name": "Notified",
+ "Type": "string"
+ },
+ {
+ "Name": "PreviouslySeenCount",
+ "Type": "real"
+ },
+ {
+ "Name": "Sensor",
+ "Type": "string"
+ },
+ {
+ "Name": "SourceIP",
+ "Type": "string"
+ },
+ {
+ "Name": "SrcHostReverse",
+ "Type": "string"
+ },
+ {
+ "Name": "SourcePort",
+ "Type": "string"
+ },
+ {
+ "Name": "UpdatedId",
+ "Type": "real"
+ },
+ {
+ "Name": "UpdatedTimePrintable",
+ "Type": "string"
+ }
+ ]
+}
diff --git a/.script/tests/detectionTemplateSchemaValidation/ValidConnectorIds.json b/.script/tests/detectionTemplateSchemaValidation/ValidConnectorIds.json
index e6974fcbab5..814a724c04e 100644
--- a/.script/tests/detectionTemplateSchemaValidation/ValidConnectorIds.json
+++ b/.script/tests/detectionTemplateSchemaValidation/ValidConnectorIds.json
@@ -342,6 +342,7 @@
"CayosoftGuardianConnector",
"VaronisSaaSAlertsPush",
"RecordedFutureIdentityAlertImporter",
+ "ThinkstCanary",
"VectraRUXConnector",
"cybereinforce_cte"
-]
\ No newline at end of file
+]
diff --git a/Logos/ThinkstCanary.svg b/Logos/ThinkstCanary.svg
new file mode 100644
index 00000000000..5c110fea150
--- /dev/null
+++ b/Logos/ThinkstCanary.svg
@@ -0,0 +1,4 @@
+
diff --git a/Solutions/ThinkstCanary/Analytic Rules/SentinelIncidentsFromThinkstCanaryAlerts.yaml b/Solutions/ThinkstCanary/Analytic Rules/SentinelIncidentsFromThinkstCanaryAlerts.yaml
new file mode 100644
index 00000000000..95ca39946dd
--- /dev/null
+++ b/Solutions/ThinkstCanary/Analytic Rules/SentinelIncidentsFromThinkstCanaryAlerts.yaml
@@ -0,0 +1,120 @@
+id: 06360572-94a7-42a4-add7-58fb933b2353
+name: Canary alerts to incidents
+description: Creates Microsoft Sentinel incidents from Thinkst Canary alerts.
+severity: High
+status: Available
+requiredDataConnectors:
+ - connectorId: ThinkstCanary
+ dataTypes:
+ - ThinkstCanaryIncidents_CL
+tactics:
+ - LateralMovement
+ - Exfiltration
+relevantTechniques: []
+query: |
+ ThinkstCanaryIncidents_CL
+ | where Description != "Canary Disconnected"
+ | where Description != "Canary Reconnected"
+ | where Description != "Canary Settings Changed"
+ | where Description != "Fake Location"
+ | where Description != "Network Settings Roll-back"
+ | extend EventData = todynamic(RawEvent[0])
+ | extend IsCanarytoken = Description contains "Canarytoken"
+ or LogType startswith "16"
+ or LogType startswith "17"
+ or isnotempty(tostring(EventData.canarytoken))
+ | extend PhysicalCanaryName = coalesce(tostring(Host.name), NodeId),
+ PhysicalCanaryIP = coalesce(tostring(Host.ip_address), DestinationIP, IpAddress),
+ TokenMemo = iff(IsCanarytoken, substring(Memo, 0, 256), ""),
+ TokenType = coalesce(tostring(EventData.kind), tostring(EventData.type)),
+ TokenHostname = tostring(EventData.hostname),
+ TokenTarget = substring(coalesce(tostring(EventData.url), tostring(EventData.hostname), tostring(EventData.cloned_site), tostring(EventData.original_site), tostring(EventData.generic_data), tostring(EventData.location)), 0, 512),
+ TokenUsername = coalesce(tostring(EventData.windows_desktopini_access_username), tostring(EventData.ms_macro_username), tostring(EventData.cmd_user_name)),
+ TokenDomain = coalesce(tostring(EventData.windows_desktopini_access_domain), tostring(EventData.cmd_machine_name)),
+ TokenHost = coalesce(tostring(EventData.windows_desktopini_computer_name), tostring(EventData.cmd_computer_name), tostring(EventData.cmd_workstation), tostring(EventData.cmd_machine_name)),
+ TokenSourceIP = coalesce(tostring(EventData.cmd_resolved_ip), tostring(EventData.ms_macro_ip)),
+ TokenCity = coalesce(tostring(EventData.geoip.city), tostring(EventData.geoip.City), tostring(EventData.City)),
+ TokenCountry = coalesce(tostring(EventData.geoip.country), tostring(EventData.geoip.country_name), tostring(EventData.geoip.Country), tostring(EventData.Country)),
+ TokenContext = case(
+ isnotempty(tostring(EventData.client_public_key)), strcat("WireGuard public key: ", substring(tostring(EventData.client_public_key), 0, 128), "; session: ", tostring(EventData.client_session_index)),
+ isnotempty(tostring(EventData.masked_card_number)), strcat("Masked card: ", tostring(EventData.masked_card_number), "; transaction: ", tostring(EventData.transaction_amount), " ", tostring(EventData.transaction_currency), "; merchant: ", tostring(EventData.merchant)),
+ isnotempty(tostring(EventData.referer)), strcat("Referrer: ", substring(tostring(EventData.referer), 0, 256)),
+ ""),
+ UserAgent = substring(coalesce(tostring(EventData.USERAGENT), tostring(EventData.HEADERS['user-agent']), tostring(EventData.headers['User-Agent']), tostring(EventData.headers['user-agent'])), 0, 512)
+ | extend ActorUsername = coalesce(tostring(EventData.USERNAME), tostring(EventData.USER), tostring(EventData.FORMDATA.username), tostring(EventData.POSTDATA.username), TokenUsername),
+ ActorDomain = coalesce(tostring(EventData.DOMAIN), tostring(EventData.DOMAINNAME), TokenDomain),
+ ActorHost = coalesce(TokenHost, tostring(EventData.HOSTNAME)),
+ Activity = coalesce(TokenContext, TokenType, tostring(EventData.INSTANCE_NAME), tostring(EventData.FUNC_NAME), tostring(EventData.METHOD), tostring(EventData.OPCODE), tostring(EventData.COMMAND), tostring(EventData.FUNCTION), Description)
+ | extend SourceIP = coalesce(SourceIP, tostring(EventData.src_host), TokenSourceIP),
+ SourceGeo = case(isnotempty(TokenCity) and isnotempty(TokenCountry), strcat(TokenCity, ", ", TokenCountry), isnotempty(TokenCity), TokenCity, TokenCountry),
+ AssetType = iff(IsCanarytoken, "Canarytoken", "Canary"),
+ AssetName = iff(IsCanarytoken, coalesce(TokenMemo, TokenTarget, TokenType, NodeId), PhysicalCanaryName),
+ AssetNode = NodeId,
+ AssetIP = iff(IsCanarytoken, "", PhysicalCanaryIP),
+ AssetLocation = iff(IsCanarytoken, "", tostring(Host.description)),
+ CanaryEntityName = iff(IsCanarytoken, "", PhysicalCanaryName),
+ CanaryEntityIP = iff(IsCanarytoken, "", PhysicalCanaryIP)
+ | extend SourceDisplay = coalesce(SourceIP, SrcHostReverse, "unknown source")
+ | project TimeGenerated, Description, IncidentId, AssetType, AssetName, AssetNode,
+ AssetIP, AssetLocation, FlockName, TokenMemo, TokenType, TokenTarget,
+ TokenHostname, ActorUsername, ActorDomain, ActorHost, SourceGeo, SourceIP,
+ SourceDisplay, SrcHostReverse, DestinationPort, Activity, UserAgent, LogType,
+ EventsCount, CanaryEntityName, CanaryEntityIP
+suppressionDuration: 1h
+suppressionEnabled: false
+eventGroupingSettings:
+ aggregationKind: AlertPerResult
+alertDetailsOverride:
+ alertDisplayNameFormat: '{{Description}} - {{AssetName}} from {{SourceDisplay}}'
+ alertDescriptionFormat: 'Thinkst {{AssetType}} {{AssetName}} recorded this activity from {{SourceDisplay}}. Review the mapped entities and custom details for asset, actor, and activity context.'
+customDetails:
+ AssetType: AssetType
+ AssetName: AssetName
+ AssetNode: AssetNode
+ AssetIP: AssetIP
+ AssetLocation: AssetLocation
+ FlockName: FlockName
+ TokenMemo: TokenMemo
+ TokenType: TokenType
+ TokenTarget: TokenTarget
+ ActorUsername: ActorUsername
+ ActorDomain: ActorDomain
+ ActorHost: ActorHost
+ SourceGeo: SourceGeo
+ IncidentKey: IncidentId
+ SourceIP: SourceIP
+ DestinationPort: DestinationPort
+ Activity: Activity
+ UserAgent: UserAgent
+ LogType: LogType
+ EventsCount: EventsCount
+entityMappings:
+ - entityType: IP
+ fieldMappings:
+ - identifier: Address
+ columnName: SourceIP
+ - entityType: IP
+ fieldMappings:
+ - identifier: Address
+ columnName: CanaryEntityIP
+ - entityType: Host
+ fieldMappings:
+ - identifier: HostName
+ columnName: CanaryEntityName
+ - entityType: Account
+ fieldMappings:
+ - identifier: Name
+ columnName: ActorUsername
+ - entityType: DNS
+ fieldMappings:
+ - identifier: DomainName
+ columnName: TokenHostname
+incidentConfiguration:
+ createIncident: true
+ groupingConfiguration:
+ enabled: false
+ reopenClosedIncident: false
+ lookbackDuration: PT5H
+ matchingMethod: AllEntities
+version: 1.0.2
+kind: NRT
diff --git a/Solutions/ThinkstCanary/Data Connectors/ThinkstCanaryLogs_ccp/ThinkstCanary_ArmTemplate.json b/Solutions/ThinkstCanary/Data Connectors/ThinkstCanaryLogs_ccp/ThinkstCanary_ArmTemplate.json
new file mode 100644
index 00000000000..86b81c54238
--- /dev/null
+++ b/Solutions/ThinkstCanary/Data Connectors/ThinkstCanaryLogs_ccp/ThinkstCanary_ArmTemplate.json
@@ -0,0 +1,946 @@
+{
+ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ "location": {
+ "type": "string",
+ "minLength": 1,
+ "defaultValue": "[resourceGroup().location]",
+ "metadata": {
+ "description": "Not used, but needed to pass arm-ttk test `Location-Should-Not-Be-Hardcoded`. We instead use the `workspace-location` which is derived from the LA workspace"
+ }
+ },
+ "workspace-location": {
+ "type": "string",
+ "defaultValue": "",
+ "metadata": {
+ "description": "[concat('Region to deploy solution resources -- separate from location selection',parameters('location'))]"
+ }
+ },
+ "subscription": {
+ "defaultValue": "[last(split(subscription().id, '/'))]",
+ "type": "string",
+ "metadata": {
+ "description": "subscription id where Microsoft Sentinel is setup"
+ }
+ },
+ "resourceGroupName": {
+ "defaultValue": "[resourceGroup().name]",
+ "type": "string",
+ "metadata": {
+ "description": "resource group name where Microsoft Sentinel is setup"
+ }
+ },
+ "workspace": {
+ "defaultValue": "",
+ "type": "string",
+ "metadata": {
+ "description": "Workspace name for Log Analytics where Microsoft Sentinel is setup"
+ }
+ },
+ "clientId": {
+ "type": "securestring",
+ "defaultValue": "-NA-"
+ },
+ "clientSecret": {
+ "type": "securestring",
+ "defaultValue": "-NA-"
+ }
+ },
+ "variables": {
+ "workspaceResourceId": "[resourceId('microsoft.OperationalInsights/Workspaces', parameters('workspace'))]",
+ "_solutionName": "Thinkst Canary",
+ "_solutionVersion": "1.0.2",
+ "_solutionAuthor": "Thinkst Engineering",
+ "_solutionId": "azuresentinel.azure-sentinel-solution-ThinkstCanaryDefinition",
+ "dataConnectorVersionConnectorDefinition": "1.0.2",
+ "dataConnectorVersionConnections": "1.0.2",
+ "_solutionTier": "Community",
+ "_dataConnectorContentIdConnections": "ThinkstCanaryDefinitionConnections",
+ "dataConnectorTemplateNameConnections": "[concat(parameters('workspace'),'-dc-',uniquestring(variables('_dataConnectorContentIdConnections')))]",
+ "_dataConnectorContentIdConnectorDefinition": "ThinkstCanaryDefinitionConnectorDefinition",
+ "dataConnectorTemplateNameConnectorDefinition": "[concat(parameters('workspace'),'-dc-',uniquestring(variables('_dataConnectorContentIdConnectorDefinition')))]",
+ "_logAnalyticsTableId1": "ThinkstCanaryIncidents_CL"
+ },
+ "resources": [
+ {
+ "type": "Microsoft.Insights/dataCollectionEndpoints",
+ "apiVersion": "2024-03-11",
+ "name": "[parameters('workspace')]",
+ "location": "[parameters('workspace-location')]",
+ "properties": {
+ "networkAcls": {
+ "publicNetworkAccess": "Enabled"
+ }
+ }
+ },
+ {
+ "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
+ "apiVersion": "2023-04-01-preview",
+ "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('dataConnectorTemplateNameConnectorDefinition'), variables('dataConnectorVersionConnectorDefinition'))]",
+ "location": "[parameters('workspace-location')]",
+ "dependsOn": [
+ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
+ ],
+ "properties": {
+ "contentId": "[variables('_dataConnectorContentIdConnectorDefinition')]",
+ "displayName": "Thinkst Canary",
+ "contentKind": "DataConnector",
+ "mainTemplate": {
+ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
+ "contentVersion": "[variables('dataConnectorVersionConnectorDefinition')]",
+ "parameters": {},
+ "variables": {},
+ "resources": [
+ {
+ "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnectorDefinition')))]",
+ "apiVersion": "2022-01-01-preview",
+ "type": "Microsoft.OperationalInsights/workspaces/providers/metadata",
+ "properties": {
+ "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectorDefinitions', variables('_dataConnectorContentIdConnectorDefinition'))]",
+ "contentId": "[variables('_dataConnectorContentIdConnectorDefinition')]",
+ "kind": "DataConnector",
+ "version": "[variables('dataConnectorVersionConnectorDefinition')]",
+ "source": {
+ "sourceId": "[variables('_solutionId')]",
+ "name": "[variables('_solutionName')]",
+ "kind": "Solution"
+ },
+ "author": {
+ "name": "[variables('_solutionAuthor')]"
+ },
+ "support": {
+ "name": "[variables('_solutionAuthor')]",
+ "tier": "[variables('_solutionTier')]"
+ },
+ "dependencies": {
+ "criteria": [
+ {
+ "version": "[variables('dataConnectorVersionConnections')]",
+ "contentId": "[variables('_dataConnectorContentIdConnections')]",
+ "kind": "ResourcesDataConnector"
+ }
+ ]
+ }
+ }
+ },
+ {
+ "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentIdConnectorDefinition'))]",
+ "apiVersion": "2022-09-01-preview",
+ "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectorDefinitions",
+ "location": "[parameters('workspace-location')]",
+ "kind": "Customizable",
+ "properties": {
+ "connectorUiConfig": {
+ "id": "ThinkstCanary",
+ "title": "Thinkst Canary",
+ "publisher": "Thinkst Engineering",
+ "descriptionMarkdown": "The Thinkst Canary connector allows you to ingest security incidents from your Thinkst Canary honeypot network into Microsoft Sentinel. Canary devices detect unauthorized access attempts including SSH logins, RDP sessions, HTTP requests, database queries, file share access, and Canarytoken triggers. This connector automatically pulls all incident data for analysis and alerting.",
+ "graphQueriesTableName": "ThinkstCanaryIncidents_CL",
+ "graphQueries": [
+ {
+ "metricName": "Total incidents received",
+ "legend": "Thinkst Canary Incidents",
+ "baseQuery": "{{graphQueriesTableName}}"
+ }
+ ],
+ "sampleQueries": [
+ {
+ "description": "All Thinkst Canary incidents in the last 24 hours",
+ "query": "ThinkstCanaryIncidents_CL\n| where TimeGenerated > ago(24h)\n| order by TimeGenerated desc"
+ },
+ {
+ "description": "Top 10 source IPs triggering incidents",
+ "query": "ThinkstCanaryIncidents_CL\n| summarize IncidentCount = count() by SourceIP\n| where isnotempty(SourceIP)\n| top 10 by IncidentCount desc"
+ },
+ {
+ "description": "Incidents by type",
+ "query": "ThinkstCanaryIncidents_CL\n| summarize Count = count() by Description\n| order by Count desc"
+ },
+ {
+ "description": "Incidents with event detail data",
+ "query": "ThinkstCanaryIncidents_CL\n| where isnotempty(RawEvent)\n| project TimeGenerated, Description, SourceIP, DestinationIP, DestinationPort, RawEvent"
+ },
+ {
+ "description": "Incidents by flock",
+ "query": "ThinkstCanaryIncidents_CL\n| summarize Count = count() by FlockId\n| order by Count desc"
+ }
+ ],
+ "dataTypes": [
+ {
+ "name": "ThinkstCanaryIncidents_CL",
+ "lastDataReceivedQuery": "ThinkstCanaryIncidents_CL\n| summarize Time = max(TimeGenerated)\n| where isnotempty(Time)"
+ }
+ ],
+ "connectivityCriteria": [
+ {
+ "type": "HasDataConnectors",
+ "value": []
+ }
+ ],
+ "availability": {
+ "status": 1,
+ "isPreview": true
+ },
+ "permissions": {
+ "resourceProvider": [
+ {
+ "provider": "Microsoft.OperationalInsights/workspaces",
+ "permissionsDisplayText": "read and write permissions are required.",
+ "providerDisplayName": "Workspace",
+ "scope": "Workspace",
+ "requiredPermissions": {
+ "write": true,
+ "read": true,
+ "delete": false
+ }
+ },
+ {
+ "provider": "Microsoft.OperationalInsights/workspaces/sharedKeys",
+ "permissionsDisplayText": "read permissions to shared keys for the workspace are required. [See the documentation to learn more about workspace keys](https://docs.microsoft.com/azure/azure-monitor/platform/agent-windows#obtain-workspace-id-and-key).",
+ "providerDisplayName": "Keys",
+ "scope": "Workspace",
+ "requiredPermissions": {
+ "action": true
+ }
+ }
+ ],
+ "customs": [
+ {
+ "name": "Thinkst Canary API Key",
+ "description": "A Thinkst Canary API authentication token is required. [See the documentation](https://docs.canary.tools/guide/user-settings.html#generating-an-api-key) to learn how to generate an API key."
+ }
+ ]
+ },
+ "instructionSteps": [
+ {
+ "title": "Connect Thinkst Canary to Microsoft Sentinel",
+ "description": "Provide your Thinkst Canary Console domain (e.g. 'yourhash' from yourhash.canary.tools) and API authentication token.",
+ "instructions": [
+ {
+ "type": "Textbox",
+ "parameters": {
+ "label": "Canary Console Domain",
+ "placeholder": "yourhash",
+ "type": "text",
+ "name": "clientId",
+ "validations": {
+ "required": true
+ }
+ }
+ },
+ {
+ "type": "Textbox",
+ "parameters": {
+ "label": "API Authentication Token",
+ "placeholder": "Enter your Canary API token",
+ "type": "password",
+ "name": "clientSecret",
+ "validations": {
+ "required": true
+ }
+ }
+ },
+ {
+ "type": "ConnectionToggleButton",
+ "parameters": {
+ "name": "toggle",
+ "connectLabel": "Connect",
+ "disconnectLabel": "Disconnect"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ },
+ {
+ "name": "[variables('_logAnalyticsTableId1')]",
+ "apiVersion": "2021-03-01-privatepreview",
+ "type": "Microsoft.OperationalInsights/workspaces/tables",
+ "location": "[parameters('workspace-location')]",
+ "kind": null,
+ "properties": {
+ "schema": {
+ "name": "[variables('_logAnalyticsTableId1')]",
+ "columns": [
+ {
+ "name": "TimeGenerated",
+ "type": "datetime",
+ "description": "Timestamp when the incident was last updated"
+ },
+ {
+ "name": "IncidentId",
+ "type": "string",
+ "description": "Unique incident key identifier"
+ },
+ {
+ "name": "Description",
+ "type": "string",
+ "description": "Incident type description (e.g. SSH Login Attempt)"
+ },
+ {
+ "name": "Acknowledged",
+ "type": "string",
+ "description": "Whether the incident has been acknowledged"
+ },
+ {
+ "name": "Created",
+ "type": "real",
+ "description": "Unix timestamp of incident creation"
+ },
+ {
+ "name": "CreatedPrintable",
+ "type": "string",
+ "description": "Human readable creation time"
+ },
+ {
+ "name": "DestinationIP",
+ "type": "string",
+ "description": "Destination IP address (Canary device)"
+ },
+ {
+ "name": "DestinationPort",
+ "type": "string",
+ "description": "Destination port targeted"
+ },
+ {
+ "name": "EventsCount",
+ "type": "string",
+ "description": "Number of events in this incident"
+ },
+ {
+ "name": "Events",
+ "type": "dynamic",
+ "description": "Array of event timestamps in milliseconds"
+ },
+ {
+ "name": "FlockId",
+ "type": "string",
+ "description": "Flock ID the incident belongs to"
+ },
+ {
+ "name": "FlockName",
+ "type": "string",
+ "description": "Flock name the incident belongs to"
+ },
+ {
+ "name": "HashId",
+ "type": "string",
+ "description": "Hash identifier for the incident"
+ },
+ {
+ "name": "Host",
+ "type": "dynamic",
+ "description": "Device details object (name, IP, version, services)"
+ },
+ {
+ "name": "IpAddress",
+ "type": "string",
+ "description": "IP address field"
+ },
+ {
+ "name": "IncidentUpdated",
+ "type": "datetime",
+ "description": "Datetime of last incident update"
+ },
+ {
+ "name": "LocalTime",
+ "type": "string",
+ "description": "Local time of the incident on the device"
+ },
+ {
+ "name": "Memo",
+ "type": "string",
+ "description": "Canarytoken reminder describing where the token was placed"
+ },
+ {
+ "name": "RawEvent",
+ "type": "dynamic",
+ "description": "Array of detailed event log objects"
+ },
+ {
+ "name": "LogType",
+ "type": "string",
+ "description": "Numeric log type identifier"
+ },
+ {
+ "name": "NodeId",
+ "type": "string",
+ "description": "Node ID of the Canary or Canarytoken"
+ },
+ {
+ "name": "Notified",
+ "type": "string",
+ "description": "Whether notification was sent"
+ },
+ {
+ "name": "PreviouslySeenCount",
+ "type": "real",
+ "description": "Number of times this source was previously seen"
+ },
+ {
+ "name": "Sensor",
+ "type": "string",
+ "description": "Sensor type (e.g. thinkstcanary)"
+ },
+ {
+ "name": "SourceIP",
+ "type": "string",
+ "description": "Source IP address of the attacker"
+ },
+ {
+ "name": "SrcHostReverse",
+ "type": "string",
+ "description": "Reverse DNS of the attacker"
+ },
+ {
+ "name": "SourcePort",
+ "type": "string",
+ "description": "Source port of the attacker"
+ },
+ {
+ "name": "UpdatedId",
+ "type": "real",
+ "description": "Incremental update ID for polling"
+ },
+ {
+ "name": "UpdatedTimePrintable",
+ "type": "string",
+ "description": "Human readable last update time"
+ }
+ ]
+ }
+ }
+ },
+ {
+ "name": "ThinkstCanaryDCR",
+ "apiVersion": "2021-09-01-preview",
+ "type": "Microsoft.Insights/dataCollectionRules",
+ "location": "[parameters('workspace-location')]",
+ "kind": "Direct",
+ "properties": {
+ "streamDeclarations": {
+ "Custom-ThinkstCanaryIncidents_CL": {
+ "columns": [
+ {
+ "name": "acknowledged",
+ "type": "string"
+ },
+ {
+ "name": "created",
+ "type": "string"
+ },
+ {
+ "name": "created_printable",
+ "type": "string"
+ },
+ {
+ "name": "description",
+ "type": "string"
+ },
+ {
+ "name": "dst_host",
+ "type": "string"
+ },
+ {
+ "name": "dst_port",
+ "type": "string"
+ },
+ {
+ "name": "events_count",
+ "type": "string"
+ },
+ {
+ "name": "events_list",
+ "type": "dynamic"
+ },
+ {
+ "name": "flock_id",
+ "type": "string"
+ },
+ {
+ "name": "flock_name",
+ "type": "string"
+ },
+ {
+ "name": "hash_id",
+ "type": "string"
+ },
+ {
+ "name": "host",
+ "type": "dynamic"
+ },
+ {
+ "name": "incident_key",
+ "type": "string"
+ },
+ {
+ "name": "ip_address",
+ "type": "string"
+ },
+ {
+ "name": "ippers",
+ "type": "string"
+ },
+ {
+ "name": "key",
+ "type": "string"
+ },
+ {
+ "name": "local_time",
+ "type": "string"
+ },
+ {
+ "name": "logdata",
+ "type": "dynamic"
+ },
+ {
+ "name": "logtype",
+ "type": "string"
+ },
+ {
+ "name": "mac_address",
+ "type": "string"
+ },
+ {
+ "name": "memo",
+ "type": "string"
+ },
+ {
+ "name": "node_id",
+ "type": "string"
+ },
+ {
+ "name": "notified",
+ "type": "string"
+ },
+ {
+ "name": "previously_seen_count",
+ "type": "real"
+ },
+ {
+ "name": "sensor",
+ "type": "string"
+ },
+ {
+ "name": "src_host",
+ "type": "string"
+ },
+ {
+ "name": "src_host_reverse",
+ "type": "string"
+ },
+ {
+ "name": "src_port",
+ "type": "string"
+ },
+ {
+ "name": "updated",
+ "type": "string"
+ },
+ {
+ "name": "updated_id",
+ "type": "real"
+ },
+ {
+ "name": "updated_time",
+ "type": "string"
+ },
+ {
+ "name": "updated_time_printable",
+ "type": "string"
+ }
+ ]
+ }
+ },
+ "destinations": {
+ "logAnalytics": [
+ {
+ "workspaceResourceId": "[variables('workspaceResourceId')]",
+ "name": "clv2ws1"
+ }
+ ]
+ },
+ "dataFlows": [
+ {
+ "streams": [
+ "Custom-ThinkstCanaryIncidents_CL"
+ ],
+ "destinations": [
+ "clv2ws1"
+ ],
+ "outputStream": "Custom-ThinkstCanaryIncidents_CL",
+ "transformKql": "source | extend TimeGenerated = datetime_add('second', tolong(updated_time), datetime(1970-01-01)) | project TimeGenerated, IncidentId = tostring(incident_key), Description = tostring(description), Acknowledged = tostring(acknowledged), Created = toreal(created), CreatedPrintable = tostring(created_printable), DestinationIP = tostring(dst_host), DestinationPort = tostring(dst_port), EventsCount = tostring(events_count), Events = todynamic(events_list), FlockId = tostring(flock_id), FlockName = tostring(flock_name), HashId = tostring(hash_id), Host = todynamic(host), IpAddress = tostring(ip_address), IncidentUpdated = TimeGenerated, LocalTime = tostring(local_time), Memo = tostring(memo), RawEvent = todynamic(logdata), LogType = tostring(logtype), NodeId = tostring(node_id), Notified = tostring(notified), PreviouslySeenCount = toreal(previously_seen_count), Sensor = tostring(sensor), SourceIP = tostring(src_host), SrcHostReverse = tostring(src_host_reverse), SourcePort = tostring(src_port), UpdatedId = toreal(updated_id), UpdatedTimePrintable = tostring(updated_time_printable)"
+ }
+ ]
+ },
+ "dependsOn": [
+ "[resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspace'), variables('_logAnalyticsTableId1'))]"
+ ]
+ }
+ ]
+ },
+ "packageKind": "Solution",
+ "packageVersion": "[variables('_solutionVersion')]",
+ "packageName": "[variables('_solutionName')]",
+ "contentProductId": "[concat(substring(variables('_solutionId'), 0, 50),'-','dc','-', uniqueString(concat(variables('_solutionId'),'-','DataConnector','-',variables('_dataConnectorContentIdConnectorDefinition'),'-', variables('dataConnectorVersionConnectorDefinition'))))]",
+ "packageId": "[variables('_solutionId')]",
+ "contentSchemaVersion": "3.0.0",
+ "version": "[variables('_solutionVersion')]"
+ }
+ },
+ {
+ "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentIdConnectorDefinition'))]",
+ "apiVersion": "2022-09-01-preview",
+ "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectorDefinitions",
+ "location": "[parameters('workspace-location')]",
+ "kind": "Customizable",
+ "properties": {
+ "connectorUiConfig": {
+ "id": "ThinkstCanary",
+ "title": "Thinkst Canary",
+ "publisher": "Thinkst Engineering",
+ "descriptionMarkdown": "The Thinkst Canary connector allows you to ingest security incidents from your Thinkst Canary honeypot network into Microsoft Sentinel. Canary devices detect unauthorized access attempts including SSH logins, RDP sessions, HTTP requests, database queries, file share access, and Canarytoken triggers. This connector automatically pulls all incident data for analysis and alerting.",
+ "graphQueriesTableName": "ThinkstCanaryIncidents_CL",
+ "graphQueries": [
+ {
+ "metricName": "Total incidents received",
+ "legend": "Thinkst Canary Incidents",
+ "baseQuery": "{{graphQueriesTableName}}"
+ }
+ ],
+ "sampleQueries": [
+ {
+ "description": "All Thinkst Canary incidents in the last 24 hours",
+ "query": "ThinkstCanaryIncidents_CL\n| where TimeGenerated > ago(24h)\n| order by TimeGenerated desc"
+ },
+ {
+ "description": "Top 10 source IPs triggering incidents",
+ "query": "ThinkstCanaryIncidents_CL\n| summarize IncidentCount = count() by SourceIP\n| where isnotempty(SourceIP)\n| top 10 by IncidentCount desc"
+ },
+ {
+ "description": "Incidents by type",
+ "query": "ThinkstCanaryIncidents_CL\n| summarize Count = count() by Description\n| order by Count desc"
+ },
+ {
+ "description": "Incidents with event detail data",
+ "query": "ThinkstCanaryIncidents_CL\n| where isnotempty(RawEvent)\n| project TimeGenerated, Description, SourceIP, DestinationIP, DestinationPort, RawEvent"
+ },
+ {
+ "description": "Incidents by flock",
+ "query": "ThinkstCanaryIncidents_CL\n| summarize Count = count() by FlockId\n| order by Count desc"
+ }
+ ],
+ "dataTypes": [
+ {
+ "name": "ThinkstCanaryIncidents_CL",
+ "lastDataReceivedQuery": "ThinkstCanaryIncidents_CL\n| summarize Time = max(TimeGenerated)\n| where isnotempty(Time)"
+ }
+ ],
+ "connectivityCriteria": [
+ {
+ "type": "HasDataConnectors",
+ "value": []
+ }
+ ],
+ "availability": {
+ "status": 1,
+ "isPreview": true
+ },
+ "permissions": {
+ "resourceProvider": [
+ {
+ "provider": "Microsoft.OperationalInsights/workspaces",
+ "permissionsDisplayText": "read and write permissions are required.",
+ "providerDisplayName": "Workspace",
+ "scope": "Workspace",
+ "requiredPermissions": {
+ "write": true,
+ "read": true,
+ "delete": false
+ }
+ },
+ {
+ "provider": "Microsoft.OperationalInsights/workspaces/sharedKeys",
+ "permissionsDisplayText": "read permissions to shared keys for the workspace are required. [See the documentation to learn more about workspace keys](https://docs.microsoft.com/azure/azure-monitor/platform/agent-windows#obtain-workspace-id-and-key).",
+ "providerDisplayName": "Keys",
+ "scope": "Workspace",
+ "requiredPermissions": {
+ "action": true
+ }
+ }
+ ],
+ "customs": [
+ {
+ "name": "Thinkst Canary API Key",
+ "description": "A Thinkst Canary API authentication token is required. [See the documentation](https://docs.canary.tools/guide/user-settings.html#generating-an-api-key) to learn how to generate an API key."
+ }
+ ]
+ },
+ "instructionSteps": [
+ {
+ "title": "Connect Thinkst Canary to Microsoft Sentinel",
+ "description": "Provide your Thinkst Canary Console domain (e.g. 'yourhash' from yourhash.canary.tools) and API authentication token.",
+ "instructions": [
+ {
+ "type": "Textbox",
+ "parameters": {
+ "label": "Canary Console Domain",
+ "placeholder": "yourhash",
+ "type": "text",
+ "name": "clientId",
+ "validations": {
+ "required": true
+ }
+ }
+ },
+ {
+ "type": "Textbox",
+ "parameters": {
+ "label": "API Authentication Token",
+ "placeholder": "Enter your Canary API token",
+ "type": "password",
+ "name": "clientSecret",
+ "validations": {
+ "required": true
+ }
+ }
+ },
+ {
+ "type": "ConnectionToggleButton",
+ "parameters": {
+ "name": "toggle",
+ "connectLabel": "Connect",
+ "disconnectLabel": "Disconnect"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ },
+ {
+ "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnectorDefinition')))]",
+ "apiVersion": "2022-01-01-preview",
+ "type": "Microsoft.OperationalInsights/workspaces/providers/metadata",
+ "properties": {
+ "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectorDefinitions', variables('_dataConnectorContentIdConnectorDefinition'))]",
+ "contentId": "[variables('_dataConnectorContentIdConnectorDefinition')]",
+ "kind": "DataConnector",
+ "version": "[variables('dataConnectorVersionConnectorDefinition')]",
+ "source": {
+ "sourceId": "[variables('_solutionId')]",
+ "name": "[variables('_solutionName')]",
+ "kind": "Solution"
+ },
+ "author": {
+ "name": "[variables('_solutionAuthor')]"
+ },
+ "support": {
+ "name": "[variables('_solutionAuthor')]",
+ "tier": "[variables('_solutionTier')]"
+ },
+ "dependencies": {
+ "criteria": [
+ {
+ "version": "[variables('dataConnectorVersionConnections')]",
+ "contentId": "[variables('_dataConnectorContentIdConnections')]",
+ "kind": "ResourcesDataConnector"
+ }
+ ]
+ }
+ }
+ },
+ {
+ "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
+ "apiVersion": "2023-04-01-preview",
+ "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('dataConnectorTemplateNameConnections'), variables('dataConnectorVersionConnections'))]",
+ "location": "[parameters('workspace-location')]",
+ "dependsOn": [
+ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
+ ],
+ "properties": {
+ "contentId": "[variables('_dataConnectorContentIdConnections')]",
+ "displayName": "Thinkst Canary",
+ "contentKind": "ResourcesDataConnector",
+ "mainTemplate": {
+ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
+ "contentVersion": "[variables('dataConnectorVersionConnections')]",
+ "parameters": {
+ "connectorDefinitionName": {
+ "defaultValue": "connectorDefinitionName",
+ "type": "string",
+ "minLength": 1
+ },
+ "workspace": {
+ "defaultValue": "[parameters('workspace')]",
+ "type": "string"
+ },
+ "dcrConfig": {
+ "defaultValue": {
+ "dataCollectionEndpoint": "data collection Endpoint",
+ "dataCollectionRuleImmutableId": "data collection rule immutableId"
+ },
+ "type": "object"
+ },
+ "clientId": {
+ "defaultValue": "-NA-",
+ "type": "securestring",
+ "minLength": 1
+ },
+ "clientSecret": {
+ "defaultValue": "-NA-",
+ "type": "securestring",
+ "minLength": 1
+ },
+ "authorizationCode": {
+ "defaultValue": "-NA-",
+ "type": "securestring",
+ "minLength": 1
+ }
+ },
+ "variables": {
+ "_dataConnectorContentIdConnections": "[variables('_dataConnectorContentIdConnections')]"
+ },
+ "resources": [
+ {
+ "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnections')))]",
+ "apiVersion": "2022-01-01-preview",
+ "type": "Microsoft.OperationalInsights/workspaces/providers/metadata",
+ "properties": {
+ "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectors', variables('_dataConnectorContentIdConnections'))]",
+ "contentId": "[variables('_dataConnectorContentIdConnections')]",
+ "kind": "ResourcesDataConnector",
+ "version": "[variables('dataConnectorVersionConnections')]",
+ "source": {
+ "sourceId": "[variables('_solutionId')]",
+ "name": "[variables('_solutionName')]",
+ "kind": "Solution"
+ },
+ "author": {
+ "name": "[variables('_solutionAuthor')]"
+ },
+ "support": {
+ "name": "[variables('_solutionAuthor')]",
+ "tier": "[variables('_solutionTier')]"
+ }
+ }
+ },
+ {
+ "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', 'ThinkstCanaryIncidentsConnector')]",
+ "apiVersion": "2022-12-01-preview",
+ "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors",
+ "location": "[parameters('workspace-location')]",
+ "kind": "RestApiPoller",
+ "properties": {
+ "connectorDefinitionName": "[parameters('connectorDefinitionName')]",
+ "dataType": "ThinkstCanaryIncidents_CL",
+ "dcrConfig": {
+ "streamName": "Custom-ThinkstCanaryIncidents_CL",
+ "dataCollectionEndpoint": "[parameters('dcrConfig').dataCollectionEndpoint]",
+ "dataCollectionRuleImmutableId": "[parameters('dcrConfig').dataCollectionRuleImmutableId]"
+ },
+ "auth": {
+ "type": "APIKey",
+ "apiKey": "not-used-by-canary",
+ "apiKeyIdentifier": "QueryParameter",
+ "apiKeyName": "not_used_by_canary"
+ },
+ "request": {
+ "apiEndpoint": "[concat('https://',parameters('clientId'),'.canary.tools/api/v1/incidents/search')]",
+ "httpMethod": "GET",
+ "headers": {
+ "X-Canary-Auth-Token": "[parameters('clientSecret')]",
+ "User-Agent": "Microsoft Sentinel Thinkst Canary Connector - Version 1.0",
+ "Accept": "application/json"
+ },
+ "rateLimitQPS": 10,
+ "StartTimeAttributeName": "newer_than",
+ "queryTimeFormat": "yyyy-MM-dd-HH:mm:ss",
+ "queryWindowInMin": 5,
+ "retryCount": 3,
+ "timeoutInSeconds": 60,
+ "queryParameters": {
+ "filter_incident_state": "all",
+ "limit": "100"
+ }
+ },
+ "response": {
+ "eventsJsonPaths": [
+ "$.incidents"
+ ],
+ "format": "json",
+ "successStatusJsonPath": "$.result",
+ "successStatusValue": "success"
+ },
+ "paging": {
+ "pagingType": "NextPageToken",
+ "nextPageTokenJsonPath": "$.cursor.next",
+ "NextPageParaName": "cursor",
+ "pageSize": 100
+ }
+ }
+ }
+ ]
+ },
+ "packageKind": "Solution",
+ "packageVersion": "[variables('_solutionVersion')]",
+ "packageName": "[variables('_solutionName')]",
+ "contentProductId": "[concat(substring(variables('_solutionId'), 0, 50),'-','rdc','-', uniqueString(concat(variables('_solutionId'),'-','ResourcesDataConnector','-',variables('_dataConnectorContentIdConnections'),'-', variables('dataConnectorVersionConnections'))))]",
+ "packageId": "[variables('_solutionId')]",
+ "contentSchemaVersion": "3.0.0",
+ "version": "[variables('_solutionVersion')]"
+ }
+ },
+ {
+ "type": "Microsoft.OperationalInsights/workspaces/providers/contentPackages",
+ "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('_solutionId'))]",
+ "apiVersion": "2023-04-01-preview",
+ "location": "[parameters('workspace-location')]",
+ "properties": {
+ "version": "[variables('_solutionVersion')]",
+ "kind": "Solution",
+ "contentSchemaVersion": "3.0.0",
+ "contentId": "[variables('_solutionId')]",
+ "source": {
+ "kind": "Solution",
+ "name": "[variables('_solutionName')]",
+ "sourceId": "[variables('_solutionId')]"
+ },
+ "author": {
+ "name": "[variables('_solutionAuthor')]"
+ },
+ "support": {
+ "name": "[variables('_solutionAuthor')]",
+ "tier": "[variables('_solutionTier')]"
+ },
+ "dependencies": {
+ "operator": "AND",
+ "criteria": [
+ {
+ "kind": "DataConnector",
+ "contentId": "[variables('_dataConnectorContentIdConnectorDefinition')]",
+ "version": "[variables('dataConnectorVersionConnectorDefinition')]"
+ }
+ ]
+ },
+ "firstPublishDate": "2022-06-24",
+ "providers": [
+ "[variables('_solutionAuthor')]"
+ ],
+ "contentKind": "Solution",
+ "packageId": "[variables('_solutionId')]",
+ "contentProductId": "[concat(substring(variables('_solutionId'), 0, 50),'-','sl','-', uniqueString(concat(variables('_solutionId'),'-','Solution','-',variables('_solutionId'),'-', variables('_solutionVersion'))))]",
+ "displayName": "Thinkst Canary",
+ "publisherDisplayName": "Thinkst Engineering",
+ "description": "The Thinkst Canary connector allows you to ingest security incidents from your Thinkst Canary honeypot network into Microsoft Sentinel. Canary devices detect unauthorized access attempts including SSH logins, RDP sessions, HTTP requests, database queries, file share access, and Canarytoken triggers. This connector automatically pulls all incident data for analysis and alerting.",
+ "descriptionHtml": "The Thinkst Canary connector allows you to ingest security incidents from your Thinkst Canary honeypot network into Microsoft Sentinel. Canary devices detect unauthorized access attempts including SSH logins, RDP sessions, HTTP requests, database queries, file share access, and Canarytoken triggers. This connector automatically pulls all incident data for analysis and alerting.",
+ "icon": "data:image/png;base64,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",
+ "parentId": "[variables('_solutionId')]"
+ }
+ }
+ ]
+}
diff --git a/Solutions/ThinkstCanary/Data Connectors/ThinkstCanaryLogs_ccp/ThinkstCanary_ConnectorDefinition.json b/Solutions/ThinkstCanary/Data Connectors/ThinkstCanaryLogs_ccp/ThinkstCanary_ConnectorDefinition.json
new file mode 100644
index 00000000000..5cbc614c76d
--- /dev/null
+++ b/Solutions/ThinkstCanary/Data Connectors/ThinkstCanaryLogs_ccp/ThinkstCanary_ConnectorDefinition.json
@@ -0,0 +1,134 @@
+{
+ "name": "ThinkstCanary",
+ "apiVersion": "2022-09-01-preview",
+ "type": "Microsoft.SecurityInsights/dataConnectorDefinitions",
+ "location": "{{location}}",
+ "kind": "Customizable",
+ "availability": {
+ "isPreview": true,
+ "status": 1
+ },
+ "properties": {
+ "connectorUiConfig": {
+ "id": "ThinkstCanary",
+ "title": "Thinkst Canary",
+ "publisher": "Thinkst Engineering",
+ "descriptionMarkdown": "The Thinkst Canary connector allows you to ingest security incidents from your Thinkst Canary honeypot network into Microsoft Sentinel. Canary devices detect unauthorized access attempts including SSH logins, RDP sessions, HTTP requests, database queries, file share access, and Canarytoken triggers. This connector automatically pulls all incident data for analysis and alerting.",
+ "graphQueriesTableName": "ThinkstCanaryIncidents_CL",
+ "graphQueries": [
+ {
+ "metricName": "Total incidents received",
+ "legend": "Thinkst Canary Incidents",
+ "baseQuery": "{{graphQueriesTableName}}"
+ }
+ ],
+ "sampleQueries": [
+ {
+ "description": "All Thinkst Canary incidents in the last 24 hours",
+ "query": "ThinkstCanaryIncidents_CL\n| where TimeGenerated > ago(24h)\n| order by TimeGenerated desc"
+ },
+ {
+ "description": "Top 10 source IPs triggering incidents",
+ "query": "ThinkstCanaryIncidents_CL\n| summarize IncidentCount = count() by SourceIP\n| where isnotempty(SourceIP)\n| top 10 by IncidentCount desc"
+ },
+ {
+ "description": "Incidents by type",
+ "query": "ThinkstCanaryIncidents_CL\n| summarize Count = count() by Description\n| order by Count desc"
+ },
+ {
+ "description": "Incidents with event detail data",
+ "query": "ThinkstCanaryIncidents_CL\n| where isnotempty(RawEvent)\n| project TimeGenerated, Description, SourceIP, DestinationIP, DestinationPort, RawEvent"
+ },
+ {
+ "description": "Incidents by flock",
+ "query": "ThinkstCanaryIncidents_CL\n| summarize Count = count() by FlockId\n| order by Count desc"
+ }
+ ],
+ "dataTypes": [
+ {
+ "name": "ThinkstCanaryIncidents_CL",
+ "lastDataReceivedQuery": "ThinkstCanaryIncidents_CL\n| summarize Time = max(TimeGenerated)\n| where isnotempty(Time)"
+ }
+ ],
+ "connectivityCriteria": [
+ {
+ "type": "HasDataConnectors"
+ }
+ ],
+ "availability": {
+ "status": 1,
+ "isPreview": true
+ },
+ "permissions": {
+ "resourceProvider": [
+ {
+ "provider": "Microsoft.OperationalInsights/workspaces",
+ "permissionsDisplayText": "read and write permissions are required.",
+ "providerDisplayName": "Workspace",
+ "scope": "Workspace",
+ "requiredPermissions": {
+ "write": true,
+ "read": true,
+ "delete": false
+ }
+ },
+ {
+ "provider": "Microsoft.OperationalInsights/workspaces/sharedKeys",
+ "permissionsDisplayText": "read permissions to shared keys for the workspace are required. [See the documentation to learn more about workspace keys](https://docs.microsoft.com/azure/azure-monitor/platform/agent-windows#obtain-workspace-id-and-key).",
+ "providerDisplayName": "Keys",
+ "scope": "Workspace",
+ "requiredPermissions": {
+ "action": true
+ }
+ }
+ ],
+ "customs": [
+ {
+ "name": "Thinkst Canary API Key",
+ "description": "A Thinkst Canary API authentication token is required. [See the documentation](https://docs.canary.tools/guide/user-settings.html#generating-an-api-key) to learn how to generate an API key."
+ }
+ ]
+ },
+ "instructionSteps": [
+ {
+ "title": "Connect Thinkst Canary to Microsoft Sentinel",
+ "description": "Provide your Thinkst Canary Console domain (e.g. 'yourhash' from yourhash.canary.tools) and API authentication token.",
+ "instructions": [
+ {
+ "type": "Textbox",
+ "parameters": {
+ "label": "Canary Console Domain",
+ "placeholder": "yourhash",
+ "type": "text",
+ "name": "clientId",
+ "validations": {
+ "required": true
+ }
+ }
+ },
+ {
+ "type": "Textbox",
+ "parameters": {
+ "label": "API Authentication Token",
+ "placeholder": "Enter your Canary API token",
+ "type": "password",
+ "name": "clientSecret",
+ "validations": {
+ "required": true
+ }
+ }
+ },
+ {
+ "type": "ConnectionToggleButton",
+ "parameters": {
+ "name": "toggle",
+ "connectLabel": "Connect",
+ "disconnectLabel": "Disconnect"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+}
diff --git a/Solutions/ThinkstCanary/Data Connectors/ThinkstCanaryLogs_ccp/ThinkstCanary_DCR.json b/Solutions/ThinkstCanary/Data Connectors/ThinkstCanaryLogs_ccp/ThinkstCanary_DCR.json
new file mode 100644
index 00000000000..9ce9da5bb4b
--- /dev/null
+++ b/Solutions/ThinkstCanary/Data Connectors/ThinkstCanaryLogs_ccp/ThinkstCanary_DCR.json
@@ -0,0 +1,166 @@
+{
+ "name": "ThinkstCanaryDCR",
+ "apiVersion": "2024-03-11",
+ "type": "Microsoft.Insights/dataCollectionRules",
+ "kind": "Direct",
+ "location": "{{location}}",
+ "tags": {
+ "createdBy": "SentinelCodelessConnector"
+ },
+ "properties": {
+ "streamDeclarations": {
+ "Custom-ThinkstCanaryIncidents_CL": {
+ "columns": [
+ {
+ "name": "acknowledged",
+ "type": "string"
+ },
+ {
+ "name": "created",
+ "type": "string"
+ },
+ {
+ "name": "created_printable",
+ "type": "string"
+ },
+ {
+ "name": "description",
+ "type": "string"
+ },
+ {
+ "name": "dst_host",
+ "type": "string"
+ },
+ {
+ "name": "dst_port",
+ "type": "string"
+ },
+ {
+ "name": "events_count",
+ "type": "string"
+ },
+ {
+ "name": "events_list",
+ "type": "dynamic"
+ },
+ {
+ "name": "flock_id",
+ "type": "string"
+ },
+ {
+ "name": "flock_name",
+ "type": "string"
+ },
+ {
+ "name": "hash_id",
+ "type": "string"
+ },
+ {
+ "name": "host",
+ "type": "dynamic"
+ },
+ {
+ "name": "incident_key",
+ "type": "string"
+ },
+ {
+ "name": "ip_address",
+ "type": "string"
+ },
+ {
+ "name": "ippers",
+ "type": "string"
+ },
+ {
+ "name": "key",
+ "type": "string"
+ },
+ {
+ "name": "local_time",
+ "type": "string"
+ },
+ {
+ "name": "logdata",
+ "type": "dynamic"
+ },
+ {
+ "name": "logtype",
+ "type": "string"
+ },
+ {
+ "name": "mac_address",
+ "type": "string"
+ },
+ {
+ "name": "memo",
+ "type": "string"
+ },
+ {
+ "name": "node_id",
+ "type": "string"
+ },
+ {
+ "name": "notified",
+ "type": "string"
+ },
+ {
+ "name": "previously_seen_count",
+ "type": "real"
+ },
+ {
+ "name": "sensor",
+ "type": "string"
+ },
+ {
+ "name": "src_host",
+ "type": "string"
+ },
+ {
+ "name": "src_host_reverse",
+ "type": "string"
+ },
+ {
+ "name": "src_port",
+ "type": "string"
+ },
+ {
+ "name": "updated",
+ "type": "string"
+ },
+ {
+ "name": "updated_id",
+ "type": "real"
+ },
+ {
+ "name": "updated_time",
+ "type": "string"
+ },
+ {
+ "name": "updated_time_printable",
+ "type": "string"
+ }
+ ]
+ }
+ },
+ "destinations": {
+ "logAnalytics": [
+ {
+ "workspaceResourceId": "{{workspaceResourceId}}",
+ "name": "clv2ws1"
+ }
+ ]
+ },
+ "dataFlows": [
+ {
+ "streams": [
+ "Custom-ThinkstCanaryIncidents_CL"
+ ],
+ "destinations": [
+ "clv2ws1"
+ ],
+ "outputStream": "Custom-ThinkstCanaryIncidents_CL",
+ "transformKql": "source | extend TimeGenerated = datetime_add('second', tolong(updated_time), datetime(1970-01-01)) | project TimeGenerated, IncidentId = tostring(incident_key), Description = tostring(description), Acknowledged = tostring(acknowledged), Created = toreal(created), CreatedPrintable = tostring(created_printable), DestinationIP = tostring(dst_host), DestinationPort = tostring(dst_port), EventsCount = tostring(events_count), Events = todynamic(events_list), FlockId = tostring(flock_id), FlockName = tostring(flock_name), HashId = tostring(hash_id), Host = todynamic(host), IpAddress = tostring(ip_address), IncidentUpdated = TimeGenerated, LocalTime = tostring(local_time), Memo = tostring(memo), RawEvent = todynamic(logdata), LogType = tostring(logtype), NodeId = tostring(node_id), Notified = tostring(notified), PreviouslySeenCount = toreal(previously_seen_count), Sensor = tostring(sensor), SourceIP = tostring(src_host), SrcHostReverse = tostring(src_host_reverse), SourcePort = tostring(src_port), UpdatedId = toreal(updated_id), UpdatedTimePrintable = tostring(updated_time_printable)"
+ }
+ ]
+ }
+}
diff --git a/Solutions/ThinkstCanary/Data Connectors/ThinkstCanaryLogs_ccp/ThinkstCanary_PollingConfig.json b/Solutions/ThinkstCanary/Data Connectors/ThinkstCanaryLogs_ccp/ThinkstCanary_PollingConfig.json
new file mode 100644
index 00000000000..f2f89478ed7
--- /dev/null
+++ b/Solutions/ThinkstCanary/Data Connectors/ThinkstCanaryLogs_ccp/ThinkstCanary_PollingConfig.json
@@ -0,0 +1,53 @@
+{
+ "type": "Microsoft.SecurityInsights/dataConnectors",
+ "apiVersion": "2023-02-01-preview",
+ "name": "ThinkstCanaryIncidentsConnector",
+ "location": "{{location}}",
+ "kind": "RestApiPoller",
+ "properties": {
+ "connectorDefinitionName": "ThinkstCanary",
+ "dataType": "ThinkstCanaryIncidents_CL",
+ "dcrConfig": {
+ "streamName": "Custom-ThinkstCanaryIncidents_CL",
+ "dataCollectionEndpoint": "{{dataCollectionEndpoint}}",
+ "dataCollectionRuleImmutableId": "{{dataCollectionRuleImmutableId}}"
+ },
+ "auth": {
+ "type": "APIKey",
+ "apiKey": "not-used-by-canary",
+ "apiKeyIdentifier": "QueryParameter",
+ "apiKeyName": "not_used_by_canary"
+ },
+ "request": {
+ "apiEndpoint": "https://{{clientId}}.canary.tools/api/v1/incidents/search",
+ "httpMethod": "GET",
+ "headers": {
+ "X-Canary-Auth-Token": "{{clientSecret}}",
+ "User-Agent": "Microsoft Sentinel Thinkst Canary Connector - Version 1.0",
+ "Accept": "application/json"
+ },
+ "rateLimitQPS": 10,
+ "StartTimeAttributeName": "newer_than",
+ "queryTimeFormat": "yyyy-MM-dd-HH:mm:ss",
+ "queryWindowInMin": 5,
+ "retryCount": 3,
+ "timeoutInSeconds": 60,
+ "queryParameters": {
+ "filter_incident_state": "all",
+ "limit": "100"
+ }
+ },
+ "response": {
+ "eventsJsonPaths": ["$.incidents"],
+ "format": "json",
+ "successStatusJsonPath": "$.result",
+ "successStatusValue": "success"
+ },
+ "paging": {
+ "pagingType": "NextPageToken",
+ "nextPageTokenJsonPath": "$.cursor.next",
+ "NextPageParaName": "cursor",
+ "pageSize": 100
+ }
+ }
+}
diff --git a/Solutions/ThinkstCanary/Data Connectors/ThinkstCanaryLogs_ccp/ThinkstCanary_Table.json b/Solutions/ThinkstCanary/Data Connectors/ThinkstCanaryLogs_ccp/ThinkstCanary_Table.json
new file mode 100644
index 00000000000..51514a498e3
--- /dev/null
+++ b/Solutions/ThinkstCanary/Data Connectors/ThinkstCanaryLogs_ccp/ThinkstCanary_Table.json
@@ -0,0 +1,44 @@
+[
+ {
+ "name": "ThinkstCanaryIncidents_CL",
+ "type": "Microsoft.OperationalInsights/workspaces/tables",
+ "apiVersion": "2025-02-01",
+ "location": "{{location}}",
+ "properties": {
+ "schema": {
+ "name": "ThinkstCanaryIncidents_CL",
+ "columns": [
+ { "name": "TimeGenerated", "type": "datetime", "description": "Timestamp when the incident was last updated" },
+ { "name": "IncidentId", "type": "string", "description": "Unique incident key identifier" },
+ { "name": "Description", "type": "string", "description": "Incident type description (e.g. SSH Login Attempt)" },
+ { "name": "Acknowledged", "type": "string", "description": "Whether the incident has been acknowledged" },
+ { "name": "Created", "type": "real", "description": "Unix timestamp of incident creation" },
+ { "name": "CreatedPrintable", "type": "string", "description": "Human readable creation time" },
+ { "name": "DestinationIP", "type": "string", "description": "Destination IP address (Canary device)" },
+ { "name": "DestinationPort", "type": "string", "description": "Destination port targeted" },
+ { "name": "EventsCount", "type": "string", "description": "Number of events in this incident" },
+ { "name": "Events", "type": "dynamic", "description": "Array of event timestamps in milliseconds" },
+ { "name": "FlockId", "type": "string", "description": "Flock ID the incident belongs to" },
+ { "name": "FlockName", "type": "string", "description": "Flock name the incident belongs to" },
+ { "name": "HashId", "type": "string", "description": "Hash identifier for the incident" },
+ { "name": "Host", "type": "dynamic", "description": "Device details object (name, IP, version, services)" },
+ { "name": "IpAddress", "type": "string", "description": "IP address field" },
+ { "name": "IncidentUpdated", "type": "datetime", "description": "Datetime of last incident update" },
+ { "name": "LocalTime", "type": "string", "description": "Local time of the incident on the device" },
+ { "name": "Memo", "type": "string", "description": "Canarytoken reminder describing where the token was placed" },
+ { "name": "RawEvent", "type": "dynamic", "description": "Array of detailed event log objects" },
+ { "name": "LogType", "type": "string", "description": "Numeric log type identifier" },
+ { "name": "NodeId", "type": "string", "description": "Node ID of the Canary or Canarytoken" },
+ { "name": "Notified", "type": "string", "description": "Whether notification was sent" },
+ { "name": "PreviouslySeenCount", "type": "real", "description": "Number of times this source was previously seen" },
+ { "name": "Sensor", "type": "string", "description": "Sensor type (e.g. thinkstcanary)" },
+ { "name": "SourceIP", "type": "string", "description": "Source IP address of the attacker" },
+ { "name": "SrcHostReverse", "type": "string", "description": "Reverse DNS of the attacker" },
+ { "name": "SourcePort", "type": "string", "description": "Source port of the attacker" },
+ { "name": "UpdatedId", "type": "real", "description": "Incremental update ID for polling" },
+ { "name": "UpdatedTimePrintable", "type": "string", "description": "Human readable last update time" }
+ ]
+ }
+ }
+ }
+]
diff --git a/Solutions/ThinkstCanary/Data/Solution_ThinkstCanary.json b/Solutions/ThinkstCanary/Data/Solution_ThinkstCanary.json
new file mode 100644
index 00000000000..b53dd32e140
--- /dev/null
+++ b/Solutions/ThinkstCanary/Data/Solution_ThinkstCanary.json
@@ -0,0 +1,16 @@
+{
+ "Name": "ThinkstCanary",
+ "Author": "Thinkst Applied Research - support@canary.tools",
+ "Logo": "",
+ "Description": "The Thinkst Canary solution for Microsoft Sentinel ingests Canary and Canarytoken incidents through the Codeless Connector Framework and provides normalized parsers, detections and response automation.",
+ "BasePath": "Solutions/ThinkstCanary",
+ "Version": "1.0.0",
+ "TemplateSpec": true,
+ "Data Connectors": [
+ "Data Connectors/ThinkstCanaryLogs_ccp/ThinkstCanary_ConnectorDefinition.json"
+ ],
+ "Analytic Rules": [
+ "Analytic Rules/SentinelIncidentsFromThinkstCanaryAlerts.yaml"
+ ],
+ "Metadata": "SolutionMetadata.json"
+}
diff --git a/Solutions/ThinkstCanary/Package/3.0.0.zip b/Solutions/ThinkstCanary/Package/3.0.0.zip
new file mode 100644
index 00000000000..d113b729c7f
Binary files /dev/null and b/Solutions/ThinkstCanary/Package/3.0.0.zip differ
diff --git a/Solutions/ThinkstCanary/Package/createUiDefinition.json b/Solutions/ThinkstCanary/Package/createUiDefinition.json
new file mode 100644
index 00000000000..7113dc90122
--- /dev/null
+++ b/Solutions/ThinkstCanary/Package/createUiDefinition.json
@@ -0,0 +1,127 @@
+{
+ "$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": "
\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/ThinkstCanary/ReleaseNotes.md)\n\n • There may be [known issues](https://aka.ms/sentinelsolutionsknownissues) pertaining to this Solution, please refer to them before installing.\n\nThe Thinkst Canary solution for Microsoft Sentinel ingests Canary and Canarytoken incidents through the Codeless Connector Framework and provides normalized parsers, detections and response automation.\n\n**Data Connectors:** 1, **Analytic Rules:** 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 Thinkst Canary. You can get Thinkst Canary 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"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "name": "analytics",
+ "label": "Analytics",
+ "subLabel": {
+ "preValidation": "Configure the analytics",
+ "postValidation": "Done"
+ },
+ "bladeTitle": "Analytics",
+ "elements": [
+ {
+ "name": "analytics-text",
+ "type": "Microsoft.Common.TextBlock",
+ "options": {
+ "text": "This solution installs the following analytic rule templates. After installing the solution, create and enable analytic rules in Manage solution view."
+ }
+ },
+ {
+ "name": "analytics-link",
+ "type": "Microsoft.Common.TextBlock",
+ "options": {
+ "link": {
+ "label": "Learn more",
+ "uri": "https://docs.microsoft.com/azure/sentinel/tutorial-detect-threats-custom?WT.mc_id=Portal-Microsoft_Azure_CreateUIDef"
+ }
+ }
+ },
+ {
+ "name": "analytic1",
+ "type": "Microsoft.Common.Section",
+ "label": "Canary alerts to incidents",
+ "elements": [
+ {
+ "name": "analytic1-text",
+ "type": "Microsoft.Common.TextBlock",
+ "options": {
+ "text": "Creates Microsoft Sentinel incidents from Thinkst Canary alerts."
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "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')]"
+ }
+ }
+}
diff --git a/Solutions/ThinkstCanary/Package/mainTemplate.json b/Solutions/ThinkstCanary/Package/mainTemplate.json
new file mode 100644
index 00000000000..b6c87466cd5
--- /dev/null
+++ b/Solutions/ThinkstCanary/Package/mainTemplate.json
@@ -0,0 +1,1133 @@
+{
+ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
+ "contentVersion": "1.0.0.0",
+ "metadata": {
+ "author": "Thinkst Applied Research - support@canary.tools",
+ "comments": "Solution template for ThinkstCanary"
+ },
+ "parameters": {
+ "location": {
+ "type": "string",
+ "minLength": 1,
+ "defaultValue": "[resourceGroup().location]",
+ "metadata": {
+ "description": "Not used, but needed to pass arm-ttk test `Location-Should-Not-Be-Hardcoded`. We instead use the `workspace-location` which is derived from the LA workspace"
+ }
+ },
+ "workspace-location": {
+ "type": "string",
+ "defaultValue": "",
+ "metadata": {
+ "description": "[concat('Region to deploy solution resources -- separate from location selection',parameters('location'))]"
+ }
+ },
+ "workspace": {
+ "defaultValue": "",
+ "type": "string",
+ "metadata": {
+ "description": "Workspace name for Log Analytics where Microsoft Sentinel is setup"
+ }
+ }
+ },
+ "variables": {
+ "email": "support@canary.tools",
+ "_email": "[variables('email')]",
+ "_solutionName": "ThinkstCanary",
+ "_solutionVersion": "1.0.0",
+ "solutionId": "87073660.azure-sentinel-solution-thinkst-canary",
+ "_solutionId": "[variables('solutionId')]",
+ "workspaceResourceId": "[resourceId('microsoft.OperationalInsights/Workspaces', parameters('workspace'))]",
+ "dataConnectorCCPVersion": "3.0.0",
+ "_dataConnectorContentIdConnectorDefinition1": "ThinkstCanary",
+ "dataConnectorTemplateNameConnectorDefinition1": "[concat(parameters('workspace'),'-dc-',uniquestring(variables('_dataConnectorContentIdConnectorDefinition1')))]",
+ "_dataConnectorContentIdConnections1": "ThinkstCanaryConnections",
+ "dataConnectorTemplateNameConnections1": "[concat(parameters('workspace'),'-dc-',uniquestring(variables('_dataConnectorContentIdConnections1')))]",
+ "dataCollectionEndpointId": "[resourceId('Microsoft.Insights/dataCollectionEndpoints', parameters('workspace'))]",
+ "analyticRuleObject1": {
+ "analyticRuleVersion1": "1.0.2",
+ "_analyticRulecontentId1": "06360572-94a7-42a4-add7-58fb933b2353",
+ "analyticRuleId1": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', '06360572-94a7-42a4-add7-58fb933b2353')]",
+ "analyticRuleTemplateSpecName1": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('06360572-94a7-42a4-add7-58fb933b2353')))]",
+ "_analyticRulecontentProductId1": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','06360572-94a7-42a4-add7-58fb933b2353','-', '1.0.2')))]"
+ },
+ "_solutioncontentProductId": "[concat(take(variables('_solutionId'),50),'-','sl','-', uniqueString(concat(variables('_solutionId'),'-','Solution','-',variables('_solutionId'),'-', variables('_solutionVersion'))))]"
+ },
+ "resources": [
+ {
+ "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
+ "apiVersion": "2023-04-01-preview",
+ "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('dataConnectorTemplateNameConnectorDefinition1'), variables('dataConnectorCCPVersion'))]",
+ "location": "[parameters('workspace-location')]",
+ "dependsOn": [
+ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
+ ],
+ "properties": {
+ "contentId": "[variables('_dataConnectorContentIdConnectorDefinition1')]",
+ "displayName": "Thinkst Canary",
+ "contentKind": "DataConnector",
+ "mainTemplate": {
+ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
+ "contentVersion": "[variables('dataConnectorCCPVersion')]",
+ "parameters": {},
+ "variables": {},
+ "resources": [
+ {
+ "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentIdConnectorDefinition1'))]",
+ "apiVersion": "2022-09-01-preview",
+ "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectorDefinitions",
+ "location": "[parameters('workspace-location')]",
+ "kind": "Customizable",
+ "properties": {
+ "connectorUiConfig": {
+ "id": "ThinkstCanary",
+ "title": "Thinkst Canary",
+ "publisher": "Thinkst Engineering",
+ "descriptionMarkdown": "The Thinkst Canary connector allows you to ingest security incidents from your Thinkst Canary honeypot network into Microsoft Sentinel. Canary devices detect unauthorized access attempts including SSH logins, RDP sessions, HTTP requests, database queries, file share access, and Canarytoken triggers. This connector automatically pulls all incident data for analysis and alerting.",
+ "graphQueriesTableName": "ThinkstCanaryIncidents_CL",
+ "graphQueries": [
+ {
+ "metricName": "Total incidents received",
+ "legend": "Thinkst Canary Incidents",
+ "baseQuery": "{{graphQueriesTableName}}"
+ }
+ ],
+ "sampleQueries": [
+ {
+ "description": "All Thinkst Canary incidents in the last 24 hours",
+ "query": "ThinkstCanaryIncidents_CL\n| where TimeGenerated > ago(24h)\n| order by TimeGenerated desc"
+ },
+ {
+ "description": "Top 10 source IPs triggering incidents",
+ "query": "ThinkstCanaryIncidents_CL\n| summarize IncidentCount = count() by SourceIP\n| where isnotempty(SourceIP)\n| top 10 by IncidentCount desc"
+ },
+ {
+ "description": "Incidents by type",
+ "query": "ThinkstCanaryIncidents_CL\n| summarize Count = count() by Description\n| order by Count desc"
+ },
+ {
+ "description": "Incidents with event detail data",
+ "query": "ThinkstCanaryIncidents_CL\n| where isnotempty(RawEvent)\n| project TimeGenerated, Description, SourceIP, DestinationIP, DestinationPort, RawEvent"
+ },
+ {
+ "description": "Incidents by flock",
+ "query": "ThinkstCanaryIncidents_CL\n| summarize Count = count() by FlockId\n| order by Count desc"
+ }
+ ],
+ "dataTypes": [
+ {
+ "name": "ThinkstCanaryIncidents_CL",
+ "lastDataReceivedQuery": "ThinkstCanaryIncidents_CL\n| summarize Time = max(TimeGenerated)\n| where isnotempty(Time)"
+ }
+ ],
+ "connectivityCriteria": [
+ {
+ "type": "HasDataConnectors"
+ }
+ ],
+ "availability": {
+ "status": 1,
+ "isPreview": true
+ },
+ "permissions": {
+ "resourceProvider": [
+ {
+ "provider": "Microsoft.OperationalInsights/workspaces",
+ "permissionsDisplayText": "read and write permissions are required.",
+ "providerDisplayName": "Workspace",
+ "scope": "Workspace",
+ "requiredPermissions": {
+ "write": true,
+ "read": true,
+ "delete": false
+ }
+ },
+ {
+ "provider": "Microsoft.OperationalInsights/workspaces/sharedKeys",
+ "permissionsDisplayText": "read permissions to shared keys for the workspace are required. [See the documentation to learn more about workspace keys](https://docs.microsoft.com/azure/azure-monitor/platform/agent-windows#obtain-workspace-id-and-key).",
+ "providerDisplayName": "Keys",
+ "scope": "Workspace",
+ "requiredPermissions": {
+ "action": true
+ }
+ }
+ ],
+ "customs": [
+ {
+ "name": "Thinkst Canary API Key",
+ "description": "A Thinkst Canary API authentication token is required. [See the documentation](https://docs.canary.tools/guide/user-settings.html#generating-an-api-key) to learn how to generate an API key."
+ }
+ ]
+ },
+ "instructionSteps": [
+ {
+ "title": "Connect Thinkst Canary to Microsoft Sentinel",
+ "description": "Provide your Thinkst Canary Console domain (e.g. 'yourhash' from yourhash.canary.tools) and API authentication token.",
+ "instructions": [
+ {
+ "type": "Textbox",
+ "parameters": {
+ "label": "Canary Console Domain",
+ "placeholder": "yourhash",
+ "type": "text",
+ "name": "clientId",
+ "validations": {
+ "required": true
+ }
+ }
+ },
+ {
+ "type": "Textbox",
+ "parameters": {
+ "label": "API Authentication Token",
+ "placeholder": "Enter your Canary API token",
+ "type": "password",
+ "name": "clientSecret",
+ "validations": {
+ "required": true
+ }
+ }
+ },
+ {
+ "type": "ConnectionToggleButton",
+ "parameters": {
+ "name": "toggle",
+ "connectLabel": "Connect",
+ "disconnectLabel": "Disconnect"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ },
+ {
+ "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnectorDefinition1')))]",
+ "apiVersion": "2022-01-01-preview",
+ "type": "Microsoft.OperationalInsights/workspaces/providers/metadata",
+ "properties": {
+ "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectorDefinitions', variables('_dataConnectorContentIdConnectorDefinition1'))]",
+ "contentId": "[variables('_dataConnectorContentIdConnectorDefinition1')]",
+ "kind": "DataConnector",
+ "version": "[variables('dataConnectorCCPVersion')]",
+ "source": {
+ "sourceId": "[variables('_solutionId')]",
+ "name": "[variables('_solutionName')]",
+ "kind": "Solution"
+ },
+ "author": {
+ "name": "Thinkst Applied Research",
+ "email": "[variables('_email')]"
+ },
+ "support": {
+ "name": "Thinkst Applied Research",
+ "email": "support@canary.tools",
+ "tier": "Partner",
+ "link": "https://help.canary.tools/"
+ },
+ "dependencies": {
+ "criteria": [
+ {
+ "version": "[variables('dataConnectorCCPVersion')]",
+ "contentId": "[variables('_dataConnectorContentIdConnections1')]",
+ "kind": "ResourcesDataConnector"
+ }
+ ]
+ }
+ }
+ },
+ {
+ "name": "[parameters('workspace')]",
+ "apiVersion": "2024-03-11",
+ "type": "Microsoft.Insights/dataCollectionEndpoints",
+ "location": "[parameters('workspace-location')]",
+ "properties": {
+ "networkAcls": {
+ "publicNetworkAccess": "Enabled"
+ }
+ }
+ },
+ {
+ "name": "ThinkstCanaryDCR",
+ "apiVersion": "2022-06-01",
+ "type": "Microsoft.Insights/dataCollectionRules",
+ "location": "[parameters('workspace-location')]",
+ "kind": "Direct",
+ "dependsOn": [
+ "[resourceId('Microsoft.Insights/dataCollectionEndpoints', parameters('workspace'))]"
+ ],
+ "properties": {
+ "streamDeclarations": {
+ "Custom-ThinkstCanaryIncidents_CL": {
+ "columns": [
+ {
+ "name": "acknowledged",
+ "type": "string"
+ },
+ {
+ "name": "created",
+ "type": "string"
+ },
+ {
+ "name": "created_printable",
+ "type": "string"
+ },
+ {
+ "name": "description",
+ "type": "string"
+ },
+ {
+ "name": "dst_host",
+ "type": "string"
+ },
+ {
+ "name": "dst_port",
+ "type": "string"
+ },
+ {
+ "name": "events_count",
+ "type": "string"
+ },
+ {
+ "name": "events_list",
+ "type": "dynamic"
+ },
+ {
+ "name": "flock_id",
+ "type": "string"
+ },
+ {
+ "name": "flock_name",
+ "type": "string"
+ },
+ {
+ "name": "hash_id",
+ "type": "string"
+ },
+ {
+ "name": "host",
+ "type": "dynamic"
+ },
+ {
+ "name": "incident_key",
+ "type": "string"
+ },
+ {
+ "name": "ip_address",
+ "type": "string"
+ },
+ {
+ "name": "ippers",
+ "type": "string"
+ },
+ {
+ "name": "key",
+ "type": "string"
+ },
+ {
+ "name": "local_time",
+ "type": "string"
+ },
+ {
+ "name": "logdata",
+ "type": "dynamic"
+ },
+ {
+ "name": "logtype",
+ "type": "string"
+ },
+ {
+ "name": "mac_address",
+ "type": "string"
+ },
+ {
+ "name": "memo",
+ "type": "string"
+ },
+ {
+ "name": "node_id",
+ "type": "string"
+ },
+ {
+ "name": "notified",
+ "type": "string"
+ },
+ {
+ "name": "previously_seen_count",
+ "type": "real"
+ },
+ {
+ "name": "sensor",
+ "type": "string"
+ },
+ {
+ "name": "src_host",
+ "type": "string"
+ },
+ {
+ "name": "src_host_reverse",
+ "type": "string"
+ },
+ {
+ "name": "src_port",
+ "type": "string"
+ },
+ {
+ "name": "updated",
+ "type": "string"
+ },
+ {
+ "name": "updated_id",
+ "type": "real"
+ },
+ {
+ "name": "updated_time",
+ "type": "string"
+ },
+ {
+ "name": "updated_time_printable",
+ "type": "string"
+ }
+ ]
+ }
+ },
+ "destinations": {
+ "logAnalytics": [
+ {
+ "workspaceResourceId": "[variables('workspaceResourceId')]",
+ "name": "clv2ws1"
+ }
+ ]
+ },
+ "dataFlows": [
+ {
+ "streams": [
+ "Custom-ThinkstCanaryIncidents_CL"
+ ],
+ "destinations": [
+ "clv2ws1"
+ ],
+ "outputStream": "Custom-ThinkstCanaryIncidents_CL",
+ "transformKql": "source | extend TimeGenerated = datetime_add('second', tolong(updated_time), datetime(1970-01-01)) | project TimeGenerated, IncidentId = tostring(incident_key), Description = tostring(description), Acknowledged = tostring(acknowledged), Created = toreal(created), CreatedPrintable = tostring(created_printable), DestinationIP = tostring(dst_host), DestinationPort = tostring(dst_port), EventsCount = tostring(events_count), Events = todynamic(events_list), FlockId = tostring(flock_id), FlockName = tostring(flock_name), HashId = tostring(hash_id), Host = todynamic(host), IpAddress = tostring(ip_address), IncidentUpdated = TimeGenerated, LocalTime = tostring(local_time), Memo = tostring(memo), RawEvent = todynamic(logdata), LogType = tostring(logtype), NodeId = tostring(node_id), Notified = tostring(notified), PreviouslySeenCount = toreal(previously_seen_count), Sensor = tostring(sensor), SourceIP = tostring(src_host), SrcHostReverse = tostring(src_host_reverse), SourcePort = tostring(src_port), UpdatedId = toreal(updated_id), UpdatedTimePrintable = tostring(updated_time_printable)"
+ }
+ ],
+ "dataCollectionEndpointId": "[variables('dataCollectionEndpointId')]"
+ }
+ },
+ {
+ "name": "ThinkstCanaryIncidents_CL",
+ "apiVersion": "2022-10-01",
+ "type": "Microsoft.OperationalInsights/workspaces/tables",
+ "location": "[parameters('workspace-location')]",
+ "kind": null,
+ "properties": {
+ "schema": {
+ "name": "ThinkstCanaryIncidents_CL",
+ "columns": [
+ {
+ "name": "TimeGenerated",
+ "type": "datetime",
+ "description": "Timestamp when the incident was last updated"
+ },
+ {
+ "name": "IncidentId",
+ "type": "string",
+ "description": "Unique incident key identifier"
+ },
+ {
+ "name": "Description",
+ "type": "string",
+ "description": "Incident type description (e.g. SSH Login Attempt)"
+ },
+ {
+ "name": "Acknowledged",
+ "type": "string",
+ "description": "Whether the incident has been acknowledged"
+ },
+ {
+ "name": "Created",
+ "type": "real",
+ "description": "Unix timestamp of incident creation"
+ },
+ {
+ "name": "CreatedPrintable",
+ "type": "string",
+ "description": "Human readable creation time"
+ },
+ {
+ "name": "DestinationIP",
+ "type": "string",
+ "description": "Destination IP address (Canary device)"
+ },
+ {
+ "name": "DestinationPort",
+ "type": "string",
+ "description": "Destination port targeted"
+ },
+ {
+ "name": "EventsCount",
+ "type": "string",
+ "description": "Number of events in this incident"
+ },
+ {
+ "name": "Events",
+ "type": "dynamic",
+ "description": "Array of event timestamps in milliseconds"
+ },
+ {
+ "name": "FlockId",
+ "type": "string",
+ "description": "Flock ID the incident belongs to"
+ },
+ {
+ "name": "FlockName",
+ "type": "string",
+ "description": "Flock name the incident belongs to"
+ },
+ {
+ "name": "HashId",
+ "type": "string",
+ "description": "Hash identifier for the incident"
+ },
+ {
+ "name": "Host",
+ "type": "dynamic",
+ "description": "Device details object (name, IP, version, services)"
+ },
+ {
+ "name": "IpAddress",
+ "type": "string",
+ "description": "IP address field"
+ },
+ {
+ "name": "IncidentUpdated",
+ "type": "datetime",
+ "description": "Datetime of last incident update"
+ },
+ {
+ "name": "LocalTime",
+ "type": "string",
+ "description": "Local time of the incident on the device"
+ },
+ {
+ "name": "Memo",
+ "type": "string",
+ "description": "Canarytoken reminder describing where the token was placed"
+ },
+ {
+ "name": "RawEvent",
+ "type": "dynamic",
+ "description": "Array of detailed event log objects"
+ },
+ {
+ "name": "LogType",
+ "type": "string",
+ "description": "Numeric log type identifier"
+ },
+ {
+ "name": "NodeId",
+ "type": "string",
+ "description": "Node ID of the Canary or Canarytoken"
+ },
+ {
+ "name": "Notified",
+ "type": "string",
+ "description": "Whether notification was sent"
+ },
+ {
+ "name": "PreviouslySeenCount",
+ "type": "real",
+ "description": "Number of times this source was previously seen"
+ },
+ {
+ "name": "Sensor",
+ "type": "string",
+ "description": "Sensor type (e.g. thinkstcanary)"
+ },
+ {
+ "name": "SourceIP",
+ "type": "string",
+ "description": "Source IP address of the attacker"
+ },
+ {
+ "name": "SrcHostReverse",
+ "type": "string",
+ "description": "Reverse DNS of the attacker"
+ },
+ {
+ "name": "SourcePort",
+ "type": "string",
+ "description": "Source port of the attacker"
+ },
+ {
+ "name": "UpdatedId",
+ "type": "real",
+ "description": "Incremental update ID for polling"
+ },
+ {
+ "name": "UpdatedTimePrintable",
+ "type": "string",
+ "description": "Human readable last update time"
+ }
+ ]
+ }
+ }
+ }
+ ]
+ },
+ "packageKind": "Solution",
+ "packageVersion": "[variables('_solutionVersion')]",
+ "packageName": "[variables('_solutionName')]",
+ "contentProductId": "[concat(take(variables('_solutionId'), 50),'-','dc','-', uniqueString(concat(variables('_solutionId'),'-','DataConnector','-',variables('_dataConnectorContentIdConnectorDefinition1'),'-', variables('dataConnectorCCPVersion'))))]",
+ "packageId": "[variables('_solutionId')]",
+ "contentSchemaVersion": "3.0.0",
+ "version": "[variables('dataConnectorCCPVersion')]"
+ }
+ },
+ {
+ "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentIdConnectorDefinition1'))]",
+ "apiVersion": "2022-09-01-preview",
+ "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectorDefinitions",
+ "location": "[parameters('workspace-location')]",
+ "kind": "Customizable",
+ "properties": {
+ "connectorUiConfig": {
+ "id": "ThinkstCanary",
+ "title": "Thinkst Canary",
+ "publisher": "Thinkst Engineering",
+ "descriptionMarkdown": "The Thinkst Canary connector allows you to ingest security incidents from your Thinkst Canary honeypot network into Microsoft Sentinel. Canary devices detect unauthorized access attempts including SSH logins, RDP sessions, HTTP requests, database queries, file share access, and Canarytoken triggers. This connector automatically pulls all incident data for analysis and alerting.",
+ "graphQueriesTableName": "ThinkstCanaryIncidents_CL",
+ "graphQueries": [
+ {
+ "metricName": "Total incidents received",
+ "legend": "Thinkst Canary Incidents",
+ "baseQuery": "{{graphQueriesTableName}}"
+ }
+ ],
+ "sampleQueries": [
+ {
+ "description": "All Thinkst Canary incidents in the last 24 hours",
+ "query": "ThinkstCanaryIncidents_CL\n| where TimeGenerated > ago(24h)\n| order by TimeGenerated desc"
+ },
+ {
+ "description": "Top 10 source IPs triggering incidents",
+ "query": "ThinkstCanaryIncidents_CL\n| summarize IncidentCount = count() by SourceIP\n| where isnotempty(SourceIP)\n| top 10 by IncidentCount desc"
+ },
+ {
+ "description": "Incidents by type",
+ "query": "ThinkstCanaryIncidents_CL\n| summarize Count = count() by Description\n| order by Count desc"
+ },
+ {
+ "description": "Incidents with event detail data",
+ "query": "ThinkstCanaryIncidents_CL\n| where isnotempty(RawEvent)\n| project TimeGenerated, Description, SourceIP, DestinationIP, DestinationPort, RawEvent"
+ },
+ {
+ "description": "Incidents by flock",
+ "query": "ThinkstCanaryIncidents_CL\n| summarize Count = count() by FlockId\n| order by Count desc"
+ }
+ ],
+ "dataTypes": [
+ {
+ "name": "ThinkstCanaryIncidents_CL",
+ "lastDataReceivedQuery": "ThinkstCanaryIncidents_CL\n| summarize Time = max(TimeGenerated)\n| where isnotempty(Time)"
+ }
+ ],
+ "connectivityCriteria": [
+ {
+ "type": "HasDataConnectors"
+ }
+ ],
+ "availability": {
+ "status": 1,
+ "isPreview": true
+ },
+ "permissions": {
+ "resourceProvider": [
+ {
+ "provider": "Microsoft.OperationalInsights/workspaces",
+ "permissionsDisplayText": "read and write permissions are required.",
+ "providerDisplayName": "Workspace",
+ "scope": "Workspace",
+ "requiredPermissions": {
+ "write": true,
+ "read": true,
+ "delete": false
+ }
+ },
+ {
+ "provider": "Microsoft.OperationalInsights/workspaces/sharedKeys",
+ "permissionsDisplayText": "read permissions to shared keys for the workspace are required. [See the documentation to learn more about workspace keys](https://docs.microsoft.com/azure/azure-monitor/platform/agent-windows#obtain-workspace-id-and-key).",
+ "providerDisplayName": "Keys",
+ "scope": "Workspace",
+ "requiredPermissions": {
+ "action": true
+ }
+ }
+ ],
+ "customs": [
+ {
+ "name": "Thinkst Canary API Key",
+ "description": "A Thinkst Canary API authentication token is required. [See the documentation](https://docs.canary.tools/guide/user-settings.html#generating-an-api-key) to learn how to generate an API key."
+ }
+ ]
+ },
+ "instructionSteps": [
+ {
+ "title": "Connect Thinkst Canary to Microsoft Sentinel",
+ "description": "Provide your Thinkst Canary Console domain (e.g. 'yourhash' from yourhash.canary.tools) and API authentication token.",
+ "instructions": [
+ {
+ "type": "Textbox",
+ "parameters": {
+ "label": "Canary Console Domain",
+ "placeholder": "yourhash",
+ "type": "text",
+ "name": "clientId",
+ "validations": {
+ "required": true
+ }
+ }
+ },
+ {
+ "type": "Textbox",
+ "parameters": {
+ "label": "API Authentication Token",
+ "placeholder": "Enter your Canary API token",
+ "type": "password",
+ "name": "clientSecret",
+ "validations": {
+ "required": true
+ }
+ }
+ },
+ {
+ "type": "ConnectionToggleButton",
+ "parameters": {
+ "name": "toggle",
+ "connectLabel": "Connect",
+ "disconnectLabel": "Disconnect"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ },
+ {
+ "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnectorDefinition1')))]",
+ "apiVersion": "2022-01-01-preview",
+ "type": "Microsoft.OperationalInsights/workspaces/providers/metadata",
+ "properties": {
+ "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectorDefinitions', variables('_dataConnectorContentIdConnectorDefinition1'))]",
+ "contentId": "[variables('_dataConnectorContentIdConnectorDefinition1')]",
+ "kind": "DataConnector",
+ "version": "[variables('dataConnectorCCPVersion')]",
+ "source": {
+ "sourceId": "[variables('_solutionId')]",
+ "name": "[variables('_solutionName')]",
+ "kind": "Solution"
+ },
+ "author": {
+ "name": "Thinkst Applied Research",
+ "email": "[variables('_email')]"
+ },
+ "support": {
+ "name": "Thinkst Applied Research",
+ "email": "support@canary.tools",
+ "tier": "Partner",
+ "link": "https://help.canary.tools/"
+ },
+ "dependencies": {
+ "criteria": [
+ {
+ "version": "[variables('dataConnectorCCPVersion')]",
+ "contentId": "[variables('_dataConnectorContentIdConnections1')]",
+ "kind": "ResourcesDataConnector"
+ }
+ ]
+ }
+ }
+ },
+ {
+ "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
+ "apiVersion": "2023-04-01-preview",
+ "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('dataConnectorTemplateNameConnections1'), variables('dataConnectorCCPVersion'))]",
+ "location": "[parameters('workspace-location')]",
+ "dependsOn": [
+ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
+ ],
+ "properties": {
+ "contentId": "[variables('_dataConnectorContentIdConnections1')]",
+ "displayName": "Thinkst Canary",
+ "contentKind": "ResourcesDataConnector",
+ "mainTemplate": {
+ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
+ "contentVersion": "[variables('dataConnectorCCPVersion')]",
+ "parameters": {
+ "guidValue": {
+ "defaultValue": "[newGuid()]",
+ "type": "securestring"
+ },
+ "innerWorkspace": {
+ "defaultValue": "[parameters('workspace')]",
+ "type": "securestring"
+ },
+ "connectorDefinitionName": {
+ "defaultValue": "Thinkst Canary",
+ "type": "securestring",
+ "minLength": 1
+ },
+ "workspace": {
+ "defaultValue": "[parameters('workspace')]",
+ "type": "securestring"
+ },
+ "dcrConfig": {
+ "defaultValue": {
+ "dataCollectionEndpoint": "data collection Endpoint",
+ "dataCollectionRuleImmutableId": "data collection rule immutableId"
+ },
+ "type": "object"
+ },
+ "clientId": {
+ "defaultValue": "clientId",
+ "type": "securestring",
+ "minLength": 1
+ },
+ "clientSecret": {
+ "defaultValue": "clientSecret",
+ "type": "securestring",
+ "minLength": 1
+ }
+ },
+ "variables": {
+ "_dataConnectorContentIdConnections1": "[variables('_dataConnectorContentIdConnections1')]"
+ },
+ "resources": [
+ {
+ "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnections1')))]",
+ "apiVersion": "2022-01-01-preview",
+ "type": "Microsoft.OperationalInsights/workspaces/providers/metadata",
+ "properties": {
+ "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectors', variables('_dataConnectorContentIdConnections1'))]",
+ "contentId": "[variables('_dataConnectorContentIdConnections1')]",
+ "kind": "ResourcesDataConnector",
+ "version": "[variables('dataConnectorCCPVersion')]",
+ "source": {
+ "sourceId": "[variables('_solutionId')]",
+ "name": "[variables('_solutionName')]",
+ "kind": "Solution"
+ },
+ "author": {
+ "name": "Thinkst Applied Research",
+ "email": "[variables('_email')]"
+ },
+ "support": {
+ "name": "Thinkst Applied Research",
+ "email": "support@canary.tools",
+ "tier": "Partner",
+ "link": "https://help.canary.tools/"
+ }
+ }
+ },
+ {
+ "name": "[concat(parameters('innerWorkspace'),'/Microsoft.SecurityInsights/', 'ThinkstCanaryIncidentsConnector', parameters('guidValue'))]",
+ "apiVersion": "2023-02-01-preview",
+ "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors",
+ "location": "[parameters('workspace-location')]",
+ "kind": "RestApiPoller",
+ "properties": {
+ "connectorDefinitionName": "ThinkstCanary",
+ "dataType": "ThinkstCanaryIncidents_CL",
+ "dcrConfig": {
+ "streamName": "Custom-ThinkstCanaryIncidents_CL",
+ "dataCollectionEndpoint": "[parameters('dcrConfig').dataCollectionEndpoint]",
+ "dataCollectionRuleImmutableId": "[parameters('dcrConfig').dataCollectionRuleImmutableId]"
+ },
+ "auth": {
+ "type": "APIKey",
+ "apiKey": "not-used-by-canary",
+ "apiKeyIdentifier": "QueryParameter",
+ "apiKeyName": "not_used_by_canary"
+ },
+ "request": {
+ "apiEndpoint": "[concat('https://',parameters('clientId'),'.canary.tools/api/v1/incidents/search')]",
+ "httpMethod": "GET",
+ "headers": {
+ "X-Canary-Auth-Token": "[parameters('clientSecret')]",
+ "User-Agent": "Microsoft Sentinel Thinkst Canary Connector - Version 1.0",
+ "Accept": "application/json"
+ },
+ "rateLimitQPS": 10,
+ "StartTimeAttributeName": "newer_than",
+ "queryTimeFormat": "yyyy-MM-dd-HH:mm:ss",
+ "queryWindowInMin": 5,
+ "retryCount": 3,
+ "timeoutInSeconds": 60,
+ "queryParameters": {
+ "filter_incident_state": "all",
+ "limit": "100"
+ }
+ },
+ "response": {
+ "eventsJsonPaths": [
+ "$.incidents"
+ ],
+ "format": "json",
+ "successStatusJsonPath": "$.result",
+ "successStatusValue": "success"
+ },
+ "paging": {
+ "pagingType": "NextPageToken",
+ "nextPageTokenJsonPath": "$.cursor.next",
+ "NextPageParaName": "cursor",
+ "pageSize": 100
+ }
+ }
+ }
+ ]
+ },
+ "packageKind": "Solution",
+ "packageVersion": "[variables('_solutionVersion')]",
+ "packageName": "[variables('_solutionName')]",
+ "contentProductId": "[concat(take(variables('_solutionId'), 50),'-','rdc','-', uniqueString(concat(variables('_solutionId'),'-','ResourcesDataConnector','-',variables('_dataConnectorContentIdConnections1'),'-', variables('dataConnectorCCPVersion'))))]",
+ "packageId": "[variables('_solutionId')]",
+ "contentSchemaVersion": "3.0.0",
+ "version": "[variables('dataConnectorCCPVersion')]"
+ }
+ },
+ {
+ "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
+ "apiVersion": "2023-04-01-preview",
+ "name": "[variables('analyticRuleObject1').analyticRuleTemplateSpecName1]",
+ "location": "[parameters('workspace-location')]",
+ "dependsOn": [
+ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
+ ],
+ "properties": {
+ "description": "SentinelIncidentsFromThinkstCanaryAlerts_AnalyticalRules Analytics Rule with template version 3.0.0",
+ "mainTemplate": {
+ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
+ "contentVersion": "[variables('analyticRuleObject1').analyticRuleVersion1]",
+ "parameters": {},
+ "variables": {},
+ "resources": [
+ {
+ "type": "Microsoft.SecurityInsights/AlertRuleTemplates",
+ "name": "[variables('analyticRuleObject1')._analyticRulecontentId1]",
+ "apiVersion": "2023-02-01-preview",
+ "kind": "NRT",
+ "location": "[parameters('workspace-location')]",
+ "properties": {
+ "description": "Creates Microsoft Sentinel incidents from Thinkst Canary alerts.",
+ "displayName": "Canary alerts to incidents",
+ "enabled": false,
+ "query": "ThinkstCanaryIncidents_CL\n| where Description != \"Canary Disconnected\"\n| where Description != \"Canary Reconnected\"\n| where Description != \"Canary Settings Changed\"\n| where Description != \"Fake Location\"\n| where Description != \"Network Settings Roll-back\"\n| extend EventData = todynamic(RawEvent[0])\n| extend IsCanarytoken = Description contains \"Canarytoken\"\n or LogType startswith \"16\"\n or LogType startswith \"17\"\n or isnotempty(tostring(EventData.canarytoken))\n| extend PhysicalCanaryName = coalesce(tostring(Host.name), NodeId),\n PhysicalCanaryIP = coalesce(tostring(Host.ip_address), DestinationIP, IpAddress),\n TokenMemo = iff(IsCanarytoken, substring(Memo, 0, 256), \"\"),\n TokenType = coalesce(tostring(EventData.kind), tostring(EventData.type)),\n TokenHostname = tostring(EventData.hostname),\n TokenTarget = substring(coalesce(tostring(EventData.url), tostring(EventData.hostname), tostring(EventData.cloned_site), tostring(EventData.original_site), tostring(EventData.generic_data), tostring(EventData.location)), 0, 512),\n TokenUsername = coalesce(tostring(EventData.windows_desktopini_access_username), tostring(EventData.ms_macro_username), tostring(EventData.cmd_user_name)),\n TokenDomain = coalesce(tostring(EventData.windows_desktopini_access_domain), tostring(EventData.cmd_machine_name)),\n TokenHost = coalesce(tostring(EventData.windows_desktopini_computer_name), tostring(EventData.cmd_computer_name), tostring(EventData.cmd_workstation), tostring(EventData.cmd_machine_name)),\n TokenSourceIP = coalesce(tostring(EventData.cmd_resolved_ip), tostring(EventData.ms_macro_ip)),\n TokenCity = coalesce(tostring(EventData.geoip.city), tostring(EventData.geoip.City), tostring(EventData.City)),\n TokenCountry = coalesce(tostring(EventData.geoip.country), tostring(EventData.geoip.country_name), tostring(EventData.geoip.Country), tostring(EventData.Country)),\n TokenContext = case(\n isnotempty(tostring(EventData.client_public_key)), strcat(\"WireGuard public key: \", substring(tostring(EventData.client_public_key), 0, 128), \"; session: \", tostring(EventData.client_session_index)),\n isnotempty(tostring(EventData.masked_card_number)), strcat(\"Masked card: \", tostring(EventData.masked_card_number), \"; transaction: \", tostring(EventData.transaction_amount), \" \", tostring(EventData.transaction_currency), \"; merchant: \", tostring(EventData.merchant)),\n isnotempty(tostring(EventData.referer)), strcat(\"Referrer: \", substring(tostring(EventData.referer), 0, 256)),\n \"\"),\n UserAgent = substring(coalesce(tostring(EventData.USERAGENT), tostring(EventData.HEADERS['user-agent']), tostring(EventData.headers['User-Agent']), tostring(EventData.headers['user-agent'])), 0, 512)\n| extend ActorUsername = coalesce(tostring(EventData.USERNAME), tostring(EventData.USER), tostring(EventData.FORMDATA.username), tostring(EventData.POSTDATA.username), TokenUsername),\n ActorDomain = coalesce(tostring(EventData.DOMAIN), tostring(EventData.DOMAINNAME), TokenDomain),\n ActorHost = coalesce(TokenHost, tostring(EventData.HOSTNAME)),\n Activity = coalesce(TokenContext, TokenType, tostring(EventData.INSTANCE_NAME), tostring(EventData.FUNC_NAME), tostring(EventData.METHOD), tostring(EventData.OPCODE), tostring(EventData.COMMAND), tostring(EventData.FUNCTION), Description)\n| extend SourceIP = coalesce(SourceIP, tostring(EventData.src_host), TokenSourceIP),\n SourceGeo = case(isnotempty(TokenCity) and isnotempty(TokenCountry), strcat(TokenCity, \", \", TokenCountry), isnotempty(TokenCity), TokenCity, TokenCountry),\n AssetType = iff(IsCanarytoken, \"Canarytoken\", \"Canary\"),\n AssetName = iff(IsCanarytoken, coalesce(TokenMemo, TokenTarget, TokenType, NodeId), PhysicalCanaryName),\n AssetNode = NodeId,\n AssetIP = iff(IsCanarytoken, \"\", PhysicalCanaryIP),\n AssetLocation = iff(IsCanarytoken, \"\", tostring(Host.description)),\n CanaryEntityName = iff(IsCanarytoken, \"\", PhysicalCanaryName),\n CanaryEntityIP = iff(IsCanarytoken, \"\", PhysicalCanaryIP)\n| extend SourceDisplay = coalesce(SourceIP, SrcHostReverse, \"unknown source\")\n| project TimeGenerated, Description, IncidentId, AssetType, AssetName, AssetNode,\n AssetIP, AssetLocation, FlockName, TokenMemo, TokenType, TokenTarget,\n TokenHostname, ActorUsername, ActorDomain, ActorHost, SourceGeo, SourceIP,\n SourceDisplay, SrcHostReverse, DestinationPort, Activity, UserAgent, LogType,\n EventsCount, CanaryEntityName, CanaryEntityIP\n",
+ "severity": "High",
+ "suppressionDuration": "PT1H",
+ "suppressionEnabled": false,
+ "status": "Available",
+ "requiredDataConnectors": [
+ {
+ "connectorId": "ThinkstCanary",
+ "dataTypes": [
+ "ThinkstCanaryIncidents_CL"
+ ]
+ }
+ ],
+ "tactics": [
+ "LateralMovement",
+ "Exfiltration"
+ ],
+ "entityMappings": [
+ {
+ "entityType": "IP",
+ "fieldMappings": [
+ {
+ "columnName": "SourceIP",
+ "identifier": "Address"
+ }
+ ]
+ },
+ {
+ "entityType": "IP",
+ "fieldMappings": [
+ {
+ "columnName": "CanaryEntityIP",
+ "identifier": "Address"
+ }
+ ]
+ },
+ {
+ "entityType": "Host",
+ "fieldMappings": [
+ {
+ "columnName": "CanaryEntityName",
+ "identifier": "HostName"
+ }
+ ]
+ },
+ {
+ "entityType": "Account",
+ "fieldMappings": [
+ {
+ "columnName": "ActorUsername",
+ "identifier": "Name"
+ }
+ ]
+ },
+ {
+ "entityType": "DNS",
+ "fieldMappings": [
+ {
+ "columnName": "TokenHostname",
+ "identifier": "DomainName"
+ }
+ ]
+ }
+ ],
+ "eventGroupingSettings": {
+ "aggregationKind": "AlertPerResult"
+ },
+ "customDetails": {
+ "TokenTarget": "TokenTarget",
+ "FlockName": "FlockName",
+ "ActorUsername": "ActorUsername",
+ "IncidentKey": "IncidentId",
+ "EventsCount": "EventsCount",
+ "AssetLocation": "AssetLocation",
+ "ActorHost": "ActorHost",
+ "Activity": "Activity",
+ "TokenMemo": "TokenMemo",
+ "UserAgent": "UserAgent",
+ "AssetType": "AssetType",
+ "AssetNode": "AssetNode",
+ "LogType": "LogType",
+ "ActorDomain": "ActorDomain",
+ "DestinationPort": "DestinationPort",
+ "SourceGeo": "SourceGeo",
+ "TokenType": "TokenType",
+ "AssetIP": "AssetIP",
+ "SourceIP": "SourceIP",
+ "AssetName": "AssetName"
+ },
+ "alertDetailsOverride": {
+ "alertDescriptionFormat": "Thinkst {{AssetType}} {{AssetName}} recorded this activity from {{SourceDisplay}}. Review the mapped entities and custom details for asset, actor, and activity context.",
+ "alertDisplayNameFormat": "{{Description}} - {{AssetName}} from {{SourceDisplay}}"
+ },
+ "incidentConfiguration": {
+ "groupingConfiguration": {
+ "matchingMethod": "AllEntities",
+ "enabled": false,
+ "reopenClosedIncident": false,
+ "lookbackDuration": "PT5H"
+ },
+ "createIncident": true
+ }
+ }
+ },
+ {
+ "type": "Microsoft.OperationalInsights/workspaces/providers/metadata",
+ "apiVersion": "2022-01-01-preview",
+ "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleObject1').analyticRuleId1,'/'))))]",
+ "properties": {
+ "description": "ThinkstCanary Analytics Rule 1",
+ "parentId": "[variables('analyticRuleObject1').analyticRuleId1]",
+ "contentId": "[variables('analyticRuleObject1')._analyticRulecontentId1]",
+ "kind": "AnalyticsRule",
+ "version": "[variables('analyticRuleObject1').analyticRuleVersion1]",
+ "source": {
+ "kind": "Solution",
+ "name": "ThinkstCanary",
+ "sourceId": "[variables('_solutionId')]"
+ },
+ "author": {
+ "name": "Thinkst Applied Research",
+ "email": "[variables('_email')]"
+ },
+ "support": {
+ "name": "Thinkst Applied Research",
+ "email": "support@canary.tools",
+ "tier": "Partner",
+ "link": "https://help.canary.tools/"
+ }
+ }
+ }
+ ]
+ },
+ "packageKind": "Solution",
+ "packageVersion": "[variables('_solutionVersion')]",
+ "packageName": "[variables('_solutionName')]",
+ "packageId": "[variables('_solutionId')]",
+ "contentSchemaVersion": "3.0.0",
+ "contentId": "[variables('analyticRuleObject1')._analyticRulecontentId1]",
+ "contentKind": "AnalyticsRule",
+ "displayName": "Canary alerts to incidents",
+ "contentProductId": "[variables('analyticRuleObject1')._analyticRulecontentProductId1]",
+ "id": "[variables('analyticRuleObject1')._analyticRulecontentProductId1]",
+ "version": "[variables('analyticRuleObject1').analyticRuleVersion1]"
+ }
+ },
+ {
+ "type": "Microsoft.OperationalInsights/workspaces/providers/contentPackages",
+ "apiVersion": "2023-04-01-preview",
+ "location": "[parameters('workspace-location')]",
+ "properties": {
+ "version": "1.0.0",
+ "kind": "Solution",
+ "contentSchemaVersion": "3.0.0",
+ "displayName": "ThinkstCanary",
+ "publisherDisplayName": "Thinkst Applied Research",
+ "descriptionHtml": "
Note: Please refer to the following before installing the solution:
\n• Review the solution Release Notes
\n• There may be known issues pertaining to this Solution, please refer to them before installing.
\nThe Thinkst Canary solution for Microsoft Sentinel ingests Canary and Canarytoken incidents through the Codeless Connector Framework and provides normalized parsers, detections and response automation.
\nData Connectors: 1, Analytic Rules: 1
\nLearn more about Microsoft Sentinel | Learn more about Solutions
\n", + "contentKind": "Solution", + "contentProductId": "[variables('_solutioncontentProductId')]", + "id": "[variables('_solutioncontentProductId')]", + "icon": "