ZeroTrustAnalyticsPlatform
Zero Trust Analytics Platform (ZTAP) is the underlying investigation platform and user interface for Critical Start's MDR service.
Endpoint · Zero Trust Analytics Platform
Details
| ID | ZeroTrustAnalyticsPlatform |
|---|---|
| Provider | Zscaler |
| Category | Endpoint |
| From Version | 6.0.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Supported Modules | Agentix XSIAM |
README
Zero Trust Analytics Platform (ZTAP) is the underlying investigation platform and user interface for Critical Start’s MDR service.
This integration was integrated and tested with version 2021-06-25 of ZeroTrustAnalyticsPlatform
Configure ZeroTrustAnalyticsPlatform in Cortex
| Parameter | Description | Required |
|---|---|---|
| ZTAP server URL | True | |
| API Key | The API Key to use for connection | True |
| Reopen Group | Group to send to when reopening | True |
| Trust any certificate (not secure) | False | |
| Use system proxy settings | False | |
| Fetch incidents | False | |
| Incident type | False | |
| Incident Mirroring Direction | False | |
| Comment entry tag | Adding this tag to a Note will sync as a comment in ZTAP | False |
| Escalate entry tag | Adding this tag to a Note will reassign the alert back to Critical Start SOC | False |
| ZTAP input tag | False | |
| Fetch attachments for comments from ZTAP | False | |
| Sync closing incidents with ZTAP | Cortex XSOAR only parameter. | False |
| Sync reopening incidents with ZTAP | False | |
| First fetch timestamp | False | |
| Maximum number of incidents to fetch | False |
Commands
You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.
get-mapping-fields
Get mapping fields from remote incident.
Base Command
get-mapping-fields
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
There is no context output for this command.
Command Example
#### Human Readable Output
### get-remote-data
***
Get remote data from a remote incident. This command should only be called manually for debugging purposes.
#### Base Command
`get-remote-data`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| id | The remote incident id. | Required |
| lastUpdate | UTC timestamp in seconds. The incident is only updated if it was modified after the last update time. Default is 0. | Optional |
#### Context Output
There is no context output for this command.
#### Command Example
!get-remote-data id=1 lastUpdate=2000-01-1
```
Human Readable Output
ztap-get-alert-entries
Get the entries data from a remote incident.
Base Command
ztap-get-alert-entries
Input
| Argument Name | Description | Required |
|---|---|---|
| id | The remote incident id. | Required |
Context Output
There is no context output for this command.
Command Example
!ztap-get-alert-entries id=1
Human Readable Output
Example comment. Sent by User (test@test) via ZTAP
Configuration parameters
url— ZTAP server URL (required)apikey— API Key (required)reopen_group— Reopen Group (required)insecure— Trust any certificate (not secure)proxy— Use system proxy settingsisFetch— Fetch incidentsincidentType— Incident typeincidentFetchInterval— Incidents Fetch Intervalmirror_direction— Incident Mirroring Directioncomment_tag— Comment entry tagescalate_tag— Escalate entry taginput_tag— ZTAP input tagget_attachments— Fetch attachments for comments from ZTAPclose_incident— Sync closing incidents with ZTAPreopen_incident— Sync reopening incidents with ZTAPfirst_fetch— First fetch timestampmax_fetch— Maximum number of incidents to fetch
Commands (3)
-
get-mapping-fieldsGet mapping fields from remote incident.
-
get-remote-dataGet remote data from a remote incident. This command should only be called manually for debugging purposes.
-
ztap-get-alert-entriesGet the entries data from a remote incident.
import json from datetime import datetime from ZeroTrustAnalyticsPlatform import ( Client, fetch_incidents, get_mapping_fields, get_modified_remote_data, get_remote_data, update_remote_system, user_to_display, ztap_get_alert_entries, ) from test_data.api_data import ( alert_data, escalation_path_data, event_data, comment_data, organization_data, group_data, user_data, ) from test_data.xsoar_data import ( alert_response, alert_response_remote, comment_entries, ) TEST_MIRROR_DIRECTION = "Both" TEST_INTEGRATION_INSTANCE = "dummy_instance" TEST_ESCALATE_ORG = "dummy_org" TEST_ESCALATE_GROUP = "Default" TEST_COMMENT_TAG = "comment_tag" TEST_ESCALATE_TAG = "escalate_tag" TEST_INPUT_TAG = "input_tag" def get_test_client(): client = Client("some_mock_url", verify_certificate=False) client.comment_tag = TEST_COMMENT_TAG client.escalate_tag = TEST_ESCALATE_TAG client.input_tag = TEST_INPUT_TAG client.reopen_group = TEST_ESCALATE_GROUP return client def test_fetch_incidents(mocker): client = get_test_client() mocker.patch.object(client, "get_alerts", return_value=alert_data()) mocker.patch.object(client, "get_escalation_path", return_value=escalation_path_data()) mocker.patch.object(client, "get_events", return_value=event_data()) mocker.patch.object(client, "get_active_user", return_value=user_data()) last_run = { "last_run": "2021-01-01T00:00:00Z", "existing_ids": [], } max_fetch = 100 first_fetch_timestamp = "7 days" response, new_last_run = fetch_incidents( client, last_run, first_fetch_timestamp, max_fetch, TEST_MIRROR_DIRECTION, TEST_INTEGRATION_INSTANCE, ) mock_response_0 = json.dumps(alert_response()[0]) mock_response_1 = json.dumps(alert_response()[1]) assert response[0]["rawJSON"] == mock_response_0 assert response[1]["rawJSON"] == mock_response_1 assert new_last_run["last_run"] == "2021-05-11T20:11:31Z" assert new_last_run["existing_ids"] == ["1", "2"] def test_fetch_incidents_already_escalated(mocker): client = get_test_client() old_escalation_path = ( { "time": "2020-05-01T00:00:00Z", "group": "Default (dummy_org)", "group_id": "1", "type": "Group", }, { "time": datetime.now().isoformat() + "Z", "group": "Default (dummy_org)", "group_id": "1", "type": "Group", }, ) mocker.patch.object(client, "get_alerts", return_value=alert_data()) mocker.patch.object(client, "get_escalation_path", return_value=old_escalation_path) mocker.patch.object(client, "get_events", return_value=event_data()) mocker.patch.object(client, "get_active_user", return_value=user_data()) last_run = { "last_run": "2021-01-01T00:00:00Z", "existing_ids": [], } max_fetch = 100 first_fetch_timestamp = "7 days" response, new_last_run = fetch_incidents( client, last_run, first_fetch_timestamp, max_fetch, TEST_MIRROR_DIRECTION, TEST_INTEGRATION_INSTANCE, ) assert len(response) == 0 assert new_last_run["last_run"] == "2021-05-11T20:11:31Z" assert new_last_run["existing_ids"] == [] def test_fetch_incidents_first_fetch(mocker): client = get_test_client() recent_escalation_path = ( { "time": datetime.now().isoformat() + "Z", "group": "Default (dummy_org)", "group_id": "1", "type": "Group", }, ) mocker.patch.object(client, "get_alerts", return_value=alert_data()) mocker.patch.object(client, "get_escalation_path", return_value=recent_escalation_path) mocker.patch.object(client, "get_events", return_value=event_data()) mocker.patch.object(client, "get_active_user", return_value=user_data()) last_run = {} max_fetch = 100 first_fetch_timestamp = "7 days" response, new_last_run = fetch_incidents( client, last_run, first_fetch_timestamp, max_fetch, TEST_MIRROR_DIRECTION, TEST_INTEGRATION_INSTANCE, ) mock_response_0 = json.dumps(alert_response()[0]) mock_response_1 = json.dumps(alert_response()[1]) assert response[0]["rawJSON"] == mock_response_0 assert response[1]["rawJSON"] == mock_response_1 assert new_last_run["existing_ids"] == ["1", "2"] def test_fetch_incidents_existing_ids(mocker): client = get_test_client() mocker.patch.object(client, "get_alerts", return_value=alert_data()) mocker.patch.object(client, "get_escalation_path", return_value=escalation_path_data()) mocker.patch.object(client, "get_events", return_value=event_data()) mocker.patch.object(client, "get_active_user", return_value=user_data()) last_run = { "last_run": "2021-05-11T20:11:31Z", "existing_ids": ["1", "2"], } max_fetch = 100 first_fetch_timestamp = "7 days" response, new_last_run = fetch_incidents( client, last_run, first_fetch_timestamp, max_fetch, TEST_MIRROR_DIRECTION, TEST_INTEGRATION_INSTANCE, ) assert len(response) == 0 assert new_last_run["last_run"] == "2021-05-11T20:11:31Z" assert new_last_run["existing_ids"] == ["1", "2"] def test_get_mapping_fields(): response = get_mapping_fields() fields = response.scheme_types_mappings[0].fields assert "status" in fields def test_get_remote_data(mocker): client = get_test_client() mocker.patch.object(client, "get_alert", return_value=alert_data()[0]) mocker.patch.object(client, "get_events", return_value=event_data()) mocker.patch.object(client, "get_comments", return_value=comment_data()) mocker.patch.object(client, "get_active_user", return_value=user_data()) args = { "id": "1", "lastUpdate": "2021-01-01T00:00:00Z", } investigation = {} response = get_remote_data(client, investigation, args) alert_json = json.dumps(response.mirrored_object) mock_response = json.dumps(alert_response_remote()) entries_json = json.dumps(response.entries) entry_response = json.dumps(comment_entries()) assert alert_json == mock_response assert entries_json == entry_response def test_get_remote_data_no_new_events(mocker): client = get_test_client() mocker.patch.object(client, "get_alert", return_value=alert_data()[0]) mocker.patch.object(client, "get_comments", return_value=[]) mocker.patch.object(client, "get_active_user", return_value=user_data()) args = { "id": "1", "lastUpdate": "2022-01-01T00:00:00Z", } investigation = {} response = get_remote_data(client, investigation, args) assert "xsoar_trigger_events" not in response.mirrored_object def test_get_remote_data_closed_incident(mocker): client = get_test_client() closed_alert = { "datetime_created": "2021-05-11T20:11:31Z", "datetime_firstevent": "2021-05-11T20:11:30Z", "datetime_closed": "2021-05-11T21:00:00Z", "datetime_events_added": "2021-05-11T20:11:31Z", "id": 1, "status": "closed", "review_outcome": "resolved", } mocker.patch.object(client, "get_alert", return_value=closed_alert) mocker.patch.object(client, "get_events", return_value=[]) mocker.patch.object(client, "get_comments", return_value=[]) mocker.patch.object(client, "get_active_user", return_value=user_data()) client.close_incident = True args = { "id": "1", "lastUpdate": "2021-01-01T00:00:00Z", } investigation = { "lastOpen": "2021-05-01T00:00:00Z", } response = get_remote_data(client, investigation, args) assert len(response.entries) == 1 assert response.entries[-1]["Contents"]["dbotIncidentClose"] # Reopened after close time investigation = { "lastOpen": "2021-05-12T00:00:00Z", } response = get_remote_data(client, investigation, args) assert len(response.entries) == 0 def test_get_remote_data_reopen_incident(mocker): client = get_test_client() reopened_alert = { "datetime_created": "2021-05-11T20:11:31Z", "datetime_firstevent": "2021-05-11T20:11:30Z", "datetime_closed": "2021-05-11T21:00:00Z", "datetime_events_added": "2021-05-11T20:11:31Z", "datetime_org_assigned": "2021-05-11T22:00:00Z", "id": 1, "status": "assigned", } mocker.patch.object(client, "get_alert", return_value=reopened_alert) mocker.patch.object(client, "get_comments", return_value=[]) mocker.patch.object(client, "get_active_user", return_value=user_data()) client.reopen_incident = True args = { "id": "1", "lastUpdate": "2021-05-11T23:00:00Z", } investigation = { "closed": "2021-05-01T00:00:00Z", } response = get_remote_data(client, investigation, args) assert len(response.entries) == 1 assert response.entries[-1]["Contents"]["dbotIncidentReopen"] # Closed after reopen time investigation = { "closed": "2021-05-12T00:00:00Z", } response = get_remote_data(client, investigation, args) assert len(response.entries) == 0 def test_get_modified_remote_data(mocker): client = get_test_client() mocker.patch.object(client, "get_all_alerts", return_value=alert_data()) args = { "lastUpdate": "2021-01-01T00:00:00Z", } response = get_modified_remote_data(client, args) assert response.modified_incident_ids == ["1", "2"] def test_update_remote_system(mocker): client = get_test_client() mocker.patch.object(client, "get_alert", return_value=alert_data()[0]) mocker.patch.object(client, "upload_comment") mocker.patch.object(client, "get_active_user", return_value=user_data()) client.close_incident = True args = { "remoteId": "1", "status": 1, "entries": [ { "user": "test user", "contents": "test contents", "tags": TEST_COMMENT_TAG, } ], "incidentChanged": False, } investigation = {} response = update_remote_system(client, investigation, args) client.upload_comment.assert_called() assert response == "1" def test_update_remote_system_escalate(mocker): client = get_test_client() mocker.patch.object(client, "get_alert", return_value=alert_data()[0]) mocker.patch.object(client, "reassign_alert_to_org") mocker.patch.object(client, "get_organizations", return_value=organization_data()) mocker.patch.object(client, "get_active_user", return_value=user_data()) client.close_incident = True args = { "remoteId": "1", "status": 1, "entries": [ { "user": "test user", "contents": "test contents", "tags": TEST_ESCALATE_TAG, } ], "incidentChanged": False, } investigation = {} response = update_remote_system(client, investigation, args) client.reassign_alert_to_org.assert_called() assert response == "1" def test_update_remote_system_escalate_and_comment(mocker): # escalate should take priority over comment client = get_test_client() mocker.patch.object(client, "get_alert", return_value=alert_data()[0]) mocker.patch.object(client, "reassign_alert_to_org") mocker.patch.object(client, "get_organizations", return_value=organization_data()) mocker.patch.object(client, "get_active_user", return_value=user_data()) client.close_incident = True args = { "remoteId": "1", "status": 1, "entries": [ { "user": "test user", "contents": "test contents", "tags": [TEST_COMMENT_TAG, TEST_ESCALATE_TAG], } ], "incidentChanged": False, } investigation = {} response = update_remote_system(client, investigation, args) client.reassign_alert_to_org.assert_called() assert response == "1" def test_update_remote_system_closed(mocker): client = get_test_client() mocker.patch.object(client, "get_alert", return_value=alert_data()[0]) mocker.patch.object(client, "close_alert") mocker.patch.object(client, "get_active_user", return_value=user_data()) client.close_incident = True args = { "remoteId": "1", "status": 2, "data": { "closeNotes": "Closed as duplicate.", "closeReason": "duplicate", }, "delta": {}, "incidentChanged": True, } investigation = {"closed": "2021-05-12T00:00:00Z"} response = update_remote_system(client, investigation, args) client.close_alert.assert_called() assert response == "1" def test_update_remote_system_reopen(mocker): client = get_test_client() client.reopen_incident = True closed_alert = { "datetime_created": "2021-05-11T20:11:31Z", "datetime_firstevent": "2021-05-11T20:11:30Z", "datetime_closed": "2021-05-11T21:00:00Z", "datetime_events_added": "2021-05-11T20:11:31Z", "id": 1, "status": "closed", } mocker.patch.object(client, "get_alert", return_value=closed_alert) mocker.patch.object(client, "reopen_alert") mocker.patch.object(client, "get_groups", return_value=group_data()) mocker.patch.object(client, "get_active_user", return_value=user_data()) args = { "remoteId": "1", "status": 1, "data": {}, "delta": {}, "incidentChanged": True, } investigation = {"lastOpen": "2021-05-12T00:00:00Z"} response = update_remote_system(client, investigation, args) client.reopen_alert.assert_called() assert response == "1" def test_ztap_get_alert_entries(mocker): client = get_test_client() mocker.patch.object(client, "get_alert", return_value=alert_data()) mocker.patch.object(client, "get_comments", return_value=comment_data()) mocker.patch.object(client, "get_active_user", return_value=user_data()) args = { "id": "1", } response = ztap_get_alert_entries(client, args) entries_json = json.dumps(response) entry_response = json.dumps(comment_entries()) assert entries_json == entry_response def test_user_to_display(): user = {"name": "User Name", "email": "test@test"} assert user_to_display(user) == "User Name (test@test)" user_only_email = {"email": "test@test"} assert user_to_display(user_only_email) == "test@test" user_only_name = {"name": "User Name"} assert user_to_display(user_only_name) == "User Name" user_unknown = {} assert user_to_display(user_unknown) == "Unknown"