Cisco Umbrella Enforcement
Add and remove domains in Cisco OpenDNS.
Network Security · Cisco Umbrella Enforcement
Details
| ID | Cisco Umbrella Enforcement |
|---|---|
| Provider | Cisco Systems |
| Category | Network Security |
| From Version | 5.0.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Supported Modules | Agentix XSIAM |
README
Add and remove domains in Cisco OpenDNS.
This integration was integrated and tested with version 1.0 of Cisco Umbrella Enforcement.
Supported Cortex XSOAR versions: 5.0.0 and later.
Configure Cisco Umbrella Enforcement in Cortex
| Parameter | Description | Required |
|---|---|---|
| url | Server URL (e.g., https://example.net) | True |
| api_key | API Key | True |
| insecure | Trust any certificate (not secure) | False |
| proxy | Use system proxy settings | 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.
umbrella-domain-event-add
Posts a malware event to the API for processing and optionally adding to a customer’s domain lists.
Base Command
umbrella-domain-event-add
Input
| Argument Name | Description | Required |
|---|---|---|
| alert_time | Alert time of the new event in datetime format, e.g., 2013-02-08T09:30:26.0Z. | Required |
| device_id | Device ID of the new event. | Required |
| destination_domain | Destination domain of the new event. | Required |
| destination_url | Destination URL of the new event. | Required |
| device_version | Device version for the new event. | Required |
| destination_ip | The destination IP address of the domain, specified in IPv4 dotted-decimal notation e.g., ‘8.8.8.8’. | Optional |
| event_severity | The partner threat level or rating, e.g., severe, bad, high, and so on. | Optional |
| event_type | Common name or classification of the threat. | Optional |
| event_description | Variant or other descriptor of the event type. | Optional |
| file_name | Path to the file exhibiting malicious behavior. | Optional |
| file_hash | SHA-1 of file reported by the appliance. | Optional |
| source | IP/Host of the infected computer/device that was patient 0 for the event. | Optional |
Context Output
There is no context output for this command.
Command Example
!umbrella-domain-event-add alert_time=2013-02-08T09:30:26.0Z device_id=ba6a58f4-e692-4724-ba36-c28132c761de destination_domain=test6.com device_version=13.7a destination_url=test6.com
Context Example
{}
Human Readable Output
New event was added successfully, The Event id is 31bb0adb,8f27,4423,a081-3b5773260f87.
umbrella-domains-list
List of domains.
Base Command
umbrella-domains-list
Input
| Argument Name | Description | Required |
|---|---|---|
| page | Number of page to return. Default is “1”. | Optional |
| limit | The maximum number of queries per page. Default is “50”. Default is 50. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| UmbrellaEnforcement.Domains.name | String | Name of the domains. |
| UmbrellaEnforcement.Domains.id | Number | ID of the domains. |
| UmbrellaEnforcement.Domains.IsDeleted | Boolean | True if the domain has been deleted from list. |
Command Example
#### Context Example
```json
{
"UmbrellaEnforcement": {
"Domains": [
{
"IsDeleted": false,
"id": 3569571,
"name": "test6.com"
},
{
"IsDeleted": false,
"id": 3790609,
"name": "test7.com"
},
{
"IsDeleted": false,
"id": 3912159,
"name": "test8.com"
},
{
"IsDeleted": false,
"id": 3912161,
"name": "test9.com"
},
{
"IsDeleted": false,
"id": 54637170,
"name": "badinterner4.com"
}
]
}
}
Human Readable Output
List of Domains
id name 3569571 test6.com 3790609 test7.com 3912159 test8.com 3912161 test9.com 54637170 badinterner4.com
umbrella-domain-delete
Delete domain.
Base Command
umbrella-domain-delete
Input
| Argument Name | Description | Required |
|---|---|---|
| id | ID of the domain. | Optional |
| name | Name of the domain. | Optional |
Context Output
There is no context output for this command.
Command Example
!umbrella-domain-delete name=test6.com
Context Example
{}
Human Readable Output
test6.com domain was removed from block list
Configuration parameters
url— Server URL (e.g., https://example.net) (required)api_key— API Keycred_api_key—insecure— Trust any certificate (not secure)proxy— Use system proxy settings
Commands (3)
-
umbrella-domain-deleteDelete domain.
-
umbrella-domain-event-addPosts a malware event to the API for processing and optionally adding to a customer's domain lists.
-
umbrella-domains-listList of domains.
import demistomock as demisto from CommonServerPython import * import urllib3 # Disable insecure warnings urllib3.disable_warnings() class Client(BaseClient): """ Client to use in the Cisco Umbrella Enforcement integration. Overrides BaseClient """ def __init__(self, base_url, verify, proxy, api_key): super().__init__(base_url=base_url, verify=verify, proxy=proxy, ok_codes=(200, 202, 204)) self.api_key = api_key def get_domains_list(self, page: str = "", limit: str = "") -> list: domains_list: list = [] response = self.get_domain_request( f"{self._base_url}domains?customerKey={self.api_key}&{prepare_suffix(page=page, limit=limit)}" ) limit = int(limit) while response and len(domains_list) < limit: response_data = response.get("data", []) for domain in response_data: domain.pop("lastSeenAt") domain["IsDeleted"] = False domains_list.append(domain) response_next_page = response.get("meta", {}).get("next", "") if response_next_page: response = self.get_domain_request(response_next_page) else: break return domains_list def get_domain_request(self, request: str): return self._http_request("GET", url_suffix="", full_url=request) def delete_domains(self, domain_name: str, domain_id: str): url_suffix = ( f"domains/{domain_id}?customerKey={self.api_key}" if domain_id else f"domains?customerKey={self.api_key}&where[name]={domain_name}" ) return self._http_request("DELETE", url_suffix, return_empty_response=True) def add_event_to_domain(self, event: dict): return self._http_request("POST", f"events?customerKey={self.api_key}", json_data=event, return_empty_response=True) def prepare_suffix(page: Optional[str] = "", limit: Optional[str] = "") -> str: """ Create the relevant suffix for the domains command, Either there is a complete request that should be sent or page and limit arguments. :param page: The number of the requested page for domains command. :param limit: The limit of the queries to return from the domains command. :return: (str) with the suffix. """ suffix = "" if page: suffix += f"page={page}&" if limit: suffix += f"limit={limit}&" return suffix def domains_list_command(client: Client, args: dict) -> CommandResults: """ :param client: Cisco Umbrella Client for the api request. :param args: args from the user for the command. """ page = args.get("page", "") limit = args.get("limit", "") response = client.get_domains_list(page=page, limit=limit) readable_output = tableToMarkdown(t=response, name="List of Domains", headers=["id", "name"]) return CommandResults( readable_output=readable_output, outputs_prefix="UmbrellaEnforcement.Domains", outputs_key_field="id", outputs=response ) def domain_event_add_command(client: Client, args: dict) -> str: """ :param client: Cisco Umbrella Client for the api request. :param args: args from the user for the command. :returns (str) confirmation or error regarding adding a new domain. """ alert_time = args.get("alert_time") device_id = args.get("device_id") dst_domain = args.get("destination_domain") dst_url = args.get("destination_url") device_version = args.get("device_version") destination_ip = args.get("destination_ip") event_severity = args.get("event_severity") event_type = args.get("event_type") event_description = args.get("event_description") file_name = args.get("file_name") file_hash = args.get("file_hash") source = args.get("source") new_event = { "alertTime": alert_time, "deviceId": device_id, "deviceVersion": device_version, "dstDomain": dst_domain, "dstUrl": dst_url, "eventTime": alert_time, "protocolVersion": "1.0a", "providerName": "Security Platform", "dstIP": destination_ip, "eventSeverity": event_severity, "eventType": event_type, "eventDescription": event_description, "fileName": file_name, "fileHash": file_hash, "src": source, } response: dict = client.add_event_to_domain(new_event) if id := str(response.get("id")): action_result = f"New event was added successfully, The Event id is {id}." else: action_result = "New event's addition failed." return action_result def domain_delete_command(client: Client, args: dict) -> CommandResults: """ :param client: Cisco Umbrella Client for the api request. :param args: args from the user for the command. :returns (str) confirmation or error regarding deleting a domain. """ response = {} domain_name = args.get("name", "") domain_id = args.get("id", "") if not domain_name and not domain_id: raise DemistoException( "Both domain name and domain id do not exist, Please supply one of them in order to set the domain to " "delete command" ) try: response = client.delete_domains(domain_id=domain_id, domain_name=domain_name) except Exception as e: # When deleting a domain by id and the id does not exist. if any(exp in str(e) for exp in ["Domain not in domain list", "Not Found"]): return CommandResults( readable_output="The domain was not found in the list, Please insert an existing domain name or id." ) if domain_name: curr_context = demisto.dt(demisto.context(), f'UmbrellaEnforcement.Domains(val.name == "{domain_name}")') else: curr_context = demisto.dt(demisto.context(), f'UmbrellaEnforcement.Domains(val.id == "{domain_id}")') if curr_context: if isinstance(curr_context, list): curr_context = curr_context[0] curr_context["IsDeleted"] = True if response and int(response.status_code) == 204: # type: ignore message = f"{domain_name if domain_name else domain_id} domain was removed from blacklist" else: # When deleting a domain by name, if name does not exist the returned code is 200 but the response is empty. message = f"{domain_name if domain_name else domain_id} domain not in the blacklist or Error" return CommandResults( readable_output=message, outputs_prefix="UmbrellaEnforcement.Domains", outputs_key_field="id", outputs=curr_context ) def test_module(client: Client) -> str: """ :param client: Cisco Umbrella Client for the api request. :return: 'ok' if there is a connection with the api and exception otherwise. """ client.get_domains_list(limit="1", page="1") return "ok" def main(): params = demisto.params() base_url = f"{params.get('url')}/1.0/" api_key = params.get("cred_api_key", {}).get("password") or params.get("api_key", None) if not api_key: raise DemistoException("API key must be provided.") verify = not params.get("insecure", False) proxy = params.get("proxy", False) command = demisto.command() commands = { "umbrella-domain-event-add": domain_event_add_command, "umbrella-domains-list": domains_list_command, "umbrella-domain-delete": domain_delete_command, } try: client = Client(base_url=base_url, api_key=api_key, verify=verify, proxy=proxy) if command == "test-module": return_results(test_module(client)) elif command in commands: return_results(commands[command](client, demisto.args())) else: raise NotImplementedError(f'Command "{command}" is not implemented.') except Exception as e: return_error(str(e)) if __name__ in ("__main__", "__builtin__", "builtins"): main()