diff --git a/Solutions/Cisco ETD/Data Connectors/CiscoETDAzureFunction.zip b/Solutions/Cisco ETD/Data Connectors/CiscoETDAzureFunction.zip deleted file mode 100644 index 79128f77ff4..00000000000 Binary files a/Solutions/Cisco ETD/Data Connectors/CiscoETDAzureFunction.zip and /dev/null differ diff --git a/Solutions/Cisco ETD/Data Connectors/CiscoETDAzureSentinelConnector/__init__.py b/Solutions/Cisco ETD/Data Connectors/CiscoETDAzureSentinelConnector/__init__.py deleted file mode 100644 index a1773dce819..00000000000 --- a/Solutions/Cisco ETD/Data Connectors/CiscoETDAzureSentinelConnector/__init__.py +++ /dev/null @@ -1,279 +0,0 @@ -""" -Azure Function to fetch Email Threat Detection messages from the Cisco ETD Api and send the mesages to Sentinel to be able to analyze them on Log Analytics. -""" -import logging -import datetime -import json -import requests -import hashlib -import hmac -import base64 -import os -from http import HTTPStatus -import azure.functions as func - -# Global variables for Connector -APIKEY = os.environ.get("ApiKey","") -CLIENTID = os.environ.get("ClientId","") -CLIENTSECRET = os.environ.get("ClientSecret","") -WORKSPACEID = os.environ.get("WorkspaceID","") -WORKSPACESHAREDKEY= os.environ.get("SharedKey","") -VERDICTS = os.environ.get("Verdicts","malicious").split(",") -REGION = os.environ.get("Region","us") -TABLENAME = "CiscoETD" -CHUNKSIZE = 20 -PAGESIZE = 50 -APISCHEME = "https://api." -APITOKENENDPOINT = ".etd.cisco.com/v1/oauth/token" -APIMESSAGEENDPOINT = ".etd.cisco.com/v1/messages/search" -LAST = "Last" -NEXT = "Next" -UTCZONE = "Z" - -def retryRequest(url, headers, jsonData=None, retryCount=3): - """ - Function to post messages and retry on failure - :param url: url to post messages to - :param headers: headers to add to the post call - :param jsonData: payload for the post call - :param retryCount: number of retries on failure, default value is set to 3 - :return: response if successful, None otherwise - """ - while retryCount > 0: - try: - response = requests.post(url, headers=headers, json=jsonData, timeout=5) - except Exception as err: - logging.error(f"Error during the request: {err}") - retryCount -= 1 - else: - if response.status_code == HTTPStatus.OK: - logging.info("Post request successful") - return response - elif response.status_code == HTTPStatus.UNAUTHORIZED: - logging.error("Authorization Error while calling post request") - return response - else: - logging.error(f"Post request failed, retrying... status code: {response.status_code}") - retryCount -= 1 - return None - -class ETD(): - """ - Class ETD is responsible for fetching the messages from ETD API - """ - def __init__(self, apiKey, clientId, clientSecret, verdicts, region, lastExecutedTime, currentTime): - self.apiKey = apiKey - self.clientId = clientId - self.clientSecret = clientSecret - self.messageFilter = [v.strip() for v in verdicts] - self.secretToken = "" - self.region = region - self.lastExecutedTime = lastExecutedTime - self.currentUtcTime = currentTime - self.tokenUrl = APISCHEME + self.region + APITOKENENDPOINT - self.messageUrl = APISCHEME + self.region + APIMESSAGEENDPOINT - - def generateToken(self): - """ - Function to generate the token for ETD message search api - :return: True if successful, False otherwise - """ - # Construct token URL - credentials = CLIENTID + ":" + CLIENTSECRET - # Create signature - signature = base64.b64encode(credentials.encode()).decode() - # Construct Headers - headers = { - "Host": "api." + self.region + ".etd.cisco.com", - "clientId": self.clientId, - "secret": self.clientSecret, - "x-api-key": self.apiKey, - "Authorization": "Basic " + signature - } - tokenResponse = retryRequest(url=self.tokenUrl, headers=headers) - if tokenResponse: - if tokenResponse.status_code == HTTPStatus.OK: - self.secretToken = tokenResponse.json().get('accessToken') - return True - return False - - def fetchMessage(self,nextPageToken=None): - """ - Function to fetch messages from ETD message search api - :param nextPageToken: token to fetch messages from next page, default value is None - :return: messages fetched if successful, else empty dictionary - """ - # Construct headers - messageHeaders = { - "Host": "api." + self.region + ".etd.cisco.com", - "x-api-key": self.apiKey, - "Accept": "application/json", - "Authorization": "Bearer "+ self.secretToken - } - # Construct body - messageJson = { - "timestamp":[self.lastExecutedTime, self.currentUtcTime], - "verdicts": self.messageFilter, - "pageSize": PAGESIZE #Each page will consist of PAGESIZE messages - } - # Append pageToken to body, if "nextPageToken" field contains value - if nextPageToken: - messageJson["pageToken"] = nextPageToken - - messageResponse = retryRequest(self.messageUrl, messageHeaders, messageJson) - if messageResponse: - if messageResponse.status_code == HTTPStatus.OK: - logging.info("Message search API call successful") - return messageResponse.json() - elif messageResponse.status_code == HTTPStatus.UNAUTHORIZED: - if not self.generateToken(): - logging.error("Error in generating token for the request") - return {} - messageHeaders["Authorization"] = "Bearer " + self.secretToken - messageResponse = retryRequest(self.messageUrl, messageHeaders, messageJson) - if messageResponse: - if messageResponse.status_code == HTTPStatus.OK: - logging.info("Message search API call successful") - return messageResponse.json() - else: - return {} - else: - return {} - else: - logging.error("Message search API call failed") - return {} - -class Sentinel(): - """ - Class Sentinel is responsible for sending the messages to Log Analytics - """ - @staticmethod - def buildSignature(date, contentLength, method, contentType, resource): - """ - Function to build signature for Authorization for Log Analytics Workspace - :param date: current time in UTC - :param contentLength: length of content - :param method: http method (POST) - :param contentType: type of content in payload(application/json) - :param resource: endpoint for messages to be posted - :return: computed authorization key - """ - xHeaders = 'x-ms-date:' + date - stringToHash = method + "\n" + str(contentLength) + "\n" + contentType + "\n" + xHeaders + "\n" + resource - bytesToHash = bytes(stringToHash, encoding="utf-8") - decodedKey = base64.b64decode(WORKSPACESHAREDKEY) - encodedHash = base64.b64encode(hmac.new(decodedKey, bytesToHash, digestmod=hashlib.sha256).digest()).decode() - authorization = "SharedKey {}:{}".format(WORKSPACEID, encodedHash) - return authorization - - def sendMessagesToSentinel(self,etdMessages): - """ - Function to batch messages received from ETD api - :param etdMessages: Messages retrived from ETD api - """ - messages = etdMessages.get("data").get("messages") - for i in range(0, len(messages), CHUNKSIZE): - batchedMessages = messages[i:i+CHUNKSIZE] - self.postMessages(batchedMessages) - - def postMessages(self, body): - """ - Function to post messages to log analytics - :param body: payload body for post call - """ - method = 'POST' - contentType = 'application/json' - resource = '/api/logs' - rfc1123date = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT') - contentLength = len(json.dumps(body)) - signature = self.buildSignature(rfc1123date, contentLength , method, contentType, resource) - uri = "https://" + WORKSPACEID + ".ods.opinsights.azure.com" + resource + "?api-version=2016-04-01" - headers = { - 'content-type': contentType, - 'Authorization': signature, - 'Log-Type': TABLENAME, - 'x-ms-date': rfc1123date - } - try: - response = retryRequest(uri, headers, body) - except Exception as err: - logging.error("Error during sending logs to Azure Sentinel: {}".format(err)) - else: - if response: - if response.status_code == HTTPStatus.OK: - logging.info("Messages have been successfully sent to Azure Sentinel.") - else: - logging.error("Error during sending messages to Azure Sentinel. Response code: {}".format(response.status_code)) - else: - logging.error("Failed to post data to Azure Sentinel") - -def setAndValidateEnvConfigurations(): - """ - Function to validate the environment variables set - :return: True is all configurations are set, else False - """ - missingConfigurations = [] - invalidVerdicts = [] - verdicts = ['spam', 'malicious', 'phishing', 'graymail', 'neutral', 'bec', 'scam', 'noVerdict'] - defaultValues = {"Region": "us", "Verdicts":"malicious"} - requiredConfigurations = ['ApiKey', 'ClientId', 'ClientSecret', 'WorkspaceID', 'SharedKey', 'Region', 'Verdicts' ] - for config in requiredConfigurations: - if os.environ.get(config) is None or len(os.environ.get(config)) == 0: - if config not in defaultValues: - missingConfigurations.append(config) - else: - logging.error(f"Configuration is not set for {config}, using default value {defaultValues[config]}" ) - if os.environ.get(config) and config == "Verdicts": - verdictList = os.environ.get(config).split(",") - verdictList = [v.strip() for v in verdictList] - for verdict in verdictList: - if verdict not in verdicts: - invalidVerdicts.append(verdict) - if invalidVerdicts: - strOfVerdicts = ','.join([str(elem) for elem in invalidVerdicts]) - logging.error(f"Encountered invalid verdict, {strOfVerdicts}") - if missingConfigurations: - strOfConfig = ','.join([str(ele) for ele in missingConfigurations]) - logging.error(f"Please set the required configurations as environment variables {strOfConfig}") - return False - return True - -def ciscoEtdConnector(last_timestamp_utc, next_timestamp_utc): - """ - Entry point of the code, responsible for fetching ETD messages and post it to Microsoft Sentinel - """ - # Check if env variables are configured - if not setAndValidateEnvConfigurations(): - return - # Create Sentinel class object - sentinelObj = Sentinel() - # Create ETD class object - etdObj = ETD(APIKEY, CLIENTID, CLIENTSECRET, VERDICTS, REGION, last_timestamp_utc, next_timestamp_utc) - nextPageToken = None - #Generate Token for ETD api - if not etdObj.generateToken(): - logging.error("Error in generating token for etd message search") - return - while True: - # Fetch messages from ETD - etdMessages = etdObj.fetchMessage(nextPageToken) - # Check for pageToken in retrieved messages - nextPageToken = etdMessages.get("nextPageToken") - if not etdMessages.get("data") or not nextPageToken: - break - # Posting ETD messages to Sentinel - sentinelObj.sendMessagesToSentinel(etdMessages) - -def main(mytimer: func.TimerRequest) -> None: - utc_timestamp = datetime.datetime.utcnow().replace( - tzinfo=datetime.timezone.utc).isoformat() - - # get last and next execution time - last_timestamp_utc = mytimer.schedule_status[LAST].replace("+00:00", UTCZONE) - next_timestamp_utc = mytimer.schedule_status[NEXT].replace("+00:00", UTCZONE) - - if mytimer.past_due: - logging.info('The timer is past due!') - - logging.info('Python timer trigger function ran at %s', utc_timestamp) - ciscoEtdConnector(last_timestamp_utc, next_timestamp_utc) diff --git a/Solutions/Cisco ETD/Data Connectors/CiscoETDAzureSentinelConnector/function.json b/Solutions/Cisco ETD/Data Connectors/CiscoETDAzureSentinelConnector/function.json deleted file mode 100644 index 6cac0b43ff9..00000000000 --- a/Solutions/Cisco ETD/Data Connectors/CiscoETDAzureSentinelConnector/function.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "scriptFile": "__init__.py", - "bindings": [ - { - "name": "mytimer", - "type": "timerTrigger", - "direction": "in", - "schedule": "0 */5 * * * *" - } - ] -} \ No newline at end of file diff --git a/Solutions/Cisco ETD/Data Connectors/CiscoETDAzureSentinelConnector/host.json b/Solutions/Cisco ETD/Data Connectors/CiscoETDAzureSentinelConnector/host.json deleted file mode 100644 index fd4bee790b9..00000000000 --- a/Solutions/Cisco ETD/Data Connectors/CiscoETDAzureSentinelConnector/host.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "version": "2.0", - "logging": { - "applicationInsights": { - "samplingSettings": { - "isEnabled": true, - "excludedTypes": "Request" - } - } - }, - "extensionBundle": { - "id": "Microsoft.Azure.Functions.ExtensionBundle", - "version": "[3.*, 4.0.0)" - } -} \ No newline at end of file diff --git a/Solutions/Cisco ETD/Data Connectors/CiscoETD_API_FunctionApp.json b/Solutions/Cisco ETD/Data Connectors/CiscoETD_API_FunctionApp.json deleted file mode 100644 index 38934bbdb16..00000000000 --- a/Solutions/Cisco ETD/Data Connectors/CiscoETD_API_FunctionApp.json +++ /dev/null @@ -1,123 +0,0 @@ -{ - "id": "CiscoETD", - "title": "Cisco ETD", - "publisher": "Cisco", - "descriptionMarkdown": "The connector fetches data from ETD api for threat analysis", - "graphQueries": [ - { - "metricName": "Total data received", - "legend": "CiscoETD_CL", - "baseQuery": "CiscoETD_CL" - } - ], - "sampleQueries": [ - { - "description" : "Incidents aggregated over a period on verdict type", - "query": "CiscoETD_CL | summarize ThreatCount = count() by verdict_category_s, TimeBin = bin(TimeGenerated, 1h) | project TimeBin, verdict_category_s, ThreatCount | render columnchart" - } - ], - "dataTypes": [ - { - "name": "CiscoETD_CL", - "lastDataReceivedQuery": "CiscoETD_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" - } - ], - "connectivityCriterias": [ - { - "type": "IsConnectedQuery", - "value": [ - "CiscoETD_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(30d)" - ] - } - ], - "availability": { - "status": 1, - "isPreview": true - }, - "permissions": { - "resourceProvider": [ - { - "provider": "Microsoft.OperationalInsights/workspaces", - "permissionsDisplayText": "read and write permissions on the workspace are required.", - "providerDisplayName": "Workspace", - "scope": "Workspace", - "requiredPermissions": { - "write": true, - "read": true, - "delete": true - } - }, - { - "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": "Microsoft.Web/sites permissions", - "description": "Read and write permissions to Azure Functions to create a Function App is required. [See the documentation to learn more about Azure Functions](https://docs.microsoft.com/azure/azure-functions/)." - }, - { - "name": "Email Threat Defense API, API key, Client ID and Secret", - "description": "Ensure you have the API key, Client ID and Secret key." - } - ] - }, - "instructionSteps": [ - { - "title": "", - "description": ">**NOTE:** This connector uses Azure Functions to connect to the ETD API to pull its logs into Microsoft Sentinel." - }, - { - "title": "", - "description": "**Follow the deployment steps to deploy the connector and the associated Azure Function**\n\n>**IMPORTANT:** Before deploying the ETD data connector, have the Workspace ID and Workspace Primary Key (can be copied from the following).\n", - "instructions": [ - { - "parameters": { - "fillWith": [ - "WorkspaceId" - ], - "label": "Workspace ID" - }, - "type": "CopyableLabel" - }, - { - "parameters": { - "fillWith": [ - "PrimaryKey" - ], - "label": "Primary Key" - }, - "type": "CopyableLabel" - } - ] - }, - { - "title": "Azure Resource Manager (ARM) Template", - "description": "Use this method for automated deployment of the Cisco ETD data connector using an ARM Template.\n\n1. Click the **Deploy to Azure** button below. \n\n\t[![Deploy To Azure](https://aka.ms/deploytoazurebutton)](https://aka.ms/sentinel-CiscoETD-azuredeploy)\n2. Select the preferred **Subscription**, **Resource Group** and **Region**. \n3. Enter the **WorkspaceID**, **SharedKey**, **ClientID**, **ClientSecret**, **ApiKey**, **Verdicts**, **ETD Region**\n4. Click **Create** to deploy." - } - ], - "metadata": { - "id": "CiscoETD_connector", - "version": "1.0.0", - "kind": "dataConnector", - "source": { - "kind": "ETD API", - "name": "ETD API" - }, - "author": { - "name": "Cisco" - }, - "support": { - "tier": "Developer Support", - "name": "Cisco" - - } - } -} diff --git a/Solutions/Cisco ETD/Data Connectors/CiscoETD_ccp/CiscoETD_DCR.json b/Solutions/Cisco ETD/Data Connectors/CiscoETD_ccp/CiscoETD_DCR.json new file mode 100644 index 00000000000..623ff4f8cad --- /dev/null +++ b/Solutions/Cisco ETD/Data Connectors/CiscoETD_ccp/CiscoETD_DCR.json @@ -0,0 +1,45 @@ +[ + { + "name": "CiscoETDDCR", + "apiVersion": "2021-09-01-preview", + "type": "Microsoft.Insights/dataCollectionRules", + "location": "{{location}}", + "properties": { + "dataCollectionEndpointId": "{{dataCollectionEndpointId}}", + "streamDeclarations": { + "Custom-CiscoETD_CL": { + "columns": [ + { + "name": "downloadLink", + "type": "string" + }, + { + "name": "message", + "type": "dynamic" + } + ] + } + }, + "destinations": { + "logAnalytics": [ + { + "workspaceResourceId": "{{workspaceResourceId}}", + "name": "clv2ws1" + } + ] + }, + "dataFlows": [ + { + "streams": [ + "Custom-CiscoETD_CL" + ], + "destinations": [ + "clv2ws1" + ], + "transformKql": "source | extend TimeGenerated = now() | project TimeGenerated, message", + "outputStream": "Custom-CiscoETD_CL" + } + ] + } + } +] diff --git a/Solutions/Cisco ETD/Data Connectors/CiscoETD_ccp/CiscoETD_PollerConfig.json b/Solutions/Cisco ETD/Data Connectors/CiscoETD_ccp/CiscoETD_PollerConfig.json new file mode 100644 index 00000000000..71de6a4f5a2 --- /dev/null +++ b/Solutions/Cisco ETD/Data Connectors/CiscoETD_ccp/CiscoETD_PollerConfig.json @@ -0,0 +1,94 @@ +[ + { + "name": "CiscoETDMessages", + "apiVersion": "2025-09-01", + "type": "Microsoft.SecurityInsights/dataConnectors", + "location": "{{location}}", + "kind": "RestApiPoller", + "properties": { + "connectorDefinitionName": "CiscoETDConnectorDefinition", + "dcrConfig": { + "dataCollectionEndpoint": "{{dataCollectionEndpoint}}", + "dataCollectionRuleImmutableId": "{{dataCollectionRuleImmutableId}}", + "streamName": "Custom-CiscoETD_CL" + }, + "dataType": "CiscoETD_CL", + "auth": { + "type": "JwtToken", + "userName": { + "key": "clientId", + "value": "{{clientId}}" + }, + "password": { + "key": "clientSecret", + "value": "{{clientSecret}}" + }, + "TokenEndpoint": "{{baseEndpoint}}/v1/oauth/token", + "TokenEndpointHttpMethod": "POST", + "Headers": { + "Accept": "application/json", + "Content-Type": "application/json", + "x-api-key": "[[parameters('apiKey')]" + }, + "IsCredentialsInHeaders": true, + "JwtTokenJsonPath": "$.accessToken" + }, + "request": { + "apiEndpoint": "{{baseEndpoint}}/v1/logs/downloadLinks", + "rateLimitQPS": 10, + "queryWindowInMin": 60, + "queryTimeFormat": "yyyy-MM-ddTHH", + "httpMethod": "POST", + "retryCount": 3, + "timeoutInSeconds": 30, + "isPostPayloadJson": true, + "queryParametersTemplate": "{\"timeRange\": [\"{_QueryWindowStartTime}\", \"{_QueryWindowEndTime}\"], \"logTypes\": [\"message\"]}", + "headers": { + "Accept": "application/json", + "Content-Type": "application/json", + "User-Agent": "Scuba", + "x-api-key": "{{apiKey}}" + } + }, + "response": { + "eventsJsonPaths": [ + "$.data.message" + ], + "format": "json" + }, + "shouldJoinNestedData": true, + "joinedDataStepName": "downloadLink", + "stepInfo": { + "stepType": "Nested", + "nextSteps": [ + { + "stepId": "fetchMessageData", + "stepPlaceholdersParsingKql": "source | project res = parse_json(data) | project downloadUrl = res.value" + } + ] + }, + "stepCollectorConfigs": { + "fetchMessageData": { + "shouldJoinNestedData": true, + "joinedDataStepName": "message", + "auth": { + "AuthType": "None" + }, + "request": { + "httpMethod": "GET", + "apiEndpoint": "$downloadUrl$", + "headers": { + "Accept": "application/x-ndjson" + } + }, + "response": { + "eventsJsonPaths": [ + "$" + ], + "format": "json-line" + } + } + } + } + } +] diff --git a/Solutions/Cisco ETD/Data Connectors/CiscoETD_ccp/CiscoETD_Table.json b/Solutions/Cisco ETD/Data Connectors/CiscoETD_ccp/CiscoETD_Table.json new file mode 100644 index 00000000000..305d83e8cde --- /dev/null +++ b/Solutions/Cisco ETD/Data Connectors/CiscoETD_ccp/CiscoETD_Table.json @@ -0,0 +1,30 @@ +[ + { + "name": "CiscoETD_CL", + "type": "Microsoft.OperationalInsights/workspaces/tables", + "apiVersion": "2021-03-01-privatepreview", + "properties": { + "schema": { + "name": "CiscoETD_CL", + "columns": [ + { + "name": "TimeGenerated", + "type": "Datetime", + "isDefaultDisplay": true, + "description": "The timestamp (UTC) reflecting the time in which the event was generated." + }, + { + "name": "downloadLink", + "type": "string", + "description": "The URL from which message data was downloaded" + }, + { + "name": "message", + "type": "dynamic", + "description": "The JSONL message data from the download" + } + ] + } + } + } +] diff --git a/Solutions/Cisco ETD/Data Connectors/CiscoETD_ccp/CiscoETD_connectorDefinition.json b/Solutions/Cisco ETD/Data Connectors/CiscoETD_ccp/CiscoETD_connectorDefinition.json new file mode 100644 index 00000000000..97f917bd35c --- /dev/null +++ b/Solutions/Cisco ETD/Data Connectors/CiscoETD_ccp/CiscoETD_connectorDefinition.json @@ -0,0 +1,142 @@ +{ + "type": "Microsoft.SecurityInsights/dataConnectorDefinitions", + "apiVersion": "2022-09-01-preview", + "name": "CiscoETDConnectorDefinition", + "location": "{{location}}", + "kind": "Customizable", + "properties": { + "connectorUiConfig": { + "id": "CiscoETDConnectorDefinition", + "title": "Cisco Email Threat Defense (ETD)", + "publisher": "Cisco", + "descriptionMarkdown": "The [Cisco Email Threat Defense (ETD)](https://docs.cmd.cisco.com/en/Content/secure-email-threat-defense-user-guide/homeUG.htm) data connector provides the capability to ingest [message events](https://docs.cmd.cisco.com/en/Content/secure-email-threat-defense-user-guide/Messages/messages.htm) from Cisco ETD into Microsoft Sentinel using the [Log Export API](https://developer.cisco.com/docs/message-search-api/log-export-api/).", + "graphQueriesTableName": "CiscoETD_CL", + "graphQueries": [ + { + "metricName": "Total messages received", + "legend": "Cisco ETD Messages", + "baseQuery": "CiscoETD_CL" + }, + { + "metricName": "Malicious messages", + "legend": "Malicious Threats", + "baseQuery": "CiscoETD_CL | where message_verdict_verdict == 'malicious'" + }, + { + "metricName": "Phishing messages", + "legend": "Phishing Threats", + "baseQuery": "CiscoETD_CL | where message_verdict_verdict == 'phishing'" + } + ], + "sampleQueries": [ + { + "description": "Get all Cisco ETD threat messages", + "query": "CiscoETD_CL\n| sort by TimeGenerated desc" + }, + { + "description": "Get recent malicious messages", + "query": "CiscoETD_CL\n| where message_verdict_verdict == 'malicious'\n| take 10" + } + ], + "dataTypes": [ + { + "name": "CiscoETD_CL", + "lastDataReceivedQuery": "CiscoETD_CL\n| summarize Time = max(TimeGenerated)\n| where isnotempty(Time)" + } + ], + "connectivityCriteria": [ + { + "type": "HasDataConnectors", + "value": [] + } + ], + "availability": { + "isPreview": false + }, + "permissions": { + "resourceProvider": [ + { + "provider": "Microsoft.OperationalInsights/workspaces", + "permissionsDisplayText": "Read and Write permissions are required.", + "providerDisplayName": "Workspace", + "scope": "Workspace", + "requiredPermissions": { + "write": true, + "read": true, + "delete": true + } + } + ], + "customs": [ + { + "name": "Cisco ETD API Credentials", + "description": "Cisco ETD API credentials are required. Refer to the [Cisco ETD API Authentication documentation](https://developer.cisco.com/docs/message-search-api/authentication/) for more information." + } + ] + }, + "instructionSteps": [ + { + "title": "Connect to Cisco ETD API", + "description": "Provide your Cisco ETD API endpoint, Client ID, Client Secret, and API Key. These credentials can be obtained from your Cisco ETD administrator or through the Cisco ETD management console.", + "instructions": [ + { + "type": "Textbox", + "parameters": { + "label": "Base Endpoint URL", + "placeholder": "https://api.us.etd.cisco.com", + "type": "text", + "name": "baseEndpoint", + "validations": { + "required": true + } + } + }, + { + "type": "Textbox", + "parameters": { + "label": "Client ID", + "placeholder": "Enter OAuth2 Client ID", + "type": "text", + "name": "clientId", + "validations": { + "required": true + } + } + }, + { + "type": "Textbox", + "parameters": { + "label": "Client Secret", + "placeholder": "Enter OAuth2 Client Secret", + "type": "password", + "name": "clientSecret", + "validations": { + "required": true + } + } + }, + { + "type": "Textbox", + "parameters": { + "label": "API Key", + "placeholder": "Enter Cisco ETD API Key", + "type": "password", + "name": "apiKey", + "validations": { + "required": true + } + } + }, + { + "parameters": { + "label": "Connect", + "name": "toggle" + }, + "type": "ConnectionToggleButton" + } + ] + } + ] + } + } +} diff --git a/Solutions/Cisco ETD/Data Connectors/azuredeploy_CiscoETD_API_FunctionApp.json b/Solutions/Cisco ETD/Data Connectors/azuredeploy_CiscoETD_API_FunctionApp.json deleted file mode 100644 index b234349e8d1..00000000000 --- a/Solutions/Cisco ETD/Data Connectors/azuredeploy_CiscoETD_API_FunctionApp.json +++ /dev/null @@ -1,326 +0,0 @@ -{ - "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "FunctionName": { - "defaultValue": "CiscoETD", - "minLength": 1, - "type": "string" - }, - "WorkspaceName": { - "type": "string", - "defaultValue": "", - "minLength": 1, - "metadata": { - "description": "Log analytics workspace name" - } - }, - "WorkspaceID": { - "type": "string", - "defaultValue": "", - "minLength": 1 - }, - "SharedKey": { - "type": "securestring", - "defaultValue": "", - "minLength": 1 - }, - "ApiKey": { - "type": "securestring", - "defaultValue": "", - "minLength": 1 - }, - "ClientId": { - "type": "securestring", - "defaultValue": "" - }, - "ClientSecret": { - "type": "securestring", - "defaultValue": "" - }, - "Region": { - "type": "string", - "allowedValues": ["Australia", "Beta", "Europe", "India", "United States (US)"], - "metadata": { - "description": "Select the ETD region", - "displayName": "Region" - } - }, - "Verdicts": { - "type": "string", - "metadata": { - "description": "Supported verdicts are: bec, graymail, malicious, neutral, phishing, scam, spam", - "displayName": "Verdicts" - } - }, - "workbookId": { - "type": "string", - "defaultValue": "[newGuid()]", - "metadata": { - "description": "The unique guid for this workbook instance, do not edit the field" - } - } - }, - "variables": { - "suffix": "[substring(toLower(uniqueString(resourceGroup().id, concat('[resourceGroup().locatio', 'n]'))),0,5)]", - "FunctionName": "[toLower(parameters('FunctionName'))]", - "StorageName": "[concat(variables('FunctionName'), variables('suffix'))]", - "ETDregion": { - "Beta": "beta", - "Australia": "au", - "Europe": "de", - "India": "in", - "United States (US)": "us" - }, - "workbookDisplayName": "[concat('EmailThreatDefenseDashboard','-',variables('FunctionName'),'-',variables('suffix'))]", - "workbookType": "sentinel", - "workbookSourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('WorkspaceName'))]" - }, - "resources": [ - { - "type": "Microsoft.Insights/components", - "apiVersion": "2015-05-01", - "name": "[variables('FunctionName')]", - "location": "[resourceGroup().location]", - "kind": "web", - "properties": { - "Application_Type": "web", - "ApplicationId": "[variables('FunctionName')]" - } - }, - { - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2019-06-01", - "name": "[variables('StorageName')]", - "location": "[resourceGroup().location]", - "sku": { - "name": "Standard_LRS", - "tier": "Standard" - }, - "kind": "StorageV2", - "properties": { - "networkAcls": { - "bypass": "AzureServices", - "virtualNetworkRules": [], - "ipRules": [], - "defaultAction": "Allow" - }, - "supportsHttpsTrafficOnly": true, - "encryption": { - "services": { - "blob": { - "keyType": "Account", - "enabled": true - } - }, - "keySource": "Microsoft.Storage" - } - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2015-11-01-preview", - "name": "[parameters('WorkspaceName')]", - "location": "[resourceGroup().location]" - }, - { - "type": "Microsoft.OperationalInsights/workspaces/savedSearches", - "apiVersion": "2015-11-01-preview", - "name": "[format('{0}/{1}', parameters('WorkspaceName'), 'ETD Mailboxes query')]", - "properties": { - "etag": "*", - "displayName": "Top 10 mailboxes", - "category": "ETD", - "query": "CiscoETD_CL | project Mailbox = parse_json(tostring(mailboxes_s)) | mv-expand Mailbox | summarize ThreatCount = count() by tostring(Mailbox) | top 10 by ThreatCount desc | project Mailbox, ThreatCount | render columnchart", - "version": 1 - }, - "dependsOn": [ - "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('WorkspaceName'))]" - ] - }, - { - "type": "Microsoft.OperationalInsights/workspaces/savedSearches", - "apiVersion": "2015-11-01-preview", - "name": "[format('{0}/{1}', parameters('WorkspaceName'), 'ETD Verdicts query')]", - "properties": { - "etag": "*", - "displayName": "Distribution of Verdict type", - "category": "ETD", - "query": "CiscoETD_CL | summarize TotalMessages = count() by verdict_category_s | extend Categories = coalesce(verdict_category_s, 'No Verdict') | project Verdicts = Categories, TotalMessages | render piechart title = 'Email Threat Defense Messages by Verdict'", - "version": 1 - }, - "dependsOn": [ - "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('WorkspaceName'))]" - ] - }, - { - "type": "Microsoft.OperationalInsights/workspaces/savedSearches", - "apiVersion": "2015-11-01-preview", - "name": "[format('{0}/{1}', parameters('WorkspaceName'), 'ETD Incidents query')]", - "properties": { - "etag": "*", - "displayName": "Incidents aggregated over a period based on verdicts ", - "category": "ETD", - "query": "CiscoETD_CL | summarize ThreatCount = count() by verdict_category_s, TimeBin = bin(TimeGenerated, 1h) | project TimeBin, verdict_category_s, ThreatCount | render columnchart", - "version": 1 - }, - "dependsOn": [ - "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('WorkspaceName'))]" - ] - }, - { - "type": "Microsoft.OperationalInsights/workspaces/savedSearches", - "apiVersion": "2015-11-01-preview", - "name": "[format('{0}/{1}', parameters('WorkspaceName'), 'ETD Malicious URL query')]", - "properties": { - "etag": "*", - "displayName": "Malicious URLs", - "category": "ETD", - "query": "CiscoETD_CL | where parse_json(verdict_techniques_s)[6].type == 'Malicious URL'", - "version": 1 - }, - "dependsOn": [ - "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('WorkspaceName'))]" - ] - }, - { - "type": "Microsoft.OperationalInsights/workspaces/savedSearches", - "apiVersion": "2015-11-01-preview", - "name": "[format('{0}/{1}', parameters('WorkspaceName'), 'ETD QR Codes query')]", - "properties": { - "etag": "*", - "displayName": "QR Codes", - "category": "ETD", - "query": "CiscoETD_CL | where parse_json(verdict_techniques_s)[6].type == 'QR code'", - "version": 1 - }, - "dependsOn": [ - "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('WorkspaceName'))]" - ] - }, - { - "type": "Microsoft.OperationalInsights/workspaces/savedSearches", - "apiVersion": "2015-11-01-preview", - "name": "[format('{0}/{1}', parameters('WorkspaceName'), 'ETD Malicious Sender Domains query')]", - "properties": { - "etag": "*", - "displayName": "Top 10 Malicious Sender Domains", - "category": "ETD", - "query": "CiscoETD_CL | extend Domain = tostring(split(fromAddress_s, '@')[1]) | where isnotnull(Domain) and trim(' ', Domain) != '' | summarize Count = count() by Domain | top 10 by Count desc", - "version": 1 - }, - "dependsOn": [ - "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('WorkspaceName'))]" - ] - }, - { - "type": "Microsoft.OperationalInsights/workspaces/savedSearches", - "apiVersion": "2015-11-01-preview", - "name": "[format('{0}/{1}', parameters('WorkspaceName'), 'ETD Malicious Senders query')]", - "properties": { - "etag": "*", - "displayName": "Top 10 Malicious Senders", - "category": "ETD", - "query": "CiscoETD_CL | extend Email = fromAddress_s | where isnotnull(Email) and trim(' ', Email) != '' | summarize Count = count() by Email | top 10 by Count desc", - "version": 1 - }, - "dependsOn": [ - "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('WorkspaceName'))]" - ] - }, - { - "type": "Microsoft.OperationalInsights/workspaces/savedSearches", - "apiVersion": "2015-11-01-preview", - "name": "[format('{0}/{1}', parameters('WorkspaceName'), 'ETD Targeted users query')]", - "properties": { - "etag": "*", - "displayName": "Top 10 Targeted users", - "category": "ETD", - "query": "CiscoETD_CL | project Mailbox = parse_json(tostring(mailboxes_s)) | mv-expand Mailbox | summarize Count = count() by tostring(Mailbox) | top 10 by Count desc | project Mailbox", - "version": 1 - }, - "dependsOn": [ - "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('WorkspaceName'))]" - ] - }, - { - "type": "Microsoft.OperationalInsights/workspaces/savedSearches", - "apiVersion": "2015-11-01-preview", - "name": "[format('{0}/{1}', parameters('WorkspaceName'), 'ETD User Impersonation query')]", - "properties": { - "etag": "*", - "displayName": "User Impersonation", - "category": "ETD", - "query": "CiscoETD_CL | where parse_json(verdict_techniques_s)[6].type == 'User Impersonation'", - "version": 1 - }, - "dependsOn": [ - "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('WorkspaceName'))]" - ] - }, - { - "name": "[parameters('workbookId')]", - "type": "microsoft.insights/workbooks", - "location": "[resourceGroup().location]", - "apiVersion": "2022-04-01", - "dependsOn": [], - "kind": "shared", - "properties": { - "displayName": "[variables('workbookDisplayName')]", - "serializedData": "{\"version\":\"Notebook/1.0\",\"items\":[{\"type\":12,\"content\":{\"version\":\"NotebookGroup/1.0\",\"groupType\":\"editable\",\"items\":[{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"CiscoETD_CL | summarize TotalMessages = count() by verdict_category_s | extend Categories = coalesce(verdict_category_s, 'No Verdict') | project Verdicts = Categories, TotalMessages | render piechart title = 'Email Threat Defense Messages by Verdict'\",\"size\":0,\"title\":\"Total Messages by Threat Type\",\"timeContext\":{\"durationMs\":86400000},\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"customWidth\":\"50\",\"name\":\"query - 0\",\"styleSettings\":{\"margin\":\"10px\"}},{\"type\":12,\"content\":{\"version\":\"NotebookGroup/1.0\",\"groupType\":\"editable\",\"title\":\"Top 10 Malicious Senders Domains\",\"items\":[{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"CiscoETD_CL\\n| extend Domain = tostring(split(fromAddress_s, '@')[1])\\n| where isnotnull(Domain) and trim(' ', Domain) != ''\\n| summarize Count = count() by Domain\\n| top 10 by Count desc\\n\",\"size\":0,\"timeContext\":{\"durationMs\":86400000},\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"categoricalbar\",\"graphSettings\":{\"type\":0,\"topContent\":{\"columnMatch\":\"Domain\",\"formatter\":1},\"centerContent\":{\"columnMatch\":\"Count\",\"formatter\":1,\"numberFormat\":{\"unit\":17,\"options\":{\"maximumSignificantDigits\":3,\"maximumFractionDigits\":2}}}}},\"name\":\"query - 0\"}]},\"customWidth\":\"50\",\"name\":\"group - 9\",\"styleSettings\":{\"margin\":\"10px\"}}]},\"customWidth\":\"100\",\"name\":\"group - 6\",\"styleSettings\":{\"margin\":\"10px\",\"showBorder\":true}},{\"type\":12,\"content\":{\"version\":\"NotebookGroup/1.0\",\"groupType\":\"editable\",\"items\":[{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"CiscoETD_CL\\n| extend Email = fromAddress_s\\n| where isnotnull(Email) and trim(' ', Email) != ''\\n| summarize Count = count() by Email\\n| top 10 by Count desc\",\"size\":0,\"title\":\"Top 10 Malicious Senders\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"gridSettings\":{\"sortBy\":[{\"itemKey\":\"Count\",\"sortOrder\":2}]},\"sortBy\":[{\"itemKey\":\"Count\",\"sortOrder\":2}]},\"customWidth\":\"50\",\"name\":\"query - 2\",\"styleSettings\":{\"margin\":\"10px\"}},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"CiscoETD_CL\\n| summarize Count = count() by mailboxes_s\\n| top 10 by Count desc\\n| extend Email = tostring(replace(\\\"[\\\\\\\"\\\\\\\"\\\\\\\\[\\\\\\\\]]\\\", \\\"\\\", mailboxes_s))\\n| project Email, Count\",\"size\":0,\"title\":\"Top 10 Targetd users\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"customWidth\":\"50\",\"name\":\"query - 3\",\"styleSettings\":{\"margin\":\"10px\"}}]},\"name\":\"Group_Top 10\"}],\"isLocked\":false,\"fallbackResourceIds\":[\"[variables('workbookSourceId')]\"],\"fromTemplateId\":\"sentinel-UserWorkbook\"}", - "version": "1.0", - "sourceId": "[variables('workbookSourceId')]", - "category": "[variables('workbookType')]" - } - }, - { - "type": "Microsoft.Web/sites", - "apiVersion": "2018-11-01", - "name": "[variables('FunctionName')]", - "location": "[resourceGroup().location]", - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts', variables('StorageName'))]", - "[resourceId('Microsoft.Insights/components', variables('FunctionName'))]" - ], - "kind": "functionapp,linux", - "identity": { - "type": "SystemAssigned" - }, - "properties": { - "name": "[variables('FunctionName')]", - "httpsOnly": true, - "clientAffinityEnabled": true, - "alwaysOn": true, - "reserved": true, - "siteConfig": { - "linuxFxVersion": "python|3.11" - } - }, - "resources": [ - { - "apiVersion": "2018-11-01", - "type": "config", - "name": "appsettings", - "dependsOn": [ - "[concat('Microsoft.Web/sites/', variables('FunctionName'))]" - ], - "properties": { - "FUNCTIONS_EXTENSION_VERSION": "~4", - "FUNCTIONS_WORKER_RUNTIME": "python", - "APPINSIGHTS_INSTRUMENTATIONKEY": "[reference(resourceId('Microsoft.insights/components', variables('FunctionName')), '2015-05-01').InstrumentationKey]", - "APPLICATIONINSIGHTS_CONNECTION_STRING": "[reference(resourceId('microsoft.insights/components', variables('FunctionName')), '2015-05-01').ConnectionString]", - "AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('StorageName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('StorageName')), '2015-05-01-preview').key1)]", - "WorkspaceID": "[parameters('WorkspaceID')]", - "SharedKey": "[parameters('SharedKey')]", - "ApiKey": "[parameters('ApiKey')]", - "ClientId": "[parameters('ClientId')]", - "ClientSecret": "[parameters('ClientSecret')]", - "Region": "[variables('ETDregion')[parameters('Region')]]", - "Verdicts": "[parameters('Verdicts')]", - "WEBSITE_RUN_FROM_PACKAGE": "https://aka.ms/sentinel-CiscoETD-functionapp" - } - } - ] - } - ] -} diff --git a/Solutions/Cisco ETD/Data Connectors/requirements.txt b/Solutions/Cisco ETD/Data Connectors/requirements.txt deleted file mode 100644 index 7bc0ff44dd6..00000000000 --- a/Solutions/Cisco ETD/Data Connectors/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -# DO NOT include azure-functions-worker in this file -# The Python Worker is managed by Azure Functions platform -# Manually managing azure-functions-worker may cause unexpected issues - -azure-functions -requests \ No newline at end of file diff --git a/Solutions/Cisco ETD/Data/Solution_CiscoETD.json b/Solutions/Cisco ETD/Data/Solution_CiscoETD.json index f9c6785ecce..222b298d047 100644 --- a/Solutions/Cisco ETD/Data/Solution_CiscoETD.json +++ b/Solutions/Cisco ETD/Data/Solution_CiscoETD.json @@ -1,17 +1,23 @@ -{ - "Name": "Cisco ETD", - "Author": "Cisco", - "Logo": "", - "Description": "Cisco ETD Solution for Microsoft Microsoft Sentinel makes it easy to connect cisco email threat data to the Microsoft Sentinel, improving visibility into email threats.", - "Data Connectors": [ - "Data Connectors/CiscoETD_API_FunctionApp.json" - ], - "Workbooks": [ - "Workbooks/CiscoETD.json" - ], - "BasePath": "c:\\GitHub\\Azure-Sentinel\\Solutions\\Cisco ETD", - "Version": "3.0.0", - "Metadata": "SolutionMetadata.json", - "TemplateSpec": true, - "Is1Pconnector": false - } +{ + "Name": "CiscoETD", + "Author": "Cisco", + "Logo": "", + "Description": "The Cisco Email Threat Defense (ETD) solution for Microsoft Sentinel enables you to ingest message events and threat data from Cisco ETD into Microsoft Sentinel using the Log Export API with nested polling.", + "Workbooks": [ + "Workbooks/CiscoETDMessages.json" + ], + "Analytic Rules": [], + "Playbooks": [], + "Parsers": [], + "Hunting Queries": [], + "Data Connectors": [ + "Data Connectors/CiscoETD_ccp/CiscoETD_connectorDefinition.json" + ], + "Watchlists": [], + "dependentDomainSolutionIds": [], + "BasePath": "C:\\GitHub\\Azure-Sentinel\\Solutions\\CiscoETDv5", + "Version": "1.0.2", + "Metadata": "SolutionMetadata.json", + "TemplateSpec": true, + "StaticDataConnectorIds": [] +} diff --git a/Solutions/Cisco ETD/Package/3.0.0.zip b/Solutions/Cisco ETD/Package/3.0.0.zip index cc6e8a73253..402f54157d0 100644 Binary files a/Solutions/Cisco ETD/Package/3.0.0.zip and b/Solutions/Cisco ETD/Package/3.0.0.zip differ diff --git a/Solutions/Cisco ETD/Package/createUiDefinition.json b/Solutions/Cisco ETD/Package/createUiDefinition.json index e9d115096d6..8ab24be97fd 100644 --- a/Solutions/Cisco ETD/Package/createUiDefinition.json +++ b/Solutions/Cisco ETD/Package/createUiDefinition.json @@ -6,7 +6,7 @@ "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/Cisco%20ETD/ReleaseNotes.md)\n\n • There may be [known issues](https://aka.ms/sentinelsolutionsknownissues) pertaining to this Solution, please refer to them before installing.\n\nCisco ETD Solution for Microsoft Microsoft Sentinel makes it easy to connect cisco email threat data to the Microsoft Sentinel, improving visibility into email threats.\n\n**Data Connectors:** 1, **Workbooks:** 1\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)", + "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/CiscoETD/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 Cisco Email Threat Defense (ETD) solution for Microsoft Sentinel enables you to ingest message events and threat data from Cisco ETD into Microsoft Sentinel using the Log Export API with nested polling.\n\n**Data Connectors:** 1\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)", "subscription": { "resourceProviders": [ "Microsoft.OperationsManagement/solutions", @@ -60,11 +60,11 @@ "name": "dataconnectors1-text", "type": "Microsoft.Common.TextBlock", "options": { - "text": "This Solution installs the data connector for Cisco ETD. You can get Cisco ETD custom log data in your Microsoft Sentinel workspace. After installing the solution, configure and enable this data connector by following guidance in Manage solution view." + "text": "This Solution installs the data connector for Cisco Email Threat Defense (ETD). You can get Cisco Email Threat Defense (ETD) 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-link2", + "name": "dataconnectors-link1", "type": "Microsoft.Common.TextBlock", "options": { "link": { @@ -100,20 +100,6 @@ "uri": "https://docs.microsoft.com/azure/sentinel/tutorial-monitor-your-data" } } - }, - { - "name": "workbook1", - "type": "Microsoft.Common.Section", - "label": "Cisco Email Threat Defense", - "elements": [ - { - "name": "workbook1-text", - "type": "Microsoft.Common.TextBlock", - "options": { - "text": "Analyze email threat data seamlessly with the workbook, correlating information from the Secure Email Threat Defense API to identify and mitigate suspicious activities, providing insights into trends and allowing for precise filtering and analysis" - } - } - ] } ] } diff --git a/Solutions/Cisco ETD/Package/mainTemplate.json b/Solutions/Cisco ETD/Package/mainTemplate.json index b87c081782d..e6be3e10305 100644 --- a/Solutions/Cisco ETD/Package/mainTemplate.json +++ b/Solutions/Cisco ETD/Package/mainTemplate.json @@ -3,7 +3,7 @@ "contentVersion": "1.0.0.0", "metadata": { "author": "Cisco", - "comments": "Solution template for Cisco ETD" + "comments": "Solution template for CiscoETD" }, "parameters": { "location": { @@ -28,103 +28,115 @@ "description": "Workspace name for Log Analytics where Microsoft Sentinel is setup" } }, - "workbook1-name": { + "resourceGroupName": { "type": "string", - "defaultValue": "Cisco Email Threat Defense", - "minLength": 1, + "defaultValue": "[resourceGroup().name]", "metadata": { - "description": "Name for the workbook" + "description": "resource group name where Microsoft Sentinel is setup" + } + }, + "subscription": { + "type": "string", + "defaultValue": "[last(split(subscription().id, '/'))]", + "metadata": { + "description": "subscription id where Microsoft Sentinel is setup" } } }, "variables": { - "_solutionName": "Cisco ETD", + "_solutionName": "CiscoETD", "_solutionVersion": "3.0.0", - "solutionId": "cisco.cisco-etd-sentinel", + "solutionId": "cisco.azure-sentinel-solution-cisco-etd", "_solutionId": "[variables('solutionId')]", - "uiConfigId1": "CiscoETD", - "_uiConfigId1": "[variables('uiConfigId1')]", - "dataConnectorContentId1": "CiscoETD", - "_dataConnectorContentId1": "[variables('dataConnectorContentId1')]", - "dataConnectorId1": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectors', variables('_dataConnectorContentId1'))]", - "_dataConnectorId1": "[variables('dataConnectorId1')]", - "dataConnectorTemplateSpecName1": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-dc-',uniquestring(variables('_dataConnectorContentId1'))))]", - "dataConnectorVersion1": "1.0.0", - "_dataConnectorcontentProductId1": "[concat(take(variables('_solutionId'),50),'-','dc','-', uniqueString(concat(variables('_solutionId'),'-','DataConnector','-',variables('_dataConnectorContentId1'),'-', variables('dataConnectorVersion1'))))]", - "workbookVersion1": "1.0", - "workbookContentId1": "CiscoETDWorkbook", - "workbookId1": "[resourceId('Microsoft.Insights/workbooks', variables('workbookContentId1'))]", - "workbookTemplateSpecName1": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-wb-',uniquestring(variables('_workbookContentId1'))))]", - "_workbookContentId1": "[variables('workbookContentId1')]", "workspaceResourceId": "[resourceId('microsoft.OperationalInsights/Workspaces', parameters('workspace'))]", - "_workbookcontentProductId1": "[concat(take(variables('_solutionId'),50),'-','wb','-', uniqueString(concat(variables('_solutionId'),'-','Workbook','-',variables('_workbookContentId1'),'-', variables('workbookVersion1'))))]", + "dataConnectorCCPVersion": "3.0.0", + "_dataConnectorContentIdConnectorDefinition1": "CiscoETDConnectorDefinition", + "dataConnectorTemplateNameConnectorDefinition1": "[concat(parameters('workspace'),'-dc-',uniquestring(variables('_dataConnectorContentIdConnectorDefinition1')))]", + "_dataConnectorContentIdConnections1": "CiscoETDConnectorDefinitionConnections", + "dataConnectorTemplateNameConnections1": "[concat(parameters('workspace'),'-dc-',uniquestring(variables('_dataConnectorContentIdConnections1')))]", + "dataCollectionEndpointId1": "[concat('/subscriptions/',parameters('subscription'),'/resourceGroups/',parameters('resourceGroupName'),'/providers/Microsoft.Insights/dataCollectionEndpoints/',parameters('workspace'))]", + "blanks": "[replace('b', 'b', '')]", "_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": "[variables('dataConnectorTemplateSpecName1')]", + "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": { - "description": "Cisco ETD data connector with template version 3.0.0", + "contentId": "[variables('_dataConnectorContentIdConnectorDefinition1')]", + "displayName": "Cisco Email Threat Defense (ETD)", + "contentKind": "DataConnector", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('dataConnectorVersion1')]", + "contentVersion": "[variables('dataConnectorCCPVersion')]", "parameters": {}, "variables": {}, "resources": [ { - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentId1'))]", - "apiVersion": "2021-03-01-preview", - "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentIdConnectorDefinition1'))]", + "apiVersion": "2022-09-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectorDefinitions", "location": "[parameters('workspace-location')]", - "kind": "GenericUI", + "kind": "Customizable", "properties": { "connectorUiConfig": { - "id": "[variables('_uiConfigId1')]", - "title": "Cisco ETD (using Azure Functions)", + "id": "CiscoETDConnectorDefinition", + "title": "Cisco Email Threat Defense (ETD)", "publisher": "Cisco", - "descriptionMarkdown": "The connector fetches data from ETD api for threat analysis", + "descriptionMarkdown": "The [Cisco Email Threat Defense (ETD)](https://docs.cmd.cisco.com/en/Content/secure-email-threat-defense-user-guide/homeUG.htm) data connector provides the capability to ingest [message events](https://docs.cmd.cisco.com/en/Content/secure-email-threat-defense-user-guide/Messages/messages.htm) from Cisco ETD into Microsoft Sentinel using the [Log Export API](https://developer.cisco.com/docs/message-search-api/log-export-api/).", + "graphQueriesTableName": "CiscoETD_CL", "graphQueries": [ { - "metricName": "Total data received", - "legend": "CiscoETD_CL", + "metricName": "Total messages received", + "legend": "Cisco ETD Messages", "baseQuery": "CiscoETD_CL" + }, + { + "metricName": "Malicious messages", + "legend": "Malicious Threats", + "baseQuery": "CiscoETD_CL | where message_verdict_verdict == 'malicious'" + }, + { + "metricName": "Phishing messages", + "legend": "Phishing Threats", + "baseQuery": "CiscoETD_CL | where message_verdict_verdict == 'phishing'" } ], "sampleQueries": [ { - "description": "Incidents aggregated over a period on verdict type", - "query": "CiscoETD_CL | summarize ThreatCount = count() by verdict_category_s, TimeBin = bin(TimeGenerated, 1h) | project TimeBin, verdict_category_s, ThreatCount | render columnchart" + "description": "Get all Cisco ETD threat messages", + "query": "CiscoETD_CL\n| sort by TimeGenerated desc" + }, + { + "description": "Get recent malicious messages", + "query": "CiscoETD_CL\n| where message_verdict_verdict == 'malicious'\n| take 10" } ], "dataTypes": [ { "name": "CiscoETD_CL", - "lastDataReceivedQuery": "CiscoETD_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + "lastDataReceivedQuery": "CiscoETD_CL\n| summarize Time = max(TimeGenerated)\n| where isnotempty(Time)" } ], - "connectivityCriterias": [ + "connectivityCriteria": [ { - "type": "IsConnectedQuery", - "value": [ - "CiscoETD_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(30d)" - ] + "type": "HasDataConnectors", + "value": [] } ], "availability": { - "status": 1, "isPreview": false }, "permissions": { "resourceProvider": [ { "provider": "Microsoft.OperationalInsights/workspaces", - "permissionsDisplayText": "read and write permissions on the workspace are required.", + "permissionsDisplayText": "Read and Write permissions are required.", "providerDisplayName": "Workspace", "scope": "Workspace", "requiredPermissions": { @@ -132,100 +144,186 @@ "read": true, "delete": true } - }, - { - "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": "Microsoft.Web/sites permissions", - "description": "Read and write permissions to Azure Functions to create a Function App is required. [See the documentation to learn more about Azure Functions](https://docs.microsoft.com/azure/azure-functions/)." - }, - { - "name": "Email Threat Defense API, API key, Client ID and Secret", - "description": "Ensure you have the API key, Client ID and Secret key." + "name": "Cisco ETD API Credentials", + "description": "Cisco ETD API credentials are required. Refer to the [Cisco ETD API Authentication documentation](https://developer.cisco.com/docs/message-search-api/authentication/) for more information." } ] }, "instructionSteps": [ { - "description": ">**NOTE:** This connector uses Azure Functions to connect to the ETD API to pull its logs into Microsoft Sentinel." - }, - { - "description": "**Follow the deployment steps to deploy the connector and the associated Azure Function**\n\n>**IMPORTANT:** Before deploying the ETD data connector, have the Workspace ID and Workspace Primary Key (can be copied from the following).\n", + "title": "Connect to Cisco ETD API", + "description": "Provide your Cisco ETD API endpoint, Client ID, Client Secret, and API Key. These credentials can be obtained from your Cisco ETD administrator or through the Cisco ETD management console.", "instructions": [ { + "type": "Textbox", "parameters": { - "fillWith": [ - "WorkspaceId" - ], - "label": "Workspace ID" - }, - "type": "CopyableLabel" + "label": "Base Endpoint URL", + "placeholder": "https://api.us.etd.cisco.com", + "type": "text", + "name": "baseEndpoint", + "validations": { + "required": true + } + } + }, + { + "type": "Textbox", + "parameters": { + "label": "Client ID", + "placeholder": "Enter OAuth2 Client ID", + "type": "text", + "name": "clientId", + "validations": { + "required": true + } + } }, { + "type": "Textbox", "parameters": { - "fillWith": [ - "PrimaryKey" - ], - "label": "Primary Key" + "label": "Client Secret", + "placeholder": "Enter OAuth2 Client Secret", + "type": "password", + "name": "clientSecret", + "validations": { + "required": true + } + } + }, + { + "type": "Textbox", + "parameters": { + "label": "API Key", + "placeholder": "Enter Cisco ETD API Key", + "type": "password", + "name": "apiKey", + "validations": { + "required": true + } + } + }, + { + "parameters": { + "label": "Connect", + "name": "toggle" }, - "type": "CopyableLabel" + "type": "ConnectionToggleButton" } ] - }, - { - "description": "Use this method for automated deployment of the Cisco ETD data connector using an ARM Template.\n\n1. Click the **Deploy to Azure** button below. \n\n\t[![Deploy To Azure](https://aka.ms/deploytoazurebutton)](https://aka.ms/sentinel-CiscoETD-azuredeploy)\n2. Select the preferred **Subscription**, **Resource Group** and **Region**. \n3. Enter the **WorkspaceID**, **SharedKey**, **ClientID**, **ClientSecret**, **ApiKey**, **Verdicts**, **ETD Region**\n4. Click **Create** to deploy.", - "title": "Azure Resource Manager (ARM) Template" } - ], - "metadata": { - "id": "CiscoETD_connector", - "version": "1.0.0", - "kind": "dataConnector", - "source": { - "kind": "ETD API", - "name": "ETD API" - }, - "author": { - "name": "Cisco" - }, - "support": { - "tier": "Developer Support", - "name": "Cisco" - } - } + ] } } }, { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnectorDefinition1')))]", + "apiVersion": "2022-01-01-preview", "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2023-04-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', last(split(variables('_dataConnectorId1'),'/'))))]", "properties": { - "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectors', variables('_dataConnectorContentId1'))]", - "contentId": "[variables('_dataConnectorContentId1')]", + "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectorDefinitions', variables('_dataConnectorContentIdConnectorDefinition1'))]", + "contentId": "[variables('_dataConnectorContentIdConnectorDefinition1')]", "kind": "DataConnector", - "version": "[variables('dataConnectorVersion1')]", + "version": "[variables('dataConnectorCCPVersion')]", "source": { - "kind": "Solution", - "name": "Cisco ETD", - "sourceId": "[variables('_solutionId')]" + "sourceId": "[variables('_solutionId')]", + "name": "[variables('_solutionName')]", + "kind": "Solution" }, "author": { "name": "Cisco" }, "support": { - "name": "Cisco Systems", + "name": "Cisco", + "email": "support@cisco.com", "tier": "Partner", - "email": "etd-sentinel@cisco.com" + "link": "https://www.cisco.com/c/en/us/support/index.html" + }, + "dependencies": { + "criteria": [ + { + "version": "[variables('dataConnectorCCPVersion')]", + "contentId": "[variables('_dataConnectorContentIdConnections1')]", + "kind": "ResourcesDataConnector" + } + ] + } + } + }, + { + "name": "CiscoETDDCR", + "apiVersion": "2022-06-01", + "type": "Microsoft.Insights/dataCollectionRules", + "location": "[parameters('workspace-location')]", + "kind": "[variables('blanks')]", + "properties": { + "dataCollectionEndpointId": "[variables('dataCollectionEndpointId1')]", + "streamDeclarations": { + "Custom-CiscoETD_CL": { + "columns": [ + { + "name": "downloadLink", + "type": "string" + }, + { + "name": "message", + "type": "dynamic" + } + ] + } + }, + "destinations": { + "logAnalytics": [ + { + "workspaceResourceId": "[variables('workspaceResourceId')]", + "name": "clv2ws1" + } + ] + }, + "dataFlows": [ + { + "streams": [ + "Custom-CiscoETD_CL" + ], + "destinations": [ + "clv2ws1" + ], + "transformKql": "source | extend TimeGenerated = now() | project TimeGenerated, message", + "outputStream": "Custom-CiscoETD_CL" + } + ] + } + }, + { + "name": "CiscoETD_CL", + "apiVersion": "2022-10-01", + "type": "Microsoft.OperationalInsights/workspaces/tables", + "location": "[parameters('workspace-location')]", + "kind": null, + "properties": { + "schema": { + "name": "CiscoETD_CL", + "columns": [ + { + "name": "TimeGenerated", + "type": "Datetime", + "isDefaultDisplay": true, + "description": "The timestamp (UTC) reflecting the time in which the event was generated." + }, + { + "name": "downloadLink", + "type": "string", + "description": "The URL from which message data was downloaded" + }, + { + "name": "message", + "type": "dynamic", + "description": "The JSONL message data from the download" + } + ] } } } @@ -234,91 +332,72 @@ "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", - "contentId": "[variables('_dataConnectorContentId1')]", - "contentKind": "DataConnector", - "displayName": "Cisco ETD (using Azure Functions)", - "contentProductId": "[variables('_dataConnectorcontentProductId1')]", - "id": "[variables('_dataConnectorcontentProductId1')]", - "version": "[variables('dataConnectorVersion1')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2023-04-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', last(split(variables('_dataConnectorId1'),'/'))))]", - "dependsOn": [ - "[variables('_dataConnectorId1')]" - ], - "location": "[parameters('workspace-location')]", - "properties": { - "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectors', variables('_dataConnectorContentId1'))]", - "contentId": "[variables('_dataConnectorContentId1')]", - "kind": "DataConnector", - "version": "[variables('dataConnectorVersion1')]", - "source": { - "kind": "Solution", - "name": "Cisco ETD", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Cisco" - }, - "support": { - "name": "Cisco Systems", - "tier": "Partner", - "email": "etd-sentinel@cisco.com" - } + "version": "[variables('dataConnectorCCPVersion')]" } }, { - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentId1'))]", - "apiVersion": "2021-03-01-preview", - "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentIdConnectorDefinition1'))]", + "apiVersion": "2022-09-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectorDefinitions", "location": "[parameters('workspace-location')]", - "kind": "GenericUI", + "kind": "Customizable", "properties": { "connectorUiConfig": { - "title": "Cisco ETD (using Azure Functions)", + "id": "CiscoETDConnectorDefinition", + "title": "Cisco Email Threat Defense (ETD)", "publisher": "Cisco", - "descriptionMarkdown": "The connector fetches data from ETD api for threat analysis", + "descriptionMarkdown": "The [Cisco Email Threat Defense (ETD)](https://docs.cmd.cisco.com/en/Content/secure-email-threat-defense-user-guide/homeUG.htm) data connector provides the capability to ingest [message events](https://docs.cmd.cisco.com/en/Content/secure-email-threat-defense-user-guide/Messages/messages.htm) from Cisco ETD into Microsoft Sentinel using the [Log Export API](https://developer.cisco.com/docs/message-search-api/log-export-api/).", + "graphQueriesTableName": "CiscoETD_CL", "graphQueries": [ { - "metricName": "Total data received", - "legend": "CiscoETD_CL", + "metricName": "Total messages received", + "legend": "Cisco ETD Messages", "baseQuery": "CiscoETD_CL" + }, + { + "metricName": "Malicious messages", + "legend": "Malicious Threats", + "baseQuery": "CiscoETD_CL | where message_verdict_verdict == 'malicious'" + }, + { + "metricName": "Phishing messages", + "legend": "Phishing Threats", + "baseQuery": "CiscoETD_CL | where message_verdict_verdict == 'phishing'" } ], - "dataTypes": [ + "sampleQueries": [ { - "name": "CiscoETD_CL", - "lastDataReceivedQuery": "CiscoETD_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" + "description": "Get all Cisco ETD threat messages", + "query": "CiscoETD_CL\n| sort by TimeGenerated desc" + }, + { + "description": "Get recent malicious messages", + "query": "CiscoETD_CL\n| where message_verdict_verdict == 'malicious'\n| take 10" } ], - "connectivityCriterias": [ + "dataTypes": [ { - "type": "IsConnectedQuery", - "value": [ - "CiscoETD_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(30d)" - ] + "name": "CiscoETD_CL", + "lastDataReceivedQuery": "CiscoETD_CL\n| summarize Time = max(TimeGenerated)\n| where isnotempty(Time)" } ], - "sampleQueries": [ + "connectivityCriteria": [ { - "description": "Incidents aggregated over a period on verdict type", - "query": "CiscoETD_CL | summarize ThreatCount = count() by verdict_category_s, TimeBin = bin(TimeGenerated, 1h) | project TimeBin, verdict_category_s, ThreatCount | render columnchart" + "type": "HasDataConnectors", + "value": [] } ], "availability": { - "status": 1, "isPreview": false }, "permissions": { "resourceProvider": [ { "provider": "Microsoft.OperationalInsights/workspaces", - "permissionsDisplayText": "read and write permissions on the workspace are required.", + "permissionsDisplayText": "Read and Write permissions are required.", "providerDisplayName": "Workspace", "scope": "Workspace", "requiredPermissions": { @@ -326,132 +405,294 @@ "read": true, "delete": true } - }, - { - "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": "Microsoft.Web/sites permissions", - "description": "Read and write permissions to Azure Functions to create a Function App is required. [See the documentation to learn more about Azure Functions](https://docs.microsoft.com/azure/azure-functions/)." - }, - { - "name": "Email Threat Defense API, API key, Client ID and Secret", - "description": "Ensure you have the API key, Client ID and Secret key." + "name": "Cisco ETD API Credentials", + "description": "Cisco ETD API credentials are required. Refer to the [Cisco ETD API Authentication documentation](https://developer.cisco.com/docs/message-search-api/authentication/) for more information." } ] }, "instructionSteps": [ { - "description": ">**NOTE:** This connector uses Azure Functions to connect to the ETD API to pull its logs into Microsoft Sentinel." - }, - { - "description": "**Follow the deployment steps to deploy the connector and the associated Azure Function**\n\n>**IMPORTANT:** Before deploying the ETD data connector, have the Workspace ID and Workspace Primary Key (can be copied from the following).\n", + "title": "Connect to Cisco ETD API", + "description": "Provide your Cisco ETD API endpoint, Client ID, Client Secret, and API Key. These credentials can be obtained from your Cisco ETD administrator or through the Cisco ETD management console.", "instructions": [ { + "type": "Textbox", "parameters": { - "fillWith": [ - "WorkspaceId" - ], - "label": "Workspace ID" - }, - "type": "CopyableLabel" + "label": "Base Endpoint URL", + "placeholder": "https://api.us.etd.cisco.com", + "type": "text", + "name": "baseEndpoint", + "validations": { + "required": true + } + } }, { + "type": "Textbox", "parameters": { - "fillWith": [ - "PrimaryKey" - ], - "label": "Primary Key" + "label": "Client ID", + "placeholder": "Enter OAuth2 Client ID", + "type": "text", + "name": "clientId", + "validations": { + "required": true + } + } + }, + { + "type": "Textbox", + "parameters": { + "label": "Client Secret", + "placeholder": "Enter OAuth2 Client Secret", + "type": "password", + "name": "clientSecret", + "validations": { + "required": true + } + } + }, + { + "type": "Textbox", + "parameters": { + "label": "API Key", + "placeholder": "Enter Cisco ETD API Key", + "type": "password", + "name": "apiKey", + "validations": { + "required": true + } + } + }, + { + "parameters": { + "label": "Connect", + "name": "toggle" }, - "type": "CopyableLabel" + "type": "ConnectionToggleButton" } ] - }, + } + ] + } + } + }, + { + "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": "Cisco" + }, + "support": { + "name": "Cisco", + "email": "support@cisco.com", + "tier": "Partner", + "link": "https://www.cisco.com/c/en/us/support/index.html" + }, + "dependencies": { + "criteria": [ { - "description": "Use this method for automated deployment of the Cisco ETD data connector using an ARM Template.\n\n1. Click the **Deploy to Azure** button below. \n\n\t[![Deploy To Azure](https://aka.ms/deploytoazurebutton)](https://aka.ms/sentinel-CiscoETD-azuredeploy)\n2. Select the preferred **Subscription**, **Resource Group** and **Region**. \n3. Enter the **WorkspaceID**, **SharedKey**, **ClientID**, **ClientSecret**, **ApiKey**, **Verdicts**, **ETD Region**\n4. Click **Create** to deploy.", - "title": "Azure Resource Manager (ARM) Template" + "version": "[variables('dataConnectorCCPVersion')]", + "contentId": "[variables('_dataConnectorContentIdConnections1')]", + "kind": "ResourcesDataConnector" } - ], - "id": "[variables('_uiConfigId1')]" + ] } } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('workbookTemplateSpecName1')]", + "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": { - "description": "CiscoETD Workbook with template version 3.0.0", + "contentId": "[variables('_dataConnectorContentIdConnections1')]", + "displayName": "Cisco Email Threat Defense (ETD)", + "contentKind": "ResourcesDataConnector", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('workbookVersion1')]", - "parameters": {}, - "variables": {}, - "resources": [ - { - "type": "Microsoft.Insights/workbooks", - "name": "[variables('workbookContentId1')]", - "location": "[parameters('workspace-location')]", - "kind": "shared", - "apiVersion": "2021-08-01", - "metadata": { - "description": "Analyze email threat data seamlessly with the workbook, correlating information from the Secure Email Threat Defense API to identify and mitigate suspicious activities, providing insights into trends and allowing for precise filtering and analysis" + "contentVersion": "[variables('dataConnectorCCPVersion')]", + "parameters": { + "guidValue": { + "defaultValue": "[[newGuid()]", + "type": "securestring" + }, + "innerWorkspace": { + "defaultValue": "[parameters('workspace')]", + "type": "securestring" + }, + "connectorDefinitionName": { + "defaultValue": "Cisco Email Threat Defense (ETD)", + "type": "securestring", + "minLength": 1 + }, + "workspace": { + "defaultValue": "[parameters('workspace')]", + "type": "securestring" + }, + "dcrConfig": { + "defaultValue": { + "dataCollectionEndpoint": "data collection Endpoint", + "dataCollectionRuleImmutableId": "data collection rule immutableId" }, - "properties": { - "displayName": "[parameters('workbook1-name')]", - "serializedData": "{\"version\":\"Notebook/1.0\",\"items\":[{\"type\":12,\"content\":{\"version\":\"NotebookGroup/1.0\",\"groupType\":\"editable\",\"items\":[{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"CiscoETD_CL | summarize TotalMessages = count() by verdict_category_s | extend Categories = coalesce(verdict_category_s, 'No Verdict') | project Verdicts = Categories, TotalMessages | render piechart title = 'Email Threat Defense Messages by Verdict'\",\"size\":0,\"title\":\"Total Messages by Threat Type\",\"timeContext\":{\"durationMs\":86400000},\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"customWidth\":\"50\",\"name\":\"query - 0\",\"styleSettings\":{\"margin\":\"10px\"}},{\"type\":12,\"content\":{\"version\":\"NotebookGroup/1.0\",\"groupType\":\"editable\",\"title\":\"Top 10 Malicious Senders Domains\",\"items\":[{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"CiscoETD_CL\\n| extend Domain = tostring(split(fromAddress_s, '@')[1])\\n| where isnotnull(Domain) and trim(' ', Domain) != ''\\n| summarize Count = count() by Domain\\n| top 10 by Count desc\\n\",\"size\":0,\"timeContext\":{\"durationMs\":86400000},\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"categoricalbar\",\"graphSettings\":{\"type\":0,\"topContent\":{\"columnMatch\":\"Domain\",\"formatter\":1},\"centerContent\":{\"columnMatch\":\"Count\",\"formatter\":1,\"numberFormat\":{\"unit\":17,\"options\":{\"maximumSignificantDigits\":3,\"maximumFractionDigits\":2}}}}},\"name\":\"query - 0\"}]},\"customWidth\":\"50\",\"name\":\"group - 9\",\"styleSettings\":{\"margin\":\"10px\"}}]},\"customWidth\":\"100\",\"name\":\"group - 6\",\"styleSettings\":{\"margin\":\"10px\",\"showBorder\":true}},{\"type\":12,\"content\":{\"version\":\"NotebookGroup/1.0\",\"groupType\":\"editable\",\"items\":[{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"CiscoETD_CL\\n| extend Email = fromAddress_s\\n| where isnotnull(Email) and trim(' ', Email) != ''\\n| summarize Count = count() by Email\\n| top 10 by Count desc\",\"size\":0,\"title\":\"Top 10 Malicious Senders\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"gridSettings\":{\"sortBy\":[{\"itemKey\":\"Count\",\"sortOrder\":2}]},\"sortBy\":[{\"itemKey\":\"Count\",\"sortOrder\":2}]},\"customWidth\":\"50\",\"name\":\"query - 2\",\"styleSettings\":{\"margin\":\"10px\"}},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"CiscoETD_CL\\n| summarize Count = count() by mailboxes_s\\n| top 10 by Count desc\\n| extend Email = tostring(replace(\\\"[\\\\\\\"\\\\\\\"\\\\\\\\[\\\\\\\\]]\\\", \\\"\\\", mailboxes_s))\\n| project Email, Count\",\"size\":0,\"title\":\"Top 10 Targetd users\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"customWidth\":\"50\",\"name\":\"query - 3\",\"styleSettings\":{\"margin\":\"10px\"}}]},\"name\":\"Group_Top 10\"}],\"fromTemplateId\":\"sentinel-CiscoETD\",\"$schema\":\"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"}\r\n", - "version": "1.0", - "sourceId": "[variables('workspaceResourceId')]", - "category": "sentinel" - } + "type": "object" + }, + "baseEndpoint": { + "defaultValue": "baseEndpoint", + "type": "securestring", + "minLength": 1 + }, + "clientId": { + "defaultValue": "clientId", + "type": "securestring", + "minLength": 1 }, + "clientSecret": { + "defaultValue": "clientSecret", + "type": "securestring", + "minLength": 1 + }, + "apiKey": { + "defaultValue": "apiKey", + "type": "securestring", + "minLength": 1 + } + }, + "variables": { + "_dataConnectorContentIdConnections1": "[variables('_dataConnectorContentIdConnections1')]" + }, + "resources": [ { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnections1')))]", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Workbook-', last(split(variables('workbookId1'),'/'))))]", + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "properties": { - "description": "@{workbookKey=CiscoETDWorkbook; logoFileName=cisco-logo-72px.svg; description=Analyze email threat data seamlessly with the workbook, correlating information from the Secure Email Threat Defense API to identify and mitigate suspicious activities, providing insights into trends and allowing for precise filtering and analysis; dataTypesDependencies=System.Object[]; dataConnectorsDependencies=System.Object[]; previewImagesFileNames=System.Object[]; version=1.0; title=Cisco Email Threat Defense; templateRelativePath=CiscoETD.json; subtitle=; provider=Cisco}.description", - "parentId": "[variables('workbookId1')]", - "contentId": "[variables('_workbookContentId1')]", - "kind": "Workbook", - "version": "[variables('workbookVersion1')]", + "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectors', variables('_dataConnectorContentIdConnections1'))]", + "contentId": "[variables('_dataConnectorContentIdConnections1')]", + "kind": "ResourcesDataConnector", + "version": "[variables('dataConnectorCCPVersion')]", "source": { - "kind": "Solution", - "name": "Cisco ETD", - "sourceId": "[variables('_solutionId')]" + "sourceId": "[variables('_solutionId')]", + "name": "[variables('_solutionName')]", + "kind": "Solution" }, "author": { "name": "Cisco" }, "support": { - "name": "Cisco Systems", + "name": "Cisco", + "email": "support@cisco.com", "tier": "Partner", - "email": "etd-sentinel@cisco.com" + "link": "https://www.cisco.com/c/en/us/support/index.html" + } + } + }, + { + "name": "[[concat(parameters('innerWorkspace'),'/Microsoft.SecurityInsights/', 'CiscoETDMessages', parameters('guidValue'))]", + "apiVersion": "2023-02-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors", + "location": "[parameters('workspace-location')]", + "kind": "RestApiPoller", + "properties": { + "connectorDefinitionName": "CiscoETDConnectorDefinition", + "dcrConfig": { + "dataCollectionEndpoint": "[[parameters('dcrConfig').dataCollectionEndpoint]", + "dataCollectionRuleImmutableId": "[[parameters('dcrConfig').dataCollectionRuleImmutableId]", + "streamName": "Custom-CiscoETD_CL" }, - "dependencies": { - "operator": "AND", - "criteria": [ - { - "contentId": "CiscoETD_CL", - "kind": "DataType" - }, + "dataType": "CiscoETD_CL", + "auth": { + "type": "JwtToken", + "userName": { + "key": "clientId", + "value": "[[parameters('clientId')]" + }, + "password": { + "key": "clientSecret", + "value": "[[parameters('clientSecret')]" + }, + "TokenEndpoint": "[[concat(parameters('baseEndpoint'),'/v1/oauth/token')]", + "TokenEndpointHttpMethod": "POST", + "Headers": { + "Accept": "application/json", + "Content-Type": "application/json", + "x-api-key": "[[parameters('apiKey')]" + }, + "IsCredentialsInHeaders": true, + "JwtTokenJsonPath": "$.accessToken" + }, + "request": { + "apiEndpoint": "[[concat(parameters('baseEndpoint'),'/v1/logs/downloadLinks')]", + "rateLimitQPS": 10, + "queryWindowInMin": 60, + "queryTimeFormat": "yyyy-MM-ddTHH", + "httpMethod": "POST", + "retryCount": 3, + "timeoutInSeconds": 30, + "isPostPayloadJson": true, + "queryParametersTemplate": "{\"timeRange\": [\"{_QueryWindowStartTime}\", \"{_QueryWindowEndTime}\"], \"logTypes\": [\"message\"]}", + "headers": { + "Accept": "application/json", + "Content-Type": "application/json", + "User-Agent": "Scuba", + "x-api-key": "[[parameters('apiKey')]" + } + }, + "response": { + "eventsJsonPaths": [ + "$.data.message" + ], + "format": "json" + }, + "shouldJoinNestedData": true, + "joinedDataStepName": "downloadLink", + "stepInfo": { + "stepType": "Nested", + "nextSteps": [ { - "contentId": "CiscoETD", - "kind": "DataConnector" + "stepId": "fetchMessageData", + "stepPlaceholdersParsingKql": "source | project res = parse_json(data) | project downloadUrl = res.value" } ] + }, + "stepCollectorConfigs": { + "fetchMessageData": { + "shouldJoinNestedData": true, + "joinedDataStepName": "message", + "auth": { + "AuthType": "None" + }, + "request": { + "httpMethod": "GET", + "apiEndpoint": "$downloadUrl$", + "headers": { + "Accept": "application/x-ndjson" + } + }, + "response": { + "eventsJsonPaths": [ + "$" + ], + "format": "json-line" + } + } } } } @@ -460,14 +701,10 @@ "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", - "contentId": "[variables('_workbookContentId1')]", - "contentKind": "Workbook", - "displayName": "[parameters('workbook1-name')]", - "contentProductId": "[variables('_workbookcontentProductId1')]", - "id": "[variables('_workbookcontentProductId1')]", - "version": "[variables('workbookVersion1')]" + "version": "[variables('dataConnectorCCPVersion')]" } }, { @@ -478,50 +715,48 @@ "version": "3.0.0", "kind": "Solution", "contentSchemaVersion": "3.0.0", - "displayName": "Cisco ETD", - "publisherDisplayName": "Cisco Systems", - "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.

\n

Cisco ETD Solution for Microsoft Microsoft Sentinel makes it easy to connect cisco email threat data to the Microsoft Sentinel, improving visibility into email threats.

\n

Data Connectors: 1, Workbooks: 1

\n

Learn more about Microsoft Sentinel | Learn more about Solutions

\n", + "displayName": "CiscoETD", + "publisherDisplayName": "Cisco", + "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.

\n

The Cisco Email Threat Defense (ETD) solution for Microsoft Sentinel enables you to ingest message events and threat data from Cisco ETD into Microsoft Sentinel using the Log Export API with nested polling.

\n

Data Connectors: 1

\n

Learn more about Microsoft Sentinel | Learn more about Solutions

\n", "contentKind": "Solution", "contentProductId": "[variables('_solutioncontentProductId')]", "id": "[variables('_solutioncontentProductId')]", - "icon": "", + "icon": "", "contentId": "[variables('_solutionId')]", "parentId": "[variables('_solutionId')]", "source": { "kind": "Solution", - "name": "Cisco ETD", + "name": "CiscoETD", "sourceId": "[variables('_solutionId')]" }, "author": { "name": "Cisco" }, "support": { - "name": "Cisco Systems", - "email": "etd-sentinel@cisco.com", - "tier": "Partner" + "name": "Cisco", + "email": "support@cisco.com", + "tier": "Partner", + "link": "https://www.cisco.com/c/en/us/support/index.html" }, "dependencies": { "operator": "AND", "criteria": [ { "kind": "DataConnector", - "contentId": "[variables('_dataConnectorContentId1')]", - "version": "[variables('dataConnectorVersion1')]" - }, - { - "kind": "Workbook", - "contentId": "[variables('_workbookContentId1')]", - "version": "[variables('workbookVersion1')]" + "contentId": "[variables('_dataConnectorContentIdConnections1')]", + "version": "[variables('dataConnectorCCPVersion')]" } ] }, - "firstPublishDate": "2024-03-04", + "firstPublishDate": "2026-02-04", "providers": [ "Cisco" ], "categories": { "domains": [ - "Security - Threat Protection" + "Security - Threat Protection", + "Security - Threat Intelligence", + "IT Operations" ] } }, diff --git a/Solutions/Cisco ETD/Package/testParameters.json b/Solutions/Cisco ETD/Package/testParameters.json index bee1c8ca22d..554801e41b7 100644 --- a/Solutions/Cisco ETD/Package/testParameters.json +++ b/Solutions/Cisco ETD/Package/testParameters.json @@ -21,12 +21,18 @@ "description": "Workspace name for Log Analytics where Microsoft Sentinel is setup" } }, - "workbook1-name": { + "resourceGroupName": { "type": "string", - "defaultValue": "Cisco Email Threat Defense", - "minLength": 1, + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "resource group name where Microsoft Sentinel is setup" + } + }, + "subscription": { + "type": "string", + "defaultValue": "[last(split(subscription().id, '/'))]", "metadata": { - "description": "Name for the workbook" + "description": "subscription id where Microsoft Sentinel is setup" } } } diff --git a/Solutions/Cisco ETD/ReleaseNotes.md b/Solutions/Cisco ETD/ReleaseNotes.md index 9ea3ff5d7fb..a5f8399c954 100644 --- a/Solutions/Cisco ETD/ReleaseNotes.md +++ b/Solutions/Cisco ETD/ReleaseNotes.md @@ -1,3 +1,4 @@ | **Version** | **Date Modified (DD-MM-YYYY)** | **Change History** | |-------------|--------------------------------|---------------------------------------------| -| 3.0.0 | 11-02-2024 | Initial Solution Release | \ No newline at end of file +| 3.0.0 | 11-02-2024 | Initial Solution Release | +| 3.0.1 | 06-04-2026 | Update with Messsage Events Logs | \ No newline at end of file diff --git a/Solutions/Cisco ETD/SolutionMetadata.json b/Solutions/Cisco ETD/SolutionMetadata.json index 8c893046ca1..9886a8d6116 100644 --- a/Solutions/Cisco ETD/SolutionMetadata.json +++ b/Solutions/Cisco ETD/SolutionMetadata.json @@ -1,16 +1,20 @@ -{ - "publisherId": "cisco", - "offerId": "cisco-etd-sentinel", - "firstPublishDate": "2024-03-04", - "providers": [ - "Cisco" - ], - "categories": { - "domains" : ["Security - Threat Protection"] - }, - "support": { - "name": "Cisco Systems", - "tier": "Partner", - "email": "etd-sentinel@cisco.com" - } -} +{ + "publisherId": "cisco", + "offerId": "azure-sentinel-solution-cisco-etd", + "firstPublishDate": "2026-02-04", + "providers": ["Cisco"], + "categories": { + "domains" : [ + "Security - Threat Protection", + "Security - Threat Intelligence", + "IT Operations" + ], + "verticals": [] + }, + "support": { + "name": "Cisco", + "email": "support@cisco.com", + "tier": "Partner", + "link": "https://www.cisco.com/c/en/us/support/index.html" + } +} diff --git a/Solutions/Cisco ETD/Workbooks/CiscoETD.json b/Solutions/Cisco ETD/Workbooks/CiscoETD.json deleted file mode 100644 index a5d4a996028..00000000000 --- a/Solutions/Cisco ETD/Workbooks/CiscoETD.json +++ /dev/null @@ -1,146 +0,0 @@ -{ - "version": "Notebook/1.0", - "items": [ - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 3, - "content": { - "version": "KqlItem/1.0", - "query": "CiscoETD_CL | summarize TotalMessages = count() by verdict_category_s | extend Categories = coalesce(verdict_category_s, 'No Verdict') | project Verdicts = Categories, TotalMessages | render piechart title = 'Email Threat Defense Messages by Verdict'", - "size": 0, - "title": "Total Messages by Threat Type", - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 0, - "resourceType": "microsoft.operationalinsights/workspaces" - }, - "customWidth": "50", - "name": "query - 0", - "styleSettings": { - "margin": "10px" - } - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "title": "Top 10 Malicious Senders Domains", - "items": [ - { - "type": 3, - "content": { - "version": "KqlItem/1.0", - "query": "CiscoETD_CL\n| extend Domain = tostring(split(fromAddress_s, '@')[1])\n| where isnotnull(Domain) and trim(' ', Domain) != ''\n| summarize Count = count() by Domain\n| top 10 by Count desc\n", - "size": 0, - "timeContext": { - "durationMs": 86400000 - }, - "queryType": 0, - "resourceType": "microsoft.operationalinsights/workspaces", - "visualization": "categoricalbar", - "graphSettings": { - "type": 0, - "topContent": { - "columnMatch": "Domain", - "formatter": 1 - }, - "centerContent": { - "columnMatch": "Count", - "formatter": 1, - "numberFormat": { - "unit": 17, - "options": { - "maximumSignificantDigits": 3, - "maximumFractionDigits": 2 - } - } - } - } - }, - "name": "query - 0" - } - ] - }, - "customWidth": "50", - "name": "group - 9", - "styleSettings": { - "margin": "10px" - } - } - ] - }, - "customWidth": "100", - "name": "group - 6", - "styleSettings": { - "margin": "10px", - "showBorder": true - } - }, - { - "type": 12, - "content": { - "version": "NotebookGroup/1.0", - "groupType": "editable", - "items": [ - { - "type": 3, - "content": { - "version": "KqlItem/1.0", - "query": "CiscoETD_CL\n| extend Email = fromAddress_s\n| where isnotnull(Email) and trim(' ', Email) != ''\n| summarize Count = count() by Email\n| top 10 by Count desc", - "size": 0, - "title": "Top 10 Malicious Senders", - "queryType": 0, - "resourceType": "microsoft.operationalinsights/workspaces", - "gridSettings": { - "sortBy": [ - { - "itemKey": "Count", - "sortOrder": 2 - } - ] - }, - "sortBy": [ - { - "itemKey": "Count", - "sortOrder": 2 - } - ] - }, - "customWidth": "50", - "name": "query - 2", - "styleSettings": { - "margin": "10px" - } - }, - { - "type": 3, - "content": { - "version": "KqlItem/1.0", - "query": "CiscoETD_CL\n| summarize Count = count() by mailboxes_s\n| top 10 by Count desc\n| extend Email = tostring(replace(\"[\\\"\\\"\\\\[\\\\]]\", \"\", mailboxes_s))\n| project Email, Count", - "size": 0, - "title": "Top 10 Targetd users", - "queryType": 0, - "resourceType": "microsoft.operationalinsights/workspaces" - }, - "customWidth": "50", - "name": "query - 3", - "styleSettings": { - "margin": "10px" - } - } - ] - }, - "name": "Group_Top 10" - } - ], - "fallbackResourceIds": [], - "fromTemplateId": "sentinel-CiscoETD", - "$schema": "https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json" - } diff --git a/Solutions/Cisco ETD/Workbooks/CiscoETDMessages.json b/Solutions/Cisco ETD/Workbooks/CiscoETDMessages.json new file mode 100644 index 00000000000..8394f9f35df --- /dev/null +++ b/Solutions/Cisco ETD/Workbooks/CiscoETDMessages.json @@ -0,0 +1,526 @@ +{ + "version": "Notebook/1.0", + "items": [ + { + "type": 9, + "content": { + "version": "KqlParameterItem/1.0", + "parameters": [ + { + "id": "cd8447d8-b10e-4a79-9a0d-1e2b4d7e2f5a", + "version": "KqlParameterItem/1.0", + "name": "TimeRange", + "type": 4, + "isRequired": true, + "value": { + "durationMs": 86400000 + }, + "typeSettings": { + "selectableValues": [ + { "durationMs": 3600000 }, + { "durationMs": 14400000 }, + { "durationMs": 43200000 }, + { "durationMs": 86400000 }, + { "durationMs": 259200000 }, + { "durationMs": 604800000 }, + { "durationMs": 2592000000 } + ] + }, + "label": "Time Range" + } + ], + "style": "pills", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces" + }, + "name": "parameters" + }, + + { + "type": 1, + "content": { + "json": "## Cisco Email Threat Defense\nThis workbook uses the **CiscoETDMessages** parser to visualize email threat data from the Cisco ETD connector. Data is sourced from the `message` dynamic column — all fields are parsed at query time. Use the time range filter above to scope all tiles.\n\n> **Note:** Verdict analysis excludes `update` events (re-remediation records that carry no sender/verdict data)." + }, + "name": "header-text" + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "title": "Overview", + "items": [ + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "CiscoETDMessages\n| extend EventType = tostring(message['eventType'])\n| extend Folder = tostring(message['action']['folder'])\n| summarize\n ['Total Events'] = count(),\n ['New Messages'] = countif(EventType =~ 'create'),\n ['Remediation Updates']= countif(EventType =~ 'update'),\n Phishing = countif(Verdict =~ 'phishing'),\n Malicious = countif(Verdict =~ 'malicious'),\n BEC = countif(Verdict =~ 'bec'),\n Graymail = countif(Verdict =~ 'graymail'),\n Spam = countif(Verdict =~ 'spam'),\n Scam = countif(Verdict =~ 'scam'),\n Quarantined = countif(Folder =~ 'quarantine'),\n ['Sent to Junk'] = countif(Folder =~ 'junk')", + "size": 4, + "title": "Message Summary", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces" + }, + "customWidth": "100", + "name": "query-summary", + "styleSettings": { "margin": "10px" } + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "CiscoETDMessages\n| where tostring(message['eventType']) =~ 'create'\n| where isnotempty(Verdict)\n| summarize Count = count() by Verdict\n| render piechart title = 'Messages by Verdict'", + "size": 0, + "title": "Messages by Verdict", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces" + }, + "customWidth": "33", + "name": "query-verdict-pie", + "styleSettings": { "margin": "10px" } + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "CiscoETDMessages\n| where tostring(message['eventType']) =~ 'create'\n| where isnotempty(Verdict)\n| summarize Count = count() by bin(EventTime, 1h), Verdict\n| render timechart title = 'Message Volume Over Time'", + "size": 0, + "title": "Message Volume Over Time (by Verdict)", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces" + }, + "customWidth": "67", + "name": "query-volume-time", + "styleSettings": { "margin": "10px" } + } + ] + }, + "name": "group-overview", + "styleSettings": { "showBorder": true, "margin": "10px" } + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "title": "Senders & Recipients", + "items": [ + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "CiscoETDMessages\n| where tostring(message['eventType']) =~ 'create'\n| where isnotempty(Sender)\n| summarize MessageCount = count(), Verdicts = make_set(Verdict, 5) by Sender\n| top 10 by MessageCount desc", + "size": 0, + "title": "Top 10 Senders", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "visualization": "categoricalbar", + "gridSettings": { "sortBy": [{ "itemKey": "MessageCount", "sortOrder": 2 }] }, + "sortBy": [{ "itemKey": "MessageCount", "sortOrder": 2 }] + }, + "customWidth": "50", + "name": "query-top-senders", + "styleSettings": { "margin": "10px" } + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "CiscoETDMessages\n| where tostring(message['eventType']) =~ 'create'\n| where isnotempty(Sender)\n| extend SenderDomain = tostring(split(Sender, '@')[1])\n| where isnotempty(SenderDomain)\n| summarize MessageCount = count(), Verdicts = make_set(Verdict, 5) by SenderDomain\n| top 10 by MessageCount desc", + "size": 0, + "title": "Top 10 Sender Domains", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "visualization": "categoricalbar", + "gridSettings": { "sortBy": [{ "itemKey": "MessageCount", "sortOrder": 2 }] }, + "sortBy": [{ "itemKey": "MessageCount", "sortOrder": 2 }] + }, + "customWidth": "50", + "name": "query-top-sender-domains", + "styleSettings": { "margin": "10px" } + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "CiscoETDMessages\n| where tostring(message['eventType']) =~ 'create'\n| where isnotempty(Recipient)\n| summarize MessageCount = count(), Verdicts = make_set(Verdict, 5) by Recipient\n| top 10 by MessageCount desc", + "size": 0, + "title": "Top 10 Targeted Recipients", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "gridSettings": { "sortBy": [{ "itemKey": "MessageCount", "sortOrder": 2 }] }, + "sortBy": [{ "itemKey": "MessageCount", "sortOrder": 2 }] + }, + "customWidth": "50", + "name": "query-top-recipients", + "styleSettings": { "margin": "10px" } + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "CiscoETDMessages\n| where tostring(message['eventType']) =~ 'create'\n| where isnotempty(Recipient)\n| extend RecipientDomain = tostring(split(Recipient, '@')[1])\n| where isnotempty(RecipientDomain)\n| summarize MessageCount = count() by RecipientDomain\n| top 10 by MessageCount desc", + "size": 0, + "title": "Top 10 Targeted Recipient Domains", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "gridSettings": { "sortBy": [{ "itemKey": "MessageCount", "sortOrder": 2 }] }, + "sortBy": [{ "itemKey": "MessageCount", "sortOrder": 2 }] + }, + "customWidth": "50", + "name": "query-top-recipient-domains", + "styleSettings": { "margin": "10px" } + } + ] + }, + "name": "group-senders-recipients", + "styleSettings": { "showBorder": true, "margin": "10px" } + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "title": "Detection Techniques", + "items": [ + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "CiscoETDMessages\n| where tostring(message['eventType']) =~ 'create'\n| where isnotempty(Verdict)\n| mv-expand detection = message['verdict']['detections']\n| where isnotnull(detection)\n| extend Technique = tostring(detection['technique'])\n| where isnotempty(Technique)\n| summarize Count = count() by Technique\n| top 15 by Count desc", + "size": 0, + "title": "Top Detection Techniques", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "visualization": "categoricalbar", + "gridSettings": { "sortBy": [{ "itemKey": "Count", "sortOrder": 2 }] }, + "sortBy": [{ "itemKey": "Count", "sortOrder": 2 }] + }, + "customWidth": "60", + "name": "query-detection-techniques", + "styleSettings": { "margin": "10px" } + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "CiscoETDMessages\n| where tostring(message['eventType']) =~ 'create'\n| where isnotempty(Verdict)\n| extend BusinessRisk = tostring(message['verdict']['businessRisk'])\n| where isnotempty(BusinessRisk)\n| summarize Count = count() by BusinessRisk\n| render piechart title = 'Business Risk'", + "size": 0, + "title": "Business Risk\n(phishing / malicious only)", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces" + }, + "customWidth": "40", + "name": "query-business-risk", + "styleSettings": { "margin": "10px" } + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "CiscoETDMessages\n| where tostring(message['eventType']) =~ 'create'\n| where isnotempty(Verdict)\n| mv-expand detection = message['verdict']['detections']\n| where isnotnull(detection)\n| extend Technique = tostring(detection['technique']),\n DetectionType = tostring(detection['type']),\n Description = tostring(detection['description'])\n| where isnotempty(Technique)\n| summarize Count = count() by Verdict, Technique, DetectionType\n| sort by Verdict asc, Count desc\n| project Verdict, Technique, DetectionType, Count", + "size": 0, + "title": "Detection Technique Details", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "gridSettings": { "sortBy": [{ "itemKey": "Count", "sortOrder": 2 }] }, + "sortBy": [{ "itemKey": "Count", "sortOrder": 2 }] + }, + "customWidth": "100", + "name": "query-detection-detail-grid", + "styleSettings": { "margin": "10px" } + } + ] + }, + "name": "group-detections", + "styleSettings": { "showBorder": true, "margin": "10px" } + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "title": "Actions & Remediation", + "items": [ + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "CiscoETDMessages\n| where tostring(message['eventType']) =~ 'create'\n| extend Folder = tostring(message['action']['folder'])\n| where isnotempty(Folder)\n| summarize Count = count() by Folder\n| render piechart title = 'Disposition Folder'", + "size": 0, + "title": "Disposition Folder\n(junk vs quarantine)", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces" + }, + "customWidth": "33", + "name": "query-action-folder", + "styleSettings": { "margin": "10px" } + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "CiscoETDMessages\n| where tostring(message['eventType']) =~ 'create'\n| where isnotempty(Verdict)\n| extend Folder = tostring(message['action']['folder'])\n| where isnotempty(Folder)\n| summarize Count = count() by Verdict, Folder\n| sort by Count desc", + "size": 0, + "title": "Verdict vs. Folder", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "visualization": "categoricalbar" + }, + "customWidth": "34", + "name": "query-verdict-folder", + "styleSettings": { "margin": "10px" } + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "CiscoETDMessages\n| where tostring(message['eventType']) =~ 'create'\n| where isnotempty(Verdict)\n| extend IsAutoRemediated = tostring(message['verdict']['isAutoRemediated'])\n| extend ReclassifiedBy = tostring(message['verdict']['reclassifiedBy'])\n| where isnotempty(IsAutoRemediated)\n| summarize Count = count() by IsAutoRemediated, ReclassifiedBy\n| project ['Auto-Remediated'] = IsAutoRemediated, ['Reclassified By'] = ReclassifiedBy, Count", + "size": 0, + "title": "Auto-Remediation & Reclassification", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces" + }, + "customWidth": "33", + "name": "query-auto-remediation", + "styleSettings": { "margin": "10px" } + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "CiscoETDMessages\n| where tostring(message['eventType']) =~ 'update'\n| extend Folder = tostring(message['action']['folder'])\n| extend RemediatedBy = tostring(message['action']['remediatedBy'])\n| extend ActionType = tostring(message['action']['action'])\n| project EventTime, MessageId, ActionType, Folder, RemediatedBy\n| sort by EventTime desc", + "size": 0, + "title": "Remediation Update Events", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "gridSettings": { "sortBy": [{ "itemKey": "EventTime", "sortOrder": 2 }] }, + "sortBy": [{ "itemKey": "EventTime", "sortOrder": 2 }] + }, + "customWidth": "100", + "name": "query-remediation-updates", + "styleSettings": { "margin": "10px" } + } + ] + }, + "name": "group-actions", + "styleSettings": { "showBorder": true, "margin": "10px" } + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "title": "Attachments", + "items": [ + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "CiscoETDMessages\n| where tostring(message['eventType']) =~ 'create'\n| where isnotnull(message['attachments'])\n| mv-expand attachment = message['attachments']\n| extend FileName = tostring(attachment['filename'])\n| where isnotempty(FileName)\n| extend FileExt = tolower(extract(@'\\.([^.]+)$', 1, FileName))\n| where isnotempty(FileExt)\n| summarize Count = count() by FileExt\n| top 10 by Count desc\n| render piechart title = 'Attachment File Types'", + "size": 0, + "title": "Attachment File Extensions", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces" + }, + "customWidth": "33", + "name": "query-attachment-types", + "styleSettings": { "margin": "10px" } + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "CiscoETDMessages\n| where tostring(message['eventType']) =~ 'create'\n| where isnotnull(message['attachments'])\n| mv-expand attachment = message['attachments']\n| extend FileName = tostring(attachment['filename']),\n SHA256 = tostring(attachment['SHA256'])\n| where isnotempty(SHA256)\n// Deduplicate by SHA256 to find unique files seen across many messages\n| summarize\n FileNames = make_set(FileName, 10),\n TimeSeen = count(),\n Verdicts = make_set(Verdict, 5),\n Senders = make_set(Sender, 10)\n by SHA256\n| sort by TimeSeen desc", + "size": 0, + "title": "Unique Attachment Hashes (SHA256)", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "gridSettings": { "sortBy": [{ "itemKey": "TimeSeen", "sortOrder": 2 }] }, + "sortBy": [{ "itemKey": "TimeSeen", "sortOrder": 2 }] + }, + "customWidth": "67", + "name": "query-attachment-hashes", + "styleSettings": { "margin": "10px" } + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "// Uses the verdict detections array — type='sha256' entries flag files\n// identified by threat intelligence, distinct from all attachments above\nCiscoETDMessages\n| where tostring(message['eventType']) =~ 'create'\n| where Verdict =~ 'malicious'\n| mv-expand detection = message['verdict']['detections']\n| where tostring(detection['type']) =~ 'sha256'\n| extend SHA256 = tostring(detection['description']),\n Technique = tostring(detection['technique'])\n| where isnotempty(SHA256)\n| summarize Count = count() by SHA256, Technique, Sender, Subject\n| sort by Count desc", + "size": 0, + "title": "Malicious File Hashes (from Threat Detections)", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "gridSettings": { "sortBy": [{ "itemKey": "Count", "sortOrder": 2 }] }, + "sortBy": [{ "itemKey": "Count", "sortOrder": 2 }] + }, + "customWidth": "100", + "name": "query-malicious-hashes", + "styleSettings": { "margin": "10px" } + } + ] + }, + "name": "group-attachments", + "styleSettings": { "showBorder": true, "margin": "10px" } + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "title": "Suspicious URLs", + "items": [ + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "// URLs surfaced in the verdict detections array with type='url'\n// These are the URLs Cisco ETD flagged as malicious/suspicious\nCiscoETDMessages\n| where tostring(message['eventType']) =~ 'create'\n| where Verdict in~ ('phishing', 'malicious')\n| mv-expand detection = message['verdict']['detections']\n| where tostring(detection['type']) =~ 'url'\n| extend MaliciousUrl = tostring(detection['description']),\n Technique = tostring(detection['technique'])\n| where isnotempty(MaliciousUrl)\n| summarize Count = count(), Senders = make_set(Sender, 5) by MaliciousUrl, Technique\n| sort by Count desc", + "size": 0, + "title": "Malicious URLs (flagged in Detections)", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "gridSettings": { "sortBy": [{ "itemKey": "Count", "sortOrder": 2 }] }, + "sortBy": [{ "itemKey": "Count", "sortOrder": 2 }] + }, + "customWidth": "100", + "name": "query-malicious-urls", + "styleSettings": { "margin": "10px" } + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "// All URLs in urlMetadata across threat messages, grouped by domain\n// Excludes HTML entities ( ) and mailto links\nCiscoETDMessages\n| where tostring(message['eventType']) =~ 'create'\n| where Verdict in~ ('phishing', 'malicious', 'bec')\n| where isnotnull(message['urlMetadata'])\n| mv-expand urlItem = message['urlMetadata']\n| extend Url = tostring(urlItem['url'])\n| where isnotempty(Url)\n and Url !startswith '&'\n and Url !startswith 'http://mailto'\n and not(Url matches regex @'^www\\.')\n| extend UrlDomain = extract(@'^https?://([^/?#\\s]+)', 1, Url)\n| where isnotempty(UrlDomain)\n| summarize Count = count() by UrlDomain\n| top 20 by Count desc", + "size": 0, + "title": "Top URL Domains in Threat Messages", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "visualization": "categoricalbar", + "gridSettings": { "sortBy": [{ "itemKey": "Count", "sortOrder": 2 }] }, + "sortBy": [{ "itemKey": "Count", "sortOrder": 2 }] + }, + "customWidth": "100", + "name": "query-url-domains", + "styleSettings": { "margin": "10px" } + } + ] + }, + "name": "group-urls", + "styleSettings": { "showBorder": true, "margin": "10px" } + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "title": "Network Indicators", + "items": [ + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "// clientIp = the external IP that delivered mail to the Cisco gateway\n// This is meaningful: hotmail.com sends from Azure IPs, gmail.com from Google IPs, etc.\nCiscoETDMessages\n| where tostring(message['eventType']) =~ 'create'\n| extend ClientIp = tostring(message['clientIp'])\n| where isnotempty(ClientIp)\n| summarize\n MessageCount = count(),\n Verdicts = make_set(Verdict, 5),\n Senders = make_set(Sender, 10)\n by ClientIp\n| sort by MessageCount desc", + "size": 0, + "title": "Top Sending Client IPs", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "gridSettings": { "sortBy": [{ "itemKey": "MessageCount", "sortOrder": 2 }] }, + "sortBy": [{ "itemKey": "MessageCount", "sortOrder": 2 }] + }, + "customWidth": "50", + "name": "query-client-ips", + "styleSettings": { "margin": "10px" } + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "CiscoETDMessages\n| where tostring(message['eventType']) =~ 'create'\n| where Verdict in~ ('phishing', 'malicious', 'bec')\n| extend ClientIp = tostring(message['clientIp'])\n| where isnotempty(ClientIp)\n| summarize\n ThreatCount = count(),\n Verdicts = make_set(Verdict, 5),\n Senders = make_set(Sender, 5),\n Subjects = make_set(Subject, 5)\n by ClientIp\n| sort by ThreatCount desc", + "size": 0, + "title": "Threat-Associated Sending IPs", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "gridSettings": { "sortBy": [{ "itemKey": "ThreatCount", "sortOrder": 2 }] }, + "sortBy": [{ "itemKey": "ThreatCount", "sortOrder": 2 }] + }, + "customWidth": "50", + "name": "query-threat-ips", + "styleSettings": { "margin": "10px" } + } + ] + }, + "name": "group-network", + "styleSettings": { "showBorder": true, "margin": "10px" } + }, + { + "type": 12, + "content": { + "version": "NotebookGroup/1.0", + "groupType": "editable", + "title": "Recent Threats", + "items": [ + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "CiscoETDMessages\n| where tostring(message['eventType']) =~ 'create'\n| where Verdict in~ ('phishing', 'malicious', 'bec')\n| extend ClientIp = tostring(message['clientIp'])\n| extend Folder = tostring(message['action']['folder'])\n| extend BusinessRisk = tostring(message['verdict']['businessRisk'])\n| extend HasAttach = isnotnull(message['attachments']) and array_length(message['attachments']) > 0\n| extend HasMalUrl = isnotnull(message['verdict']['detections'])\n| project\n EventTime,\n MessageId,\n Verdict,\n BusinessRisk,\n Sender,\n Recipient,\n Subject,\n Folder,\n ['Has Attachments'] = HasAttach,\n ['Has Malicious URL'] = HasMalUrl,\n ClientIp\n| sort by EventTime desc\n| take 100", + "size": 0, + "title": "Recent High-Threat Messages (Phishing / Malicious / BEC)", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "gridSettings": { "sortBy": [{ "itemKey": "EventTime", "sortOrder": 2 }] }, + "sortBy": [{ "itemKey": "EventTime", "sortOrder": 2 }] + }, + "customWidth": "100", + "name": "query-recent-threats", + "styleSettings": { "margin": "10px" } + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "CiscoETDMessages\n| where tostring(message['eventType']) =~ 'create'\n| where isnotempty(Subject) and isnotempty(Verdict)\n| where Verdict in~ ('phishing', 'malicious', 'bec')\n| project EventTime, Verdict, Subject, Sender, Recipient\n| sort by EventTime desc", + "size": 0, + "title": "Subject Lines in Threat Messages", + "timeContextFromParameter": "TimeRange", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "gridSettings": { "sortBy": [{ "itemKey": "EventTime", "sortOrder": 2 }] }, + "sortBy": [{ "itemKey": "EventTime", "sortOrder": 2 }] + }, + "customWidth": "100", + "name": "query-threat-subjects", + "styleSettings": { "margin": "10px" } + } + ] + }, + "name": "group-recent", + "styleSettings": { "showBorder": true, "margin": "10px" } + } + ], + "fallbackResourceIds": [], + "fromTemplateId": "sentinel-CiscoETDMessages", + "$schema": "https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json" +} diff --git a/Solutions/Cisco ETD/Workbooks/Images/Preview/CiscoETDBlack01.PNG b/Solutions/Cisco ETD/Workbooks/Images/Preview/CiscoETDBlack01.PNG deleted file mode 100644 index 83811e66f77..00000000000 Binary files a/Solutions/Cisco ETD/Workbooks/Images/Preview/CiscoETDBlack01.PNG and /dev/null differ diff --git a/Solutions/Cisco ETD/Workbooks/Images/Preview/CiscoETDBlack02.PNG b/Solutions/Cisco ETD/Workbooks/Images/Preview/CiscoETDBlack02.PNG deleted file mode 100644 index 4078a55494f..00000000000 Binary files a/Solutions/Cisco ETD/Workbooks/Images/Preview/CiscoETDBlack02.PNG and /dev/null differ diff --git a/Solutions/Cisco ETD/Workbooks/Images/Preview/CiscoETDWhite01.PNG b/Solutions/Cisco ETD/Workbooks/Images/Preview/CiscoETDWhite01.PNG deleted file mode 100644 index 7efa5e1cf90..00000000000 Binary files a/Solutions/Cisco ETD/Workbooks/Images/Preview/CiscoETDWhite01.PNG and /dev/null differ diff --git a/Solutions/Cisco ETD/Workbooks/Images/Preview/CiscoETDWhite02.PNG b/Solutions/Cisco ETD/Workbooks/Images/Preview/CiscoETDWhite02.PNG deleted file mode 100644 index 669724c965e..00000000000 Binary files a/Solutions/Cisco ETD/Workbooks/Images/Preview/CiscoETDWhite02.PNG and /dev/null differ