Details
| ID | iot-security-get-raci |
|---|---|
| Language | python |
| From Version | 5.0.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Tags | iot |
README
IoT RACI model script
Script Data
| Name | Description |
|---|---|
| Script Type | python3 |
| Tags | iot |
| Cortex XSOAR Version | 5.5.0 |
This script is using the device and incident attributes to evaluate the Responsible (R) and Informed (I) parties in the RACI model.
A list variable needs to be created with a fixed format JSON. You can create a new XSOAR list variable under Settings > Advanced > Lists.
By default, the name of the list variable is IOT_CONFIG.
There are three main sections in the JSON: devices, alerts, and groups.
| “devices” is a list of devices mapping to the owners based on the device_id, which is a concatenation of the device’s category, profile, vendor and model delimited by “ | ”. |
- device_id: a regular expression to match
- owner: a group name, which is also defined in the “groups” section
“alerts” is a list of conditions to map a combination of IoT incident type and incident names to the RACI model.
- iot_raw_type: either “IoT Alert” or “IoT Vulnerability”
- name_regex: a list of regular expressions trying to match with the alert/vulnerability names
- raci: a section to define the RACI model for the match. If the value is “IOT_OWNER”, we look up the underlying group using the mapping in “devices” section.
“groups” is all the groups found in the “devices” and “alerts” section.
- email: the email of the group, this is used when setting the incident owner in XSOAR or sending an email through the email integration
- snow: it has three fields, table, fields and custom_fields. Those are the fields when you use the official ServiceNow integration when you create a ServiceNow ticket.
Here is the template of the JSON:
{
"devices": [
{
"device_id": "Audio Streaming|Profusion.*",
"owner": "IT_AUDIO_VIDEO"
},
{
"device_id": "Camera|Avigilon Camera.*",
"owner": "PHYSICAL_SECURITY"
}
],
"alerts": [
{
"iot_raw_type": "IoT Alert",
"name_regex": [
"DOUBLEPULSAR.+",
"ECLIPSEDWING.+",
"ETERNALBLUE.+"
],
"raci": {
"r": "SOC",
"i": ["IOT_OWNER"]
}
},
{
"iot_raw_type": "IoT Vulnerability",
"raci": {
"r": "IOT_OWNER",
"i": ["INFOSEC", "SOC"]
}
}
],
"groups": {
"DEFAULT": {
"email": "default@example.com"
},
"SOC": {
"email": "soc@example.com"
},
"INFOSEC": {
"email": "infosec@example.com"
},
"IT_AUDIO_VIDEO": {
"email": "av@example.com",
"snow": {
"table": "incident",
"fields": {
"assignment_group": "98dae8874fd67348bf547fe24210c7a0"
},
"custom_fields": {
"u_custom_field1": "IT",
"u_category": "05b9e5371b3b08905f28fc43cd4bcbe2"
}
}
},
"PHYSICAL_SECURITY": {
"email": "security@example.com"
}
}
}
Used In
This script is used in the following playbooks and scripts.
- PANW IoT Incident Handling with ServiceNow
Inputs
| Argument Name | Description |
|---|---|
| alert_name | The name of the IoT alert. |
| raw_type | The raw type of the incident. |
| category | The device category. |
| profile | The device profile. |
| vendor | The device vendor. |
| model | The device model. |
| iot_config_list_name | The variable name for IOT_CONFIG. |
Outputs
| Path | Description | Type |
|---|---|---|
| PaloAltoNetworksIoT.RACI | The RACI model of the IoT incident | unknown |
| PaloAltoNetworksIoT.RACI.r | The responsible in the RACI model | string |
| PaloAltoNetworksIoT.RACI.r_email | The email of responsible in the RACI model | string |
| PaloAltoNetworksIoT.RACI.i | The informed in the RACI model | string |
| PaloAltoNetworksIoT.RACI.i_email | The emails of informed in the RACI model delimited by comma | string |
| PaloAltoNetworksIoT.RACI.owner | The IoT owner of the device | string |
| PaloAltoNetworksIoT.RACI.r_snow | The ServiceNow information of the incident responsible | string |
| PaloAltoNetworksIoT.RACI.r_snow.fields | The fields of the ServiceNow ticket | string |
| PaloAltoNetworksIoT.RACI.r_snow.custom_fields | The custom fields of the ServiceNow ticket | string |
| PaloAltoNetworksIoT.RACI.r_snow.table | The table of the ServiceNow ticket | string |
import json import re import demistomock as demisto # noqa: F401 from CommonServerPython import * # noqa: F401 from CommonServerUserPython import * # noqa: E402 lgtm [py/polluting-import] def get_iot_config(iot_config_list_name="IOT_CONFIG"): iot_config = demisto.executeCommand("getList", {"listName": iot_config_list_name}) if is_error(iot_config): return None iot_config_content = iot_config[0]["Contents"] try: return json.loads(iot_config_content) except Exception as e: return_error(f"Failed to parse the IOT_CONFIG. Error: {e!s}") def get_raci(args): alert_name = args.get("alert_name", "") alert_type = args.get("raw_type") category = args.get("category", "") profile = args.get("profile", "") vendor = args.get("vendor", "") model = args.get("model", "") device_id = f"{category}|{profile}|{vendor}|{model}" iot_config_list_name = args.get("iot_config_list_name", "IOT_CONFIG") config = get_iot_config(iot_config_list_name) if config is None: return None result = {} # determine owner owner = None for d in config.get("devices", []): if "device_id" in d and "owner" in d and re.match(d["device_id"], device_id): owner = d["owner"] result["owner"] = owner # determine raci raci = None for a in config.get("alerts", []): if "iot_raw_type" in a and "raci" in a and alert_type == a["iot_raw_type"]: match_name = "name_regex" not in a if not match_name: for n in a["name_regex"]: if re.match(n, alert_name): match_name = True break if match_name: raci = a["raci"] if raci: r = raci["r"] if r == "IOT_OWNER": result["r"] = owner if owner is None: result["r_email"] = None result["r_snow"] = None else: e = config.get("groups", {}).get(owner, {}).get("email", None) if e is None: default_email = config.get("groups", {}).get("DEFAULT", {}).get("email", None) if default_email is not None: result["r_email"] = default_email else: result["r_email"] = None else: result["r_email"] = e result["r_snow"] = config.get("groups", {}).get(owner, {}).get("snow", None) elif r is not None: result["r"] = r e = config.get("groups", {}).get(r, {}).get("email", None) if e is None: default_email = config.get("groups", {}).get("DEFAULT", {}).get("email", None) if default_email is not None: result["r_email"] = default_email else: result["r_email"] = None else: result["r_email"] = e result["r_snow"] = config.get("groups", {}).get(r, {}).get("snow", None) else: result["r_email"] = None result["r_snow"] = None r_snow = result.get("r_snow", {}) if r_snow: fields = r_snow.get("fields", {}) if fields: r_snow["fields"] = ";".join([f"{k}={v}" for k, v in fields.items()]) cfields = r_snow.get("custom_fields", {}) if cfields: r_snow["custom_fields"] = ";".join([f"{k}={v}" for k, v in cfields.items()]) i = [] for inform in raci["i"]: if inform == "IOT_OWNER": if owner is not None: i.append(owner) else: i.append(inform) result["i"] = ", ".join(i) if i else None if i: i_email = [] for entry in i: e = config.get("groups", {}).get(entry, {}).get("email", None) if e is None: default_email = config.get("groups", {}).get("DEFAULT", {}).get("email", None) if default_email is not None: i_email.append(default_email) else: i_email.append(e) if len(i_email) > 0: result["i_email"] = ", ".join(i_email) else: result["i_email"] = None else: result["r"] = None result["r_email"] = None result["r_snow"] = None result["i"] = None result["i_email"] = None return CommandResults(outputs_prefix="PaloAltoNetworksIoT.RACI", outputs_key_field="", outputs=result) def main(): try: return_results(get_raci(demisto.args())) except Exception as ex: return_error(f"Failed to execute iot-security-get-raci. Error: {ex!s}") if __name__ in ("__main__", "__builtin__", "builtins"): main()