Data management automation API
Splunk Phantom's Automation API allows security operations teams to develop detailed and precise automation strategies. Playbooks can serve many purposes, ranging from automating minimal investigative tasks that can speed up analysis to large-scale response to a security breach. The following APIs are supported to leverage the capabilities of the platform using Playbooks.
get_list
phantom.get_list(list_name=None, values=None, column_index=-1, trace=False)
'Custom Lists' are lists of dictionaries to allow users to manage data that can be referenced in Phantom Playbooks. These lists are available and accessible to the user to maintain in UI Playbooks / Custom Lists.
This API allows programmatic access to these 'Custom Lists' that the users may have defined and setup. For example, users may want to define a set of user names as 'executives' or a set of IP addresses as 'test machines'. In the context of containers (events) and artifacts, if the user is a member of the 'executives' list, then the course of action may be different or the severity may have to be altered using the 'set_severity' API explained elsewhere in the docs. Similarly if the IP address on which an event has been detected is a 'test machine' there may not be any reason to act. The result of this call is the full list as defined by the user.
Parameter | Required? | Type | Description |
---|---|---|---|
list_name | Required | str | The name of the custom list to retrieve. |
values | Optional | str | A value or a list of values to search, if not included the full list will be retrieved. |
column_index | Optional | int | Used to specify a specific column to retrieve. |
trace | Optional | bool | When set to True, more detailed output will be displayed in debug output. |
Here is an example of how to use the API:
import phantom.rules as phantom import json def on_start(container): #in the product in 'Playbooks / Custom Lists', define a # list called 'executives' and then access it here success, message, execs = phantom.get_list(list_name='executives') phantom.debug( 'phantom.get_list results: success: {}, message: {}, execs: {}'\ .format(success, message, execs) ) return def on_finish(container, summary): return
add_list
phantom.add_list(list_name=None, values=None)
Append a new row of data to the "Custom List" named by "list_name". If the list does not exist, it will be created. Values will be converted to a list of strings. On completion it returns a tuple of a success flag (bool) and any response message (str).
Parameter | Required? | Type | Description |
---|---|---|---|
list_name | Required | str | The name of the custom list to add an item to. |
values | Required | str | The values to be added, either a single value (str), or multiple (list of str). |
Here is an example of how to use the API:
import phantom.rules as phantom import json def on_start(container): #in the product in 'Playbooks / Custom Lists', define a # list called 'executives' and then access it here success, message = phantom.add_list( list_name='executives', values=[ 'bob.jones@splunk.com' ] ) phantom.debug( 'phantom.add_list results: success: {}, message: {}' \ .format(success, message) ) success, message = phantom.add_list( list_name='executives', values=[ 'susan.smith@splunk.com' ] ) phantom.debug( 'phantom.add_list results: success: {}, message: {}' \ .format(success, message) ) return def on_finish(container, summary): return
The above will add 2 rows to a 1-column list. First it adds Bob then it adds Susan.
remove_list
phantom.remove_list(list_name=None, empty_list=False, trace=False)
Delete a list. The list will no longer exist and not be available from the UI. When using the empty_list option, the list will still exist, but will be cleared of all values.
Parameter | Required? | Type | Description |
---|---|---|---|
list_name | Required | str | The name of the custom list to delete. |
empty_list | Optional | bool | Setting this to True will just clear out the list contents instead of completely removing the list. |
trace | Optional | bool | When set to True, more detailed output will be displayed in debug output. |
For this API you will need to give the automation user permissions to delete lists.
Here is an example of how to use the API:
import phantom.rules as phantom import json def on_start(container): phantom.debug('phantom.remove_list start') success, message = phantom.remove_list(list_name='example') phantom.debug( 'phantom.remove_list results: success: {}, message: {}'\ .format(success, message) ) return def on_finish(container, summary): return
set_list
phantom.set_list(list_name=None, values=None)
This API provides the ability to replace the entire contents of a list. This API returns a tuple of a success flag (bool) and any response message (str).
Parameter | Required? | Type | Description |
---|---|---|---|
list_name | Required | str | The name of the custom list to modify. |
values | Required | list of lists | The values to set. |
Here is an example of how to use the API:
import phantom.rules as phantom import json def on_start(container): #in the product in 'Playbooks / Custom Lists', define a # list called 'example' with two rows. Creates the list if it does not exist. success, message = phantom.set_list( list_name='example', values=[ ['a', 'list', 'of', 'values'], ['second', 'row'] ]) phantom.debug( 'phantom.set_list results: success: {}, message: {}'\ .format(success, message) ) return def on_finish(container, summary): return
check_list
phantom.check_list(list_name=None, value=None, case_sensitive=False, substring=False)
This API allows users to check whether a value is in a custom list or does not appear in any column. The default behavior (case_sensitive=False) is case insensitive and to search complete strings (substring=False). It returns a tuple of a success flag (bool), any response message, and the number of matching rows in the custom list (int).
Parameter | Required? | Type | Description |
---|---|---|---|
list_name | Required | string | The name of the custom list to search through. |
value | Required | string | The value that should be searched. |
case_sensitive | Optional | boolean | Default behavior is case insensitive but can be changed with this option. |
substring | Optional | boolean | Default behavior is complete string match, but can be changed with this option. |
Example:
import phantom.rules as phantom def on_start(container): phantom.debug('phantom.check_list start') success, message, matched_row_count = \ phantom.check_list(list_name='Example List', value='Example Value') phantom.debug( 'phantom.check_list results: success: {}, message: {}, matched_row_count: {}'\ .format(success, message, matched_row_count) ) return def on_finish(container, summary): return
delete_from_list
phantom.delete_from_list(list_name=None, value=None, column=None, remove_all=False, remove_row=False)
This API provides the ability to remove rows from a list that contain a specific value. This API returns a tuple of a success flag (bool) and any response message (str).
Parameter | Required? | Type | Description |
---|---|---|---|
list_name | Required | str | The name of the custom list to modify. |
value | Required | str | Will replace cells containing the value with None. |
column | Optional | positive int | Zero based index, only check for value in this column. |
remove_all | Optional | boolean | If True, replace all occurrences of value with None. Otherwise the API will fail if multiple are found. |
remove_row | Optional | boolean | If True, remove the full row where an occurrence of value was found. |
Here is an example of how to use the API:
import phantom.rules as phantom import json def on_start(container): #in the product in 'Playbooks / Custom Lists', define a # list called 'example' with two rows. Creates the list if it does not exist. success, message = phantom.delete_from_list( list_name='example', value='deleteme') phantom.debug( 'phantom.delete_from_list results: success: {}, message: {}'\ .format(success, message) ) return def on_finish(container, summary): return
NOTE: It is not possible to delete all rows from the list, and phantom.delete_from_list commands that attempt to do so will result in an error. At least one row must be present in the list.
get_run_data
phantom.get_run_data(key=None)
This API returns the data value saved for the specified 'key' via the phantom.save_run_data() method. If 'key' is not specified, this API returns data for all the keys as a string object.
Sample result data if a key is not specified when calling get_run_data:
{ "specified_key_on_save_run_data_call" : { "auto_" : true, "data_" : "specified value on save run data call with key provided" }, "ef106ce1-301d-490d-9b96-d16b7e3a1a85" : { "auto_" : true, "data_" : "specified value on save run data call without key provided" } }
save_run_data
phantom.save_run_data(value=None, key=None, auto=True)
This API saves the 'value' in a 'key' only in the context of the playbook run/execution. 'key' and 'value' are string objects. This data is automatically deleted when the playbook execution completes unless the 'auto' parameter is set to False.
get_object
phantom.get_object(key=None, clear_data=False, container_id=None, playbook_name=None, repo_name=None)
This API retrieves data that was saved via the save_object API.
NOTE: Please see the save_object() API for sample playbook and usage of this API.
Parameter | Required? | Description |
---|---|---|
key | Required | The key specified in the save_object() API used when saving data. |
clear_data | Optional | If set True, clears the data after fetching. Defaults to False. |
container_id | Optional, unless playbook_name is not specified. Can also be specified with a playbook_name . |
The container id specified when the data was saved. |
playbook_name | Optional, unless container_id is not specified. Can also be specified with a container_id |
The playbook name as specified when the data was saved. |
repo_name | Optional | The repo name as specified when saving the data in the save_object API call |
The key
parameter supports Postgres LIKE patterns. If pattern does not contain percent signs or underscores, then the pattern only represents the string itself; in that case LIKE acts like the equals operator. An underscore (_) in pattern stands for (matches) any single character; a percent sign (%) matches any sequence of zero or more characters.
The return value is a list of dictionaries where each dictionary has search criteria and the value for the specified combination of parameters.
Sample result data:
[ { "composite_key": { "container_id": <>, "playbook_name": <>, "key": <> }, "value": {<> } } ]
save_object
phantom.save_object(key=None, value=None, container_id=None, auto_delete=False, playbook_name=None, repo_name=None)
This API allows you to save data by key and/or container_id and/or playbook name, to be retrieved when executing playbooks on containers. Users can save a key and value pair along with the context of container id and/or playbook name.
NOTE: Only JSON compliant objects, dictionaries, lists, strings and numbers are supported as objects that can be saved and retrieved.
Parameter | Required? | Description |
---|---|---|
key | Required | Specify to save and retrieve data by this unique key. |
value | Required | The data to be saved. This is expected to be a Python dictionary object. |
container_id | Optional, unless a playbook_name is not specified. |
This is the container_id as a context to the data being saved. Must be provided if auto_delete is True.
|
auto_delete | Optional | Defaults to False. If set True, the data will be deleted when the container is closed. The clear_object can be used to delete the data. If set True, container_id must be provided.
|
playbook_name | Optional, unless a container_id is not provided. |
The playbook name which is also saved as context to the data. |
repo_name | Optional | It is recommended to specify the repo_name when a playbook name is provided, since a particular playbook may exist in more than one repo. |
Sample playbook:
import phantom.rules as phantom import json from datetime import datetime, timedelta def on_start(container): phantom.debug('on_start() called {}'.format(container)) pb_info = phantom.get_playbook_info() phantom.debug(pb_info) if not pb_info: return playbook_name = pb_info[0].get('name', None) container_id = container['id'] # SAVE data with key, container id and Playbook name phantom.save_object(key="key1", value={'value':'key 1 data for container and playbook'}, auto_delete=True, container_id = container_id, playbook_name=playbook_name) phantom.save_object(key="key2", value={'value':'key 2 data for container and playbook'}, auto_delete=True, container_id = container_id, playbook_name=playbook_name) # SAVE data with key, container id but NO Playbook name phantom.save_object(key="key1", value={'value':'key 1 data for only container and NO playbook'}, auto_delete=True, container_id = container_id) # SAVE data with key, Playbook name and NO container id phantom.save_object(key="key1", value={'value':'key 1 data for only playbook and not container'}, auto_delete=False, playbook_name=playbook_name) my_key = "key1" data = phantom.get_object(key=my_key, container_id = container_id, playbook_name=playbook_name) phantom.debug("get by key, container_id and playbook name: {} records found".format(len(data))) phantom.debug(data) data = phantom.get_object(key=my_key, container_id = container_id) phantom.debug("get by key, and container_id and NO playbook name: {} records found".format(len(data))) phantom.debug(data) data = phantom.get_object(key=my_key, playbook_name=playbook_name) phantom.debug("get by key, and playbook name and no container id: {} records found".format(len(data))) phantom.debug(data) data = phantom.get_object(key=my_key, playbook_name="%%") phantom.debug("get by key, and ALL playbook name and no container id: {} records found".format(len(data))) phantom.debug(data) data = phantom.get_object(key="%%", container_id = container_id) phantom.debug("get for ALL key, and container_id and no playbook name: {} records found".format(len(data))) phantom.debug(data) data = phantom.get_object(key="%%", container_id = container_id, playbook_name=playbook_name) phantom.debug("get for ALL key, and container_id and playbook name: {} records found".format(len(data))) phantom.debug(data) # TESTING CLEAR API data = phantom.get_object(key="key1", container_id = container_id, playbook_name=playbook_name) phantom.debug("BEFORE clear ... get for key1, and container_id and playbook name: {} records found".format(len(data))) phantom.debug(data) phantom.clear_object(key="key1", container_id = container_id, playbook_name=playbook_name) data = phantom.get_object(key="key1", container_id = container_id, playbook_name=playbook_name) phantom.debug("AFTER clear ... get for key1, and container_id and playbook name: {} records found".format(len(data))) phantom.debug(data) return def on_finish(container, summary): phantom.debug('on_finish() called') return
The output of the above playbook in debugger shows the following results:
Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): Starting playbook 'local/automation_data' (id: 112, version: 35) on 'incident'(id: 10) with playbook run id: 72 Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): calling on_start() on incident 'CryptoLocker Ransomware Infection (new, SLA breached) (192.168.1.41)'(id: 10). Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): on_start() called {'sensitivity': 'amber', 'create_time': '2017-03-23 03:54:12.981519+00', 'owner': 'bob.tailor@splunk.com', 'id': 10, 'close_time': '', 'severity': 'high', 'label': 'incident', 'due_time': '2017-03-18 21:34:47.217516+00', 'version': '1', 'current_rule_run_id': 72, 'status': 'new', 'owner_name': '', 'hash': 'f407a85b849baecdb34d27da1e1431dc', 'description': 'CryptoLocker has been detected on finance system 192.168.1.41 running on ESXi server 192.168.1.40', 'tags': [], 'start_time': '2014-09-04 14:40:33+00', 'asset_name': 'qradar_entr', 'artifact_update_time': '2017-03-23 03:54:15.990076+00', 'container_update_time': '', 'kill_chain': '', 'name': 'CryptoLocker Ransomware Infection (new, SLA breached) (192.168.1.41)', 'ingest_app_id': '', 'source_data_identifier': '45', 'end_time': '', 'artifact_count': 2} Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): [ { "parent_playbook_run_id": "0", "name": "automation_data", "run_id": "72", "scope_artifacts": [], "scope": "new", "id": "112", "repo_name": "local" } ] Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): save_object() called:key=key1,auto_delete=True,container_id=10,playbook_name=automation_data,repo_name=None Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): save_object() called:key=key2,auto_delete=True,container_id=10,playbook_name=automation_data,repo_name=None Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): save_object() called:key=key1,auto_delete=True,container_id=10,playbook_name=None,repo_name=None Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): save_object() called:key=key1,auto_delete=False,container_id=None,playbook_name=automation_data,repo_name=None Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): get_object() called:key=key1, clear_data=False,container_id=10,playbook_name=automation_data,repo_name=None Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): get by key, container_id and playbook name: 1 records found Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): [ { "composite_key": { "container_id": 10, "playbook_name": "automation_data", "key": "key1" }, "value": { "value": "key 1 data for container and playbook" } } ] Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): get_object() called:key=key1, clear_data=False,container_id=10,playbook_name=None,repo_name=None Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): get by key, and container_id and NO playbook name: 1 records found Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): [ { "composite_key": { "container_id": 10, "playbook_name": "", "key": "key1" }, "value": { "value": "key 1 data for only container and NO playbook" } } ] Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): get_object() called:key=key1, clear_data=False,container_id=None,playbook_name=automation_data,repo_name=None Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): get by key, and playbook name and no container id: 1 records found Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): [ { "composite_key": { "container_id": 0, "playbook_name": "automation_data", "key": "key1" }, "value": { "value": "key 1 data for only playbook and not container" } } ] Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): get_object() called:key=key1, clear_data=False,container_id=None,playbook_name=%%,repo_name=None Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): get by key, and ALL playbook name and no container id: 1 records found Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): [ { "composite_key": { "container_id": 0, "playbook_name": "automation_data", "key": "key1" }, "value": { "value": "key 1 data for only playbook and not container" } } ] Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): get_object() called:key=%%, clear_data=False,container_id=10,playbook_name=None,repo_name=None Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): get for ALL key, and container_id and no playbook name: 1 records found Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): [ { "composite_key": { "container_id": 10, "playbook_name": "", "key": "key1" }, "value": { "value": "key 1 data for only container and NO playbook" } } ] Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): get_object() called:key=%%, clear_data=False,container_id=10,playbook_name=automation_data,repo_name=None Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): get for ALL key, and container_id and playbook name: 2 records found Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): [ { "composite_key": { "container_id": 10, "playbook_name": "automation_data", "key": "key2" }, "value": { "value": "key 2 data for container and playbook" } }, { "composite_key": { "container_id": 10, "playbook_name": "automation_data", "key": "key1" }, "value": { "value": "key 1 data for container and playbook" } } ] Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): get_object() called:key=key1, clear_data=False,container_id=10,playbook_name=automation_data,repo_name=None Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): BEFORE clear ... get for key1, and container_id and playbook name: 1 records found Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): [ { "composite_key": { "container_id": 10, "playbook_name": "automation_data", "key": "key1" }, "value": { "value": "key 1 data for container and playbook" } } ] Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): clear_object() called:key=key1,container_id=10,playbook_name=automation_data,repo_name=None Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): get_object() called:key=key1, clear_data=False,container_id=10,playbook_name=automation_data,repo_name=None Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): AFTER clear ... get for key1, and container_id and playbook name: 0 records found Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): [] Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): No actions were executed Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): Playbook 'automation_data' (playbook id: 112) executed (playbook run id: 72) on incident 'CryptoLocker Ransomware Infection (new, SLA breached) (192.168.1.41)'(container id: 10). Playbook execution status is 'success' Total actions executed: 0 Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): on_finish() called Fri Mar 24 2017 07:13:08 GMT-0700 (PDT): {"message":"No actions were executed","playbook_run_id":72,"result":[],"status":"success"}
WARNING: If auto_delete is False or no container id is provided or container is NOT closed, the data will not be deleted and can waste space.
clear_object
phantom.clear_object(key=None, container_id=None, playbook_name=None, repo_name=None)
This is an API that allows you to delete data saved via the save_object() API.
Parameter | Required? | Description |
---|---|---|
key | Required | The key parameter that was used in save_object() API |
container_id | Optional, unless playbook_name is not provided. Can also be use together with a playbook_name . |
The same container_id parameter that was used in save_object() API. |
playbook_name | Optional, unless playbook_name is not provided. Can also be use together with a playbook_name . |
The same playbook_name parameter that was used in save_object() API. |
repo_name | Optional | The same repo_name parameter that was used in save_object() API. |
The container_id
and playbook_name
parameters support Postgres LIKE patterns. If pattern does not contain percent signs or underscores, then the pattern only represents the string itself; in that case LIKE acts like the equals operator. An underscore (_) in pattern stands for (matches) any single character; a percent sign (%) matches any sequence of zero or more characters.
Container automation API | Data access automation API |
This documentation applies to the following versions of Splunk® Phantom (Legacy): 4.8
Feedback submitted, thanks!