diff --git a/Solutions/Blacklens/Package/1.0.0.zip b/Solutions/Blacklens/Package/1.0.0.zip new file mode 100644 index 00000000000..51d7ef21e2f Binary files /dev/null and b/Solutions/Blacklens/Package/1.0.0.zip differ diff --git a/Solutions/Blacklens/Package/mainTemplate.json b/Solutions/Blacklens/Package/mainTemplate.json new file mode 100644 index 00000000000..591301cc19f --- /dev/null +++ b/Solutions/Blacklens/Package/mainTemplate.json @@ -0,0 +1,599 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "author": "snapSEC GmbH", + "comments": "blacklens Insights Solution" + }, + "parameters": { + "location": { + "type": "string", + "minLength": 1, + "defaultValue": "[resourceGroup().location]" + }, + "workspaceResourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID from the log workspace, where Sentinel is connected to. Go to Overview > JSON View (right-top) and copy the Resource ID." + } + }, + "dceName": { + "type": "string", + "defaultValue": "dce-blacklens" + }, + "dcrName": { + "type": "string", + "defaultValue": "dcr-blacklens" + }, + "tableName": { + "type": "string", + "defaultValue": "blacklens_CL" + }, + "streamName": { + "type": "string", + "defaultValue": "Custom-blacklens_CL" + } + }, + "variables": { + "ridParts": "[split(parameters('workspaceResourceId'), '/')]", + "subId": "[variables('ridParts')[2]]", + "rgName": "[variables('ridParts')[4]]", + "wsName": "[variables('ridParts')[8]]" + }, + "resources": [ + { + "type": "Microsoft.Insights/dataCollectionEndpoints", + "apiVersion": "2023-03-11", + "name": "[parameters('dceName')]", + "location": "[parameters('location')]", + "properties": { + "networkAcls": { + "publicNetworkAccess": "Enabled" + } + } + }, + { + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2023-03-11", + "name": "[parameters('dcrName')]", + "location": "[parameters('location')]", + "properties": { + "dataCollectionEndpointId": "[resourceId('Microsoft.Insights/dataCollectionEndpoints', parameters('dceName'))]", + "streamDeclarations": { + "[format('{0}', parameters('streamName'))]": { + "columns": [ + { + "name": "TimeGenerated", + "type": "datetime" + }, + { + "name": "id", + "type": "string" + }, + { + "name": "ws_id", + "type": "string" + }, + { + "name": "alert_title", + "type": "string" + }, + { + "name": "message", + "type": "string" + }, + { + "name": "severity", + "type": "string" + }, + { + "name": "link", + "type": "string" + }, + { + "name": "payload", + "type": "dynamic" + } + ] + } + }, + "destinations": { + "logAnalytics": [ + { + "name": "sentinelWorkspace", + "workspaceResourceId": "[parameters('workspaceResourceId')]" + } + ] + }, + "dataFlows": [ + { + "streams": [ + "[parameters('streamName')]" + ], + "destinations": [ + "sentinelWorkspace" + ], + "outputStream": "[parameters('streamName')]" + } + ] + }, + "dependsOn": [ + "[resourceId('Microsoft.Insights/dataCollectionEndpoints', parameters('dceName'))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subId'), variables('rgName')), 'Microsoft.Resources/deployments', 'blacklens-table')]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "blacklens-table", + "subscriptionId": "[variables('subId')]", + "resourceGroup": "[variables('rgName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "workspaceName": { + "value": "[variables('wsName')]" + }, + "tableName": { + "value": "[parameters('tableName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "16589392648025521741" + } + }, + "parameters": { + "workspaceName": { + "type": "string" + }, + "tableName": { + "type": "string", + "defaultValue": "blacklens_CL" + } + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/tables", + "apiVersion": "2022-10-01", + "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('tableName'))]", + "properties": { + "plan": "Analytics", + "schema": { + "name": "[parameters('tableName')]", + "columns": [ + { + "name": "TimeGenerated", + "type": "datetime" + }, + { + "name": "id", + "type": "string" + }, + { + "name": "ws_id", + "type": "string" + }, + { + "name": "alert_title", + "type": "string" + }, + { + "name": "message", + "type": "string" + }, + { + "name": "severity", + "type": "string" + }, + { + "name": "link", + "type": "string" + }, + { + "name": "payload", + "type": "dynamic" + } + ] + } + } + } + ], + "outputs": { + "tableNameOut": { + "type": "string", + "value": "[parameters('tableName')]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "la-blacklens-alert-log-ingestion", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "logicAppName": { + "value": "la-blacklens-alert-log-ingestion" + }, + "dceLogsIngestionEndpoint": { + "value": "[reference(resourceId('Microsoft.Insights/dataCollectionEndpoints', parameters('dceName')), '2023-03-11').logsIngestion.endpoint]" + }, + "dcrImmutableId": { + "value": "[reference(resourceId('Microsoft.Insights/dataCollectionRules', parameters('dcrName')), '2023-03-11').immutableId]" + }, + "streamName": { + "value": "[parameters('streamName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "1245268422438739651" + } + }, + "parameters": { + "location": { + "type": "string" + }, + "logicAppName": { + "type": "string", + "defaultValue": "la-blacklens-alert-log-ingestion" + }, + "dceLogsIngestionEndpoint": { + "type": "string" + }, + "dcrImmutableId": { + "type": "string" + }, + "streamName": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Logic/workflows", + "apiVersion": "2019-05-01", + "name": "[parameters('logicAppName')]", + "location": "[parameters('location')]", + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "state": "Enabled", + "definition": { + "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "dceLogsIngestionEndpoint": { + "type": "String" + }, + "dcrImmutableId": { + "type": "String" + }, + "streamName": { + "type": "String" + }, + "$connections": { + "type": "Object", + "defaultValue": {} + } + }, + "triggers": { + "When_an_alert_is_received_from_blacklens_io": { + "type": "Request", + "kind": "Http", + "runtimeConfiguration": { + "secureData": { + "properties": [ + "inputs", + "outputs" + ] + } + } + } + }, + "actions": { + "AutoDecode": { + "runAfter": {}, + "type": "Compose", + "inputs": "@{if(contains(toLower(string(triggerOutputs()?['headers']?['Content-Type'])), 'application/octet-stream'), base64ToString(string(triggerBody())), string(triggerBody()))}" + }, + "Validate_JSON": { + "runAfter": { + "AutoDecode": [ + "Succeeded" + ] + }, + "type": "ParseJson", + "inputs": { + "content": "@outputs('AutoDecode')", + "schema": { + "type": "object", + "properties": { + "id": {}, + "ws_id": {}, + "created_date": {}, + "title": { + "type": "string" + }, + "message": { + "type": "string" + }, + "severity": { + "type": "string" + }, + "link": {}, + "payload": {} + } + }, + "runtimeConfiguration": { + "secureData": { + "properties": [ + "inputs", + "outputs" + ] + } + } + } + }, + "HTTP": { + "runAfter": { + "Validate_JSON": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "@{concat(parameters('dceLogsIngestionEndpoint'), '/dataCollectionRules/', parameters('dcrImmutableId'), '/streams/', parameters('streamName'), '?api-version=2023-01-01')}", + "method": "POST", + "headers": { + "Content-Type": "application/json" + }, + "body": [ + { + "TimeGenerated": "@{body('Validate_JSON')?['created_date']}", + "id": "@{string(body('Validate_JSON')?['id'])}", + "ws_id": "@{string(body('Validate_JSON')?['ws_id'])}", + "alert_title": "@{body('Validate_JSON')?['title']}", + "message": "@{body('Validate_JSON')?['message']}", + "severity": "@{body('Validate_JSON')?['severity']}", + "link": "@{string(body('Validate_JSON')?['link'])}", + "payload": "@{body('Validate_JSON')?['payload']}" + } + ], + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://monitor.azure.com" + } + }, + "runtimeConfiguration": { + "secureData": { + "properties": [ + "inputs", + "outputs" + ] + }, + "contentTransfer": { + "transferMode": "Chunked" + } + } + } + }, + "outputs": {} + }, + "parameters": { + "dceLogsIngestionEndpoint": { + "value": "[parameters('dceLogsIngestionEndpoint')]" + }, + "dcrImmutableId": { + "value": "[parameters('dcrImmutableId')]" + }, + "streamName": { + "value": "[parameters('streamName')]" + }, + "$connections": { + "value": {} + } + } + } + } + ], + "outputs": { + "logicAppResourceId": { + "type": "string", + "value": "[resourceId('Microsoft.Logic/workflows', parameters('logicAppName'))]" + }, + "webhookUrl": { + "type": "string", + "value": "[listCallbackUrl(resourceId('Microsoft.Logic/workflows/triggers', parameters('logicAppName'), 'When_an_alert_is_received_from_blacklens_io'), '2016-06-01').value]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Insights/dataCollectionEndpoints', parameters('dceName'))]", + "[resourceId('Microsoft.Insights/dataCollectionRules', parameters('dcrName'))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "blacklens-dcr-roleassign", + "subscriptionId": "[variables('subId')]", + "resourceGroup": "[variables('rgName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dcrName": { + "value": "[parameters('dcrName')]" + }, + "logicAppResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'la-blacklens-alert-log-ingestion'), '2025-04-01').outputs.logicAppResourceId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "2433944844148284348" + } + }, + "parameters": { + "dcrName": { + "type": "string" + }, + "logicAppResourceId": { + "type": "string" + } + }, + "variables": { + "roleDefId": "3913510d-42f4-4e42-8a64-420c390055eb" + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Insights/dataCollectionRules/{0}', parameters('dcrName'))]", + "name": "[guid(resourceId('Microsoft.Insights/dataCollectionRules', parameters('dcrName')), parameters('logicAppResourceId'), variables('roleDefId'))]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefId'))]", + "principalId": "[reference(parameters('logicAppResourceId'), '2019-05-01', 'Full').identity.principalId]", + "principalType": "ServicePrincipal" + } + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'la-blacklens-alert-log-ingestion')]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "blacklens-analytic-rule", + "subscriptionId": "[variables('subId')]", + "resourceGroup": "[variables('rgName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "workspaceName": { + "value": "[variables('wsName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.39.26.7824", + "templateHash": "13108905814963156612" + } + }, + "parameters": { + "workspaceName": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.SecurityInsights/alertRules", + "apiVersion": "2023-12-01-preview", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('workspaceName'))]", + "name": "e261b70a-3005-4a1b-a7a2-2c8147fafed7", + "kind": "NRT", + "properties": { + "displayName": "blacklens Insights", + "description": "", + "severity": "High", + "enabled": true, + "query": "blacklens_CL\n| summarize arg_max(TimeGenerated, *) by id\n| extend AlertSeverity = case(\n tolower(severity) == \"high\", \"High\",\n tolower(severity) == \"medium\", \"Medium\",\n tolower(severity) == \"low\", \"Low\",\n \"Informational\"\n)\n", + "suppressionDuration": "PT5H", + "suppressionEnabled": false, + "tactics": [], + "techniques": [], + "subTechniques": [], + "incidentConfiguration": { + "createIncident": true, + "groupingConfiguration": { + "enabled": false, + "reopenClosedIncident": false, + "lookbackDuration": "PT5H", + "matchingMethod": "AllEntities", + "groupByEntities": [], + "groupByAlertDetails": [], + "groupByCustomDetails": [] + } + }, + "eventGroupingSettings": { + "aggregationKind": "AlertPerResult" + }, + "alertDetailsOverride": { + "alertDisplayNameFormat": "{{alert_title}}", + "alertDescriptionFormat": "{{message}}", + "alertSeverityColumnName": "AlertSeverity", + "alertDynamicProperties": [] + }, + "customDetails": {}, + "entityMappings": [ + { + "entityType": "URL", + "fieldMappings": [ + { + "identifier": "Url", + "columnName": "link" + } + ] + } + ], + "sentinelEntitiesMappings": null, + "templateVersion": null + } + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Insights/dataCollectionRules', parameters('dcrName'))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subId'), variables('rgName')), 'Microsoft.Resources/deployments', 'blacklens-table')]" + ] + } + ], + "outputs": { + "blacklensWebhookUrl": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'la-blacklens-alert-log-ingestion'), '2025-04-01').outputs.webhookUrl.value]" + } + } +} \ No newline at end of file diff --git a/Solutions/Blacklens/README.md b/Solutions/Blacklens/README.md new file mode 100644 index 00000000000..5f33e4b4b75 --- /dev/null +++ b/Solutions/Blacklens/README.md @@ -0,0 +1,55 @@ +# blacklens.io + +The **blacklens.io Microsoft Sentinel integration** allows you to ingest all related alerts about your Attack Surface directly in Microsoft Sentinel. + +**blacklens.io** is a comprehensive **Attack Surface Management (ASM)** platform that helps organizations understand and secure their external attack surface. By combining automated security analysis, continuous monitoring, and penetration testing, blacklens.io identifies and addresses vulnerabilities early. Features such as **Darknet Monitoring**, **Vulnerability Scanning**, and **XDR Response** enable a proactive defense strategy and provide a clear, continuous view of an organization’s external security posture. + +This integration enables security teams to **centralize blacklens.io alerts in Microsoft Sentinel**, correlate them with other security data sources, and automatically create incidents for investigation and response. + +--- + +## What does this solution deploy? + +When you install this solution, the following resources are deployed: + +- A **custom Log Analytics table**: `blacklens_CL` +- A **Data Collection Endpoint (DCE)** and **Data Collection Rule (DCR)** for secure log ingestion +- A **Logic App (webhook-based)** to receive alerts from blacklens.io +- A **Microsoft Sentinel Analytics Rule** to generate incidents from ingested alerts + +--- + +## Prerequisites + +Before installing this solution, ensure that: + +- Microsoft Sentinel is enabled on the target Log Analytics workspace +- You have **Contributor** or **Owner** permissions on the workspace and resource group + +--- + +## Installation + +1. Open **Microsoft Sentinel** in the Azure Portal. +2. Navigate to **Content hub**. +3. Search for **blacklens.io**. +4. Select the solution and click **Install**. +5. Choose the subscription, resource group, where you want to place the resources (probably the same resource group, where Sentinel's Log Analytics workspace is located) and the target Log Analytics workspace Resource ID. +6. Complete the installation. + +After the installation finishes, continue with the post-deployment configuration steps below. + +--- + +## Post-deployment configuration (Guided steps) + +After deployment, a webhook endpoint is created that must be configured in blacklens.io. + +### Step 1: Copy the webhook URL + +1. Open the **deployment details** of the installed solution. +2. Navigate to the **Outputs** tab. +3. Copy the webhook +4. Integrate it into blacklens.io +5. After some minutes a informational test incident should appear in the Microsoft Sentinel + diff --git a/Solutions/Blacklens/ReleaseNotes.md b/Solutions/Blacklens/ReleaseNotes.md new file mode 100644 index 00000000000..a7eb6e0a3a8 --- /dev/null +++ b/Solutions/Blacklens/ReleaseNotes.md @@ -0,0 +1,3 @@ +| **Version** | **Date Modified (DD-MM-YYYY)** | **Change History** | +|-------------|--------------------------------|---------------------------------------------| +| 1.0.0 | 31-12-2025 | Initial Solution Release.| diff --git a/Solutions/Blacklens/SolutionMetadata.json b/Solutions/Blacklens/SolutionMetadata.json new file mode 100644 index 00000000000..dbfad68eb19 --- /dev/null +++ b/Solutions/Blacklens/SolutionMetadata.json @@ -0,0 +1,18 @@ +{ + "publisherId": "snapsecgmbh1733575353555", + "offerId": "blacklens-solution", + "firstPublishDate": "2025-12-31", + "lastPublishDate": "2025-12-31", + "providers": ["snapSEC GmbH"], + "categories": { + "domains": ["Security - Threat Intelligence"], + "verticals": [] + }, + "support": { + "name": "blacklens.io Support", + "email": "support@blacklens.io", + "tier": "Partner", + "link": "https://blacklens.io/contact" + } +} + \ No newline at end of file