Resilient IRP Custom Action Developer Guide

Resilient%20IRP%20Custom%20Action%20Developer%20Guide

User Manual:

Open the PDF directly: View PDF PDF.
Page Count: 47

DownloadResilient IRP Custom Action Developer Guide
Open PDF In BrowserView PDF
Incident Response Platform
CUSTOM ACTION DEVELOPER’S GUIDE v1.2

Custom Action Developer’s Guide

Resilient Incident Response Platform

Licensed Materials – Property of IBM
© Copyright IBM Corp. 2010, 2019. All Rights Reserved.
US Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule
Contract with IBM Corp.

Resilient Incident Response Platform Custom Action Developer’s Guide
Platform
Version
1.2
1.1
1.0

Publication
January 2019
October 2018
July 2018

Notes
Updated information about the integration server.
Documented Resilient Circuits V31 commands.
Initial release.

Page 2

Custom Action Developer’s Guide

Resilient Incident Response Platform

Table of Contents
1.

Objective .............................................................................................................................................. 5

2.

Overview .............................................................................................................................................. 6
2.1.

Integration Architecture ................................................................................................................ 6

2.2.

Resilient Platform Playbook ......................................................................................................... 7

2.3.

Custom Actions ............................................................................................................................ 8

2.4.

Integration Toolkit ........................................................................................................................ 9

2.5.

Development Overview ................................................................................................................ 9

2.6.

Developer Website......................................................................................................................10

3.

Prerequisites .......................................................................................................................................11

4.

Configuring Resilient Circuits ...........................................................................................................12
4.1.

Install Integrations .......................................................................................................................12

4.2.

Edit the Configuration File ...........................................................................................................12

4.3.

Pull Configuration Values ............................................................................................................14

4.4.

Add Values to Keystore ..............................................................................................................14

4.5.

Run Resilient Circuits..................................................................................................................14
Run Multiple Instances ...........................................................................................................14
Monitor Config File for Changes .............................................................................................15
Override Configuration Values ................................................................................................15

4.6.

Run as a Service.........................................................................................................................16
Systemd on RHEL ..................................................................................................................16
Windows .................................................................................................................................17

5.

Developing Using Resilient Circuits .................................................................................................18
5.1.

Get Started .................................................................................................................................18

5.2.

Create the Resilient Platform Components .................................................................................18

5.3.

Write the Action Processor .........................................................................................................20

5.4.

Run the Action Processor ...........................................................................................................21

5.5.

Run during Development ............................................................................................................23

5.6.

Add Functionality with Decorators...............................................................................................24

5.7.

Long-Running Actions.................................................................................................................26

5.8.

Web UI and RESTful Components .............................................................................................27

5.9.

Package the Integration ..............................................................................................................27

5.10.

Test the Integration .....................................................................................................................28
res-action-test .........................................................................................................................28
Write and Run Tests Using pytest ..........................................................................................29
Run Tests with tox ..................................................................................................................30
Mock Resilient API..................................................................................................................31

5.11.
6.

Publish Your Function .................................................................................................................31

Developing Using the API ..................................................................................................................32

Page 3

Custom Action Developer’s Guide

Resilient Incident Response Platform

7.

6.1.

User Authentication/Authorization ...............................................................................................32

6.2.

Message Destination and Org Prefix ..........................................................................................33

6.3.

Menu Item Rules and Activity Fields ...........................................................................................34

6.4.

Action Data .................................................................................................................................36

6.5.

Action Data and Type Information...............................................................................................37

6.6.

Message Headers .......................................................................................................................37

6.7.

Acknowledgements .....................................................................................................................38

6.8.

TLS .............................................................................................................................................39

6.9.

Resilient REST API with Action Processors ................................................................................40

6.10.

HTTP Conflict (409) Errors .........................................................................................................40

6.11.

Using a Framework .....................................................................................................................41

6.12.

Always Running ..........................................................................................................................41

6.13.

Retry ...........................................................................................................................................42

6.14.

Processor Installation ..................................................................................................................42

6.15.

Testing Considerations ...............................................................................................................42

6.16.

Example: Creating an Incident ....................................................................................................44

JSON Structures in the Resilient API ...............................................................................................45
7.1.

Basics .........................................................................................................................................45

7.2.

Data Types .................................................................................................................................46

7.3.

Other values................................................................................................................................46
Rich Text ................................................................................................................................46
Object Handles .......................................................................................................................47
Structured Values and Custom Fields ....................................................................................47

Page 4

Custom Action Developer’s Guide

Resilient Incident Response Platform

1. Objective
This guide provides the information to integrate the Resilient Incident Response Platform with
your organization’s existing security and IT investments. Integrations makes security alerts
instantly actionable, provides valuable intelligence and incident context, and enables adaptive
response to complex cyber threats.
This guide is intended for programmers, testers, architects and technical managers interested in
developing and testing integrations with the Resilient platform. It assumes a general
understanding of the Resilient platform, message-oriented middleware (MOM) systems, and a
knowledge of writing scripts.

Page 5

Custom Action Developer’s Guide

Resilient Incident Response Platform

2. Overview
A custom action is a type of integration that allows the Resilient platform to send a snapshot of
the incident data automatically to external code, which can then act upon the data to perform
integration work, and, optionally, send data to the Resilient platform.
You should familiarize yourself with the Resilient architecture and the relevant Resilient features,
as described in the following sections, before designing and writing custom action integrations.

2.1. Integration Architecture
The Resilient platform has a full-featured REST API that sends and receives JSON formatted
data. It has complete access to almost all Resilient features, including but not limited to; creating
and updating incidents and tasks, managing users and groups, and creating artifacts and
attachments. To access the API Reference guide, including schemas for all of the JSON sent and
received by the API, log into the Resilient platform, click on your account name at the top right
and select Help/Contact. For information on how JSON is used in the Resilient API, see the
JSON Structures in the Resilient API section in this guide.
To integrate your system, your Resilient platform must subscribe to the Action Module. This is an
extension to the Resilient platform that allows implementation of custom behaviors beyond what
is possible in the Resilient internal scripting feature. It is built on Apache ActiveMQ. The STOMP
message protocol is used for Python based integrations. Custom actions are triggered by adding
a message destination to a rule defined in the Resilient platform and subscribing your integration
code to that message destination.
The following diagram shows the relationship between the integration component, REST API,
Action Module and Resilient platform.

Page 6

Custom Action Developer’s Guide

Resilient Incident Response Platform

2.2. Resilient Platform Playbook
The Resilient Incident Response Platform is a central hub for incident responses. It is
customizable so that it can be tailored to meet the needs of your company or organization. The
focus of these customizations is the dynamic playbook, which is the set of rules, conditions,
business logic, workflows and tasks used to respond to an incident. The playbook updates the
response automatically as the incident progresses and is modified.
You should be familiar with your organization’s customized Resilient playbook when designing an
integration. In particular, you should be familiar with the following playbook components:


Rule. A set of conditional statements that identify relationships and run responses
accordingly. Rules define a set of activities that are triggered when conditions are met.
Activities include setting incident field values, inserting tasks into the task list, launching
workflows, and running internal scripts to implement business logic.



Workflow. A graphically designed set of activities that allows you to create a complex set of
operations. You can use workflows to implement sophisticated business processes that can
be invoked by rules. Workflows can contain various components, such as scripts and
functions.



Message destination. The location where data is posted and made accessible to remote
programs. The message includes details about an object and the activity taken. You can
configure rules, workflows and functions to send messages to one or more message
destinations.



Custom field. Design element used in incident layouts to capture specific data. You can
design your custom actions so that your integrated system can populate a custom field.



Data table. Design element that organizes data in a tabular format. You can design your
custom actions so that your integrated system can populate the table.

For more information about the Resilient platform and dynamic playbooks, refer to the Resilient
Incident Response Platform Playbook Designer Guide.

Page 7

Custom Action Developer’s Guide

Resilient Incident Response Platform

2.3. Custom Actions
Custom action is a type of integration that allows the Resilient platform to send a snapshot of the
incident data automatically to external code, called action processors. This external code can
then perform integration work, for example:


Perform a lookup for information about a user or machine in an asset database then update a
Resilient data table with the result.



Search SIEM logs for additional information related to an IP address, a URL or a server
name, create a file with the result, and add the file as an artifact to a Resilient incident.



Use information from the incident, task or artifact to open a ticket in an ITSM system, then
track the ticket for updates.

When a Resilient rule or workflow fires, it sends data about its object to a message destination.
The action processor retrieves that message, acts on it, and updates the Resilient platform with
the result.

Page 8

Custom Action Developer’s Guide

Resilient Incident Response Platform

2.4. Integration Toolkit
The Resilient platform provides a number of tools to assist with integrations:


Resilient Circuits. A Python circuits framework that automatically manages authenticating and
connecting to the STOMP connection and REST API in the Resilient platform. It simplifies
creating custom integrations by allowing you to focus on writing the behavior logic. It is the
preferred method for writing integrations.
You can also use Resilient Circuits to manage your integrations. Each integration has its own
section in the app config file. This file stores information about the Resilient platform, such as
user credentials, as well as variables for your integrations.



Resilient helper module. A Python library to facilitate easy use of the Rest API. It is used with
Resilient Circuits.



Interactive Rest API browser. Allows you to access the Resilient REST API and try out any
endpoint on the system. When logged into the Resilient platform, click on your account name
at the top right and select Help/Contact. Here you can access the complete API Reference
guide, including schemas for all of the JSON sent and received by the API, and the
interactive Rest API.

For information about JSON structures used in the Resilient API, see JSON Structures in the
Resilient API later in this guide.
The Resilient Circuits framework makes it simple to develop and deploy action processors using
Python. When using the Resilient Circuits framework, the action processor component is a
Python class that implements message handlers. These handlers are called by the framework
when an action message arrives on a message destination.
If you wish to create your custom actions in another language, you can use the API directly
instead of using Resilient Circuits.

2.5. Development Overview
The following list provides a high-level overview of the development process. The subsequent
sections in this guide provide the details.


Before you write a custom action processor, you must understand its purpose, the data it
needs from the Resilient platform, and the actions or decisions to be made based on the
results.



Determine whether to use Resilient Circuits. If writing in Python, this is the preferred method
and the Resilient Circuits framework can simplify your development.



If using Resilient Circuits, install and configure Resilient Circuits and the Resilient helper
module on your integration system, if not already installed.



At the Resilient platform (preferably in a test environment), define and implement the
message destination and other components, such as rules, workflows, or both.



Write the action processor, which includes your integration code. If you have access to
integrations that are similar to the one you wish to create, use that integration as a template
to save time.



Test the integration by triggering the workflow and checking the results.



Package your integration and make it available for deployment to the Resilient platform in
your production environment.

Page 9

Custom Action Developer’s Guide

Resilient Incident Response Platform

2.6. Developer Website
The Resilient developer web site contains the core Resilient helper module and Resilient Circuit
packages, additional integration packages, documentation and examples. The links are provided
below.


Resilient Success Hub. If you have not already, use this link to request access to the other
Resilient web locations.



IBM Resilient Developer website. Provides overview information and access to various areas
of development, such as developing playbooks and publishing integrations.



IBM Resilient Github. Provides access to library modules, community-provided extensions,
example scripts, and developer documentation. It also contains the Resilient Circuits and
helper module packages. This is also accessible from the developer website reference page.



IBM X-Force App Exchange. Provides access to the Resilient community apps on IBM XForce.



Releases. Lists the apps by Resilient Incident Response Platform release. You can also
download from this page.

Page 10

Custom Action Developer’s Guide

Resilient Incident Response Platform

3. Prerequisites
Before starting, make sure your environment meets the following prerequisites:


Resilient platform V29 or later (preferably in a test environment) with the Resilient Action
Module.



A dedicated Resilient account to use as the API user. In most integrations, the account must
have the permission to view and edit incidents, and view and modify administrator and
customization settings. You need to know the account username and password.



If using Resilient Circuits, a Resilient integration server where you deploy and run the
functions code. See the Integration Server Guide for the information to install and configure
the server.

IBM Resilient recommends that you use a Resilient platform in a test environment to create the
function, message destination, rules, workflows and other components needed for your
integration. Once tested, you can deploy the integration into any Resilient platform that is at the
same or later version as your test platform.

Page 11

Custom Action Developer’s Guide

Resilient Incident Response Platform

4. Configuring Resilient Circuits
This section assumes that Resilient Circuits is installed and configured on the integration server,
as described in the Integration Server Guide.

4.1. Install Integrations
Perform the following procedure to install a new app on the integration server. The app can be
one you have written or an app downloaded from the IBM Resilient Community App Exchange.
1. Use ssh to connect to your integration server.
2. Go to the folder where the installers are located.
3. Install your chosen component using the following command:
pip install -x.x.x.tar.gz

4. Verify that the component installed using the resilient-circuits list command.
resilient-circuits list

5. If you downloaded an app from the App Exchange, follow the instructions in the component’s
readme file to configure the component.

4.2. Edit the Configuration File
The [resilient] section of the configuration file controls how the core Resilient Circuits and
Resilient packages access the Resilient platform.
Open the configuration file in the text editor of your choice then update the [resilient] section with
your Resilient system hostname/IP and credentials and the absolute path to the logs directory
you created. The following table describes all the required and optional values that can be
included in this section.
NOTE: If on a Windows system and you edit the file with Notepad, please ensure that you save it
as type All Files to avoid a new extension being added to the filename, and use UTF-8 encoding.
Parameter

Required?

Description

logfile

N

Name of rotating logfile that is written to logdir. Default is app.log.

logdir

N

Path to directory to write log files. If not specified, program checks
environment variable DEFAULT_LOG_DIR for path. If that is not set, then
defaults to a directory called “log” located wherever Resilient Circuits is
launched.

log_level

N

Level of log messages written to stdout and the logfile. Levels are: CRITICAL,
ERROR, WARN, INFO (default), and DEBUG.

host

Y

IP or hostname for the Resilient appliance.

org

Y, if
multiple
orgs

Name of the Resilient organization. This is required only if the user account is
used with more than one Resilient organization.

email

Y

User account for authenticating to the Resilient platform. It is recommended
that this account is dedicated to integrations.

password

Y

Password for the Resilient user account.

Page 12

Custom Action Developer’s Guide

Resilient Incident Response Platform

Parameter

Required?

Description

no_prompt_password

N

If set to False (default) and the “password” value is missing from this config
file, the user is prompted for a password.
If set to True, the user is not prompted.

stomp_port

N

Port number for STOMP. Default is 65001.

componentsdir

N

Path to directory containing additional Python modules. Resilient Circuits load
the components from this directory.

noload

N

Comma-separated list of:
 Installed components that should not be loaded.
 Module names in the componentsdir that should not be loaded.
Example: my_module, my_other_module, InstalledComponentX

proxy_host

N

IP or Host for Proxy to use for STOMP connection. By default, no proxy is used.

proxy_port

N

Port number for Proxy to use for STOMP connection. By default, no proxy is
used.

proxy_user

N

Username for authentication to Proxy to use for STOMP connection. If a
proxy_host is specified and no proxy_user specified, then it is assumed no
authentication is required.

proxy_password

N

Password for authentication to Proxy to use for STOMP connection. Used in
conjunction with proxy_user.

cafile

N

Path and file name of the PEM file to use as the list of trusted Certificate
Authorities for SSL verification when the Resilient platform is using untrusted
self-signed certificates.
If there is a PEM file, use a second instance of cafile to set to True or False. If
set to False, certificate verification is not performed and the PEM file is used. If
set to True (default), allow only trusted certs.

Whenever you install a new components package for Resilient Circuits, you need to update your
app.config file to include any required section(s) for the new component(s). After installing the
package, run:
resilient-circuits config –u

Alternately, you can choose specific packages:
resilient-circuits config –u –l  

If using an alternate file location for your app.config file, you need to specify it when you update.
resilient-circuits config –u /path/to/app.config

This adds a new section to your existing config file with default values. Depending on the
requirements of the component, you may need to modify those defaults to fit your environment,
such as credentials to a 3rd party system.

Page 13

Custom Action Developer’s Guide

Resilient Incident Response Platform

4.3. Pull Configuration Values
Values in the config file can be pulled from a compatible keystore system on your OS. This is
useful for values like passwords that you would prefer not to store in plain text. To retrieve a value
from a keystore, set it to ^. For example:
[resilient]
password=^resilient_password

Values in your config file can also be pulled from environment variables. To retrieve a value from
the environment, set it to $. For example:
[resilient]
password=$resilient_password

4.4. Add Values to Keystore
The Resilient package includes a utility to add all of the keystore-based values from your
app.config file to your system's compatible keystore system. Once you have created the keys in
your app.config file, run res-keyring and you are prompted to create the secure values to store.
res-keyring
Configuration file: /Users/kexample/.resilient/app.config
Secrets are stored with 'keyring.backends.OS_X'
[resilient] password: 
Enter new value (or  to leave unchanged):

4.5. Run Resilient Circuits
Once configuration is complete, you can run Resilient Circuits with the following command:
resilient-circuits run

If everything has been successful, you should see lots of output to your shell, including a
components loaded message. For example:

2017-03-06 11:04:35,525 INFO [app] Components loaded

You can stop the application running with ctrl+c.

Run Multiple Instances
Running the application creates a hidden file called “resilient_circuits_lockfile” in a “.resilient”
directory in your home directory. This is to prevent multiple copies of the application from running
at once. If your particular situation requires running multiple instances of Resilient Circuits, you
can override this behavior by specifying an alternate location for the lockfile via an
“APP_LOCK_FILE” environment variable.

Page 14

Custom Action Developer’s Guide

Resilient Incident Response Platform

Monitor Config File for Changes
You can configure Resilient Circuits to monitor the app.config file for changes. When it detects a
change has been saved, it updates its connection to the Resilient appliance and notifies all
components of the change. To enable this option, install the “watchdog” package.
pip install watchdog

Now you can run with:
resilient-circuits run –r

Without the –r option, changes to the app.config file have no impact on a running instance of
Resilient Circuits. Note that not all components currently handle the reload event and may
continue using the previous configuration until Resilient Circuits is restarted.

Override Configuration Values
Sometimes it is necessary to override one or more values from your app.config file when running
Resilient Circuits. For example, you may want to temporarily run with the log level set to DEBUG.
To accomplish this, run Resilient Circuits with:
resilient-circuits run --loglevel DEBUG

You can also use optional parameters to run the application when the values being overridden
are required and missing from the config file.
For a complete list of optional arguments for overrides, run:
resilient-circuits run -- --help

Page 15

Custom Action Developer’s Guide

Resilient Incident Response Platform

4.6. Run as a Service
You can configure Resilient Circuits to run as a service on a Red Hat Enterprise Linux or
Windows system.

Systemd on RHEL
Systemd is a process control program available on a variety of Linux systems. It is available on
the RHEL-based Resilient appliance. You need to create an OS user for the service. On RHEL
Linux:
sudo adduser integration --home /home/integration

Systemd uses unit configuration files to define services. Copy the configuration file provided
below to your integration machine and edit as necessary. The configuration file defines the
following properties:






OS user account to use.
Directory from where it should run.
Any required environment variables.
Command to run the integrations, such as resilient-circuits run.
Dependencies.

Here is an example of a configuration file. Copy this text to a file called resilient_circuits.service
and edit the content to match your setup. If you are not running on the Resilient system, then the
“After” and “Requires” lines in the [Unit] section should be removed.
[Unit]
Description=Resilient-Circuits Service
After=resilient.service
Requires=resilient.service
[Service]
Type=simple
User=integration
WorkingDirectory=/home/integration
ExecStart=/usr/local/bin/resilient-circuits run
Restart=always
TimeoutSec=10
Environment=APP_CONFIG_FILE=/home/integration/.resilient/app.config
Environment=APP_LOCK_FILE=/home/integration/.resilient/resilient_circuits.
lock
[Install]
WantedBy=multi-user.target

Copy this to the configuration directory and tell systemd to reload and enable the new service:
cp resilient_circuits.service
/etc/systemd/system/resilient_circuits.service
sudo chmod 664 /etc/systemd/system/ resilient_circuits.service
sudo systemctl daemon-reload
sudo systemctl enable resilient_circuits.service

To start or stop the resilient_circuits service, run:
sudo systemctl start resilient_circuits.service
sudo systemctl stop resilient_circuits.service

Page 16

Custom Action Developer’s Guide

Resilient Incident Response Platform

Windows
Resilient Circuits can be configured to run as a service on Windows. It requires the pywin32
library, which should be downloaded from sourceforge. Instructions for downloading and installing
the correct package are at the bottom of the sourceforge web page and must be followed
carefully. Do not use the pypi/pip version of pywin32.
Installation of the wrong version of the pywin32 library will likely result in a Resilient service that
installs successfully but is unable to start.
Now run:
resilient-circuits.exe service install

Once installed, you can update the service to start up automatically and run as a user account.

It is recommended that you log in as whichever user account the service will run as to generate
the config file and confirm that the integration runs successfully with “resilient-circuits.exe run”
before starting the service.
Commands to start, stop, and restart the service are provided as well.
resilient-circuits.exe service start
resilient-circuits.exe service stop
resilient-circuits.exe service restart

Page 17

Custom Action Developer’s Guide

Resilient Incident Response Platform

5. Developing Using Resilient
Circuits
The Resilient Circuits framework makes it simple to develop and deploy custom action
processors using Python. An action processor component, in this framework, is a Python class
that implements message handlers. These handlers are called by the framework when a
message arrives on a message destination.

5.1. Get Started
Before writing the action processor, perform the following:
1. Create a directory on your integration system. This is the directory where Resilient Circuits
looks to load your module.
2. Add the absolute path to the directory in your app.config.
For example, create a directory called “components” and then add a value for “componentsdir” to
your app.config file and set it to the absolute path of this components directory.
If you have access to an integration that is similar to the one you wish to create, you can use that
integration as a template to save time.

5.2. Create the Resilient Platform Components
There are several ways to trigger your custom action:


A menu item rule that posts the transaction to a message destination. When the conditions
are met, the rule adds an action to the Action menu of its object, such as an incident, task, or
artifact. With a menu item rule, you can add Activity Fields for additional user input, which is
also sent with the message.



An automatic rule that posts the transaction to a message destination. The message is sent
when an object, such as an incident, task or artifact, is created or modified and meets the
conditions that you specify. For example, you might automatically send “IP Address” artifacts
to a particular destination if the incident is not yet triaged.



A workflow that posts the transaction to a message destination. Workflows provide flexibility
in how these custom actions are coordinated, and are ideal for complex scenarios including
task completion, decision logic, scripts, and timers.

Page 18

Custom Action Developer’s Guide

Resilient Incident Response Platform

Determine which method is best for you then perform the following to create the Resilient
components. For detailed procedures, see the Resilient Incident Response Platform Playbook
Designer Guide.
1. Log in to the Resilient platform as a user with permission to view and modify the
customization settings.
2. Go to the Message Destinations tab and create a message destination as follows:
a. Set the Type to Queue.
b. Set Expect Acknowledgement to Yes.
c.

Add the Resilient account that you use for integrations as an authorized user in the
Users field.

3. If you require custom fields to gather or receive specific data for your integration, perform the
following:
a. Go to the Layouts tab.
b. Determine where to place the fields by selecting the tab or New Incident Wizard.
c.

Create the fields. Take note of the API Access name of each field for use in your code.

4. If you require a data table to receive data from the integration, perform the following:
a. Go to the Layouts tab.
b. Determine where to place the data table by selecting the tab.
c.

Create the data table. Take note of the API Access name of the data table for use in your
code.

5. If using a rule, go to the Rules tab and create the rule. Configure it as an automatic or menu
item rule. Make sure that the rule includes your message destination. Note the programmatic
name of the rule, which is the same as the display name with underscores instead of spaces.
6. If using a workflow, go to the Workflows tab and create a workflow. Make sure to add the
message destination at an appropriate place in the workflow. Note the programmatic name of
the workflow.
NOTE: If you create a workflow, you should also create one or more rules that call the
workflow.

Page 19

Custom Action Developer’s Guide

Resilient Incident Response Platform

5.3. Write the Action Processor
The action processor is a Python module. Perform the following:
1. Create a Python module in your components directory that contains your integration code.
You can use any of the example Resilient Circuits component modules as a starting point.
The module name and component class name may be anything you wish, but it is advisable
to give them a name reflective of their behavior or purpose.
2. Set the channel member to the programmatic name of the message destination.
3. Rename the _framework_function method of your class to something descriptive for what the
action should do.
4. Match the @handler to the API name of the rule or workflow.
5. Update the handler code to perform your desired actions. You can update incident fields, add
tasks or artifacts, or anything else supported by the Resilient REST API. For details, see Add
Functionality with Decorators.
6. Make sure to end your logic by yielding a status string. This is used for the action status
message in the Resilient platform. For example:
yield StatusMessage “Task added successfully”

7. Add a section to your app.config file with a name that is reflective of your component to store
configuration values. Put any configuration values you need here.
8. Update the CONFIG_DATA_SECTION variable in your module with the name of the section
you created. For example: CONFIG_DATA_SECTION = “example_action”
The following example is a simple script that is a component that subscribes to a message
destination named “example”, and handles a rule named “example_action”. The name of the
Python class (in this example, “MyExampleComponent”) is not important, nor is the filename.
In the __init__ method of the component class, the “channel” member is set to the programmatic
name of the message destination you created. The class has a method, decorated with
@handler() that determines the action(s) to be sent to the Resilient platform.
# Simple example component for resilient-circuits
import json
import logging
from circuits.core.handlers import handler
from resilient_circuits.actions_component import ResilientComponent,
ActionMessage
logger = logging.getLogger(__name__)
class MyExampleComponent(ResilientComponent):
# Subscribe to the Action Module message destination named "example"
channel = "actions.example"
@handler("example_action")
def _example_handler_function(self, event, *args, **kwargs):
# This function is called with the action message,
# In the message we find the whole incident data (and other
context)
incident = event.message["incident"]
logger.info("Called from incident {}: {}".format(incident["id"],
incident["name"]))

Page 20

Custom Action Developer’s Guide

Resilient Incident Response Platform

The handler function can access additional context, for example:
# The message also contains information about the user who
triggered the action
who = event.message["user"]["email"]
# Post a new artifact to the incident, using the provided REST API
client
new_artifact = {
"type": "String",
"value": "Test artifact from {}".format(who)
}
new_artifact_uri =
"/incidents/{}/artifacts".format(incident["id"])
self.rest_client().post(new_artifact_uri, new_artifact)

Any string returned by the handler function is shown to the Resilient user in the Action Status
dialog:
return "Action Processed OK"

5.4. Run the Action Processor
Run the integration code from the command-line, with resilient-circuits run. The framework
reads your configuration file, connects to the Resilient platform, finds and loads your components,
then subscribes to the message destination for each action processor component. Leave it
running; when an event is triggered, the code handles it.
$ resilient-circuits run
2017-11-21 09:23:52,288 INFO [app] Configuration file:
/home/integration/.resilient/app.config
2017-11-21 09:23:52,291 INFO [app] Resilient server: culture.example.com
2017-11-21 09:23:52,293 INFO [app] Resilient user: api@example.com
2017-11-21 09:23:52,295 INFO [app] Resilient org: Special Circumstances
2017-11-21 09:23:52,296 INFO [app] Logging Level: INFO
2017-11-21 09:23:52,840 INFO [app] Components auto-load directory:
/home/integration/components
2017-11-21 09:23:52,857 INFO [stomp_component] Connect to
culture.example.com:65001
2017-11-21 09:23:52,966 INFO [app] App Started
2017-11-21 09:23:52,969 INFO [actions_component] Component registered to
actions.example
2017-11-21 09:23:52,970 INFO [component_loader] Loaded and registered
component 'example'
2017-11-21 09:23:52,971 INFO [actions_component] STOMP attempting to
connect
2017-11-21 09:23:52,972 INFO [app] Components loaded
2017-11-21 09:23:52,973 INFO [stomp_component] Connect to Stomp...
2017-11-21 09:23:52,974 INFO [client] Connecting to
culture.example.com:65001 ...
2017-11-21 09:23:53,069 INFO [client] Connection established
2017-11-21 09:23:53,221 INFO [client] Connected to stomp broker
[session=ID:culture-40894-1508509684399-5:81, version=1.2]
2017-11-21 09:23:53,223 INFO [stomp_component] Connected to
failover:(ssl://culture.example.com:65001)?maxReconnectAttempts=1,startupM
axReconnectAttempts=1
2017-11-21 09:23:53,224 INFO [stomp_component] Client HB: 0 Server HB:
15000
2017-11-21 09:23:53,225 INFO [stomp_component] No Client heartbeats will
be sent
2017-11-21 09:23:53,226 INFO [stomp_component] Requested heartbeats from
server.

Page 21

Custom Action Developer’s Guide

Resilient Incident Response Platform

2017-11-21 09:23:53,229 INFO [actions_component] Subscribe to message
destination 'example'
2017-11-21 09:23:53,230 INFO [actions_component] STOMP connected.
2017-11-21 09:23:53,232 INFO [stomp_component] Subscribe to message
destination actions.203.example

In this example, the “Example Action” can be found on the Actions menu at the top right of the
incident.

If your menu item is for artifact objects, you can find the menu available from the “…” action
button beside the artifact; similarly for tasks, notes, and so on. For details, see the Resilient
Incident Response User Guide.
Select Example Action from the Actions menu. Where this is a menu item rule in the example,
the Resilient user is prompted to enter the fields as shown below. When the user clicks Execute,
the Resilient platform sends the data to the message destination.

Page 22

Custom Action Developer’s Guide

Resilient Incident Response Platform

At the integration console, you can see the message arrive, including the logging message to
print the incident name as part of the example code.
2017-11-21 09:24:23,235 INFO [actions_component] Event: Channel:
actions.example
2017-11-21 09:24:23,237 INFO [example] Called from incident 2496: The New
Incident

The Action Status menu shows whether each action is pending (queued for delivery to the action
processor), processed successfully, or with an error. Here you can see that the action completed
with success, and included a status message.

5.5. Run during Development
During development, it would be inconvenient to have to re-install your package every time you
want to test a change. Fortunately, you can install your project in “unbuilt” mode, which links
directly against the source code in your project directory rather than installing a copy in sitepackages. Now your changes take effect immediately with no need to re-install. There are two
ways to do this. From within your project directory (at the same level as your setup.py script), run
one of the following commands:
python setup.py develop

or
pip install -e .

This creates an “egg-info” directory in your project directory and links your site-packages to it.
While developing your Resilient Circuits integration, it is very useful to be able to run it from your
IDE (PyCharm and so on) so you can use tools like a debugger.
Instead of the “resilient-circuits run” command that you would normally use at the command line,
have your IDE run Resilient Circuits with the command “python resilientcircuits/resilient_circuits/app.py”. This is best used in combination with the “develop” installation
mode. If you have not packaged your integration, make sure the “componentsdir” parameter is
set correctly in your app.config file to point to the directory containing the component you are
developing.

Page 23

Custom Action Developer’s Guide

Resilient Incident Response Platform

5.6. Add Functionality with Decorators
Resilient Circuits provides various Python “decorators” that you can use to add functionality to the
handler functions in your component.

required_field
The required_field class decorator allows you to require that a custom field with a particular name
is present in the Resilient platform. If that field does not exist, the component fails to load and
provides an appropriate error message.
Sample Usage:
@required_field("last_updated")
class SetLastUpdated(ResilientComponent):
"""Set a last updated timestamp on incident"""
@handler("incident_updated")
def _set_last_updated(self, event, source=None, headers=None,
message=None):
inc_id = event.message["incident"]["id"]
timestamp = int(headers.get("timestamp"))
def update_func(inc):
inc["properties"]["last_updated"] = timestamp
return inc
self.rest_client().get_put("/incidents/%d" % inc_id, update_func)
yield "last_updated set"

required_action_field
This class decorator allows you to require that an activity field with a particular name is present in
the Resilient platform. If that field does not exist, then the component fails to load and provides an
appropriate error message. Its usage is the same as for the required_field decorator.

defer
This method decorator allows you to postpone handling an action for a specified number of
seconds. This is useful for situations where you need to accommodate a delay in the availability
of a resource. For example, allowing time for incident updates to be reflected in the Resilient
newsfeed before querying that API endpoint. The defer decorator should be placed ABOVE the
handler decorator on your method.
The defer decorator works only with handlers that specify the action they are handling. Methods
that are being used as a default handler, with @handler(), are called for all types of circuits
events, most of which do not relate to the Resilient Action Module. There is an alternate method
to defer action handling in these types of handlers which is accessed by calling a defer method
on the event itself.
Sample Usage:
@defer(delay=3)
@handler("my_action")
def _do_deferred_action1(self, event, source=None, headers=None,
message=None):
# Code to handle action here!
return "action handled"
@handler()
def _do_deferred_action2(self, event, *args, **kwargs):
"""Defer handling action on generic handler"""
if not isinstance(event, ActionMessage):
# Some event we are not interested in
return
if event.defer(self, delay=3):

Page 24

Custom Action Developer’s Guide

Resilient Incident Response Platform
return
# Code to handle action here!
return "action handled"

debounce
There are times when an action handler is likely to be triggered multiple times in quick
succession, but you do not want to handle the events until all of them are done firing. The
debounce method decorator allows you to “accumulate” these events and defer handling them
until they stop firing. Similar to the defer decorator, a delay value is specified. If another event
with the same key occurs within that delay period, then the timer is reset. All events are
processed once the timer expires.
In most scenarios, it is only the last event in the series that is of interest. If the “discard” option is
specified, then only the most recent event is handled when the timer expires and any earlier ones
are discarded. This is useful in cases where all the events would have triggered the same action,
resulting in “noise” on an incident’s newsfeed.
The defer decorator works only with handlers that specify the action they are handling. Methods
that are being used as a default handler, with @handler(), cannot use this feature.
Sample usage:
@debounce(delay=30, discard=True)
@handler("task_changed")
def _who_owns_next_task(self, event, source=None, headers=None,
message=None):
inc_id = event.message["incident"]["id"]
url = '/incidents/{0}/tasks?handle_format=names'.format(inc_id)
tasks = self.rest_client().get(url)
for _task in tasks:
if _task['status'] == 'O':
owner_fname = _task["owner_fname"] or ""
owner_lname = _task["owner_lname"] or ""
break
else:
owner = "All Tasks Complete"
def update_func(inc):
inc["properties"]["next_task_owned_by"] = "%s %s" % (owner_fname,
owner_lname)
return inc
self.rest_client().get_put("/incidents/%d" % inc_id, update_func)
yield "next_task_owned_by set"

Page 25

Custom Action Developer’s Guide

Resilient Incident Response Platform

5.7. Long-Running Actions
Some types of actions, like running a database query in another system, can take a long time to
complete. A Resilient Circuits handler is blocking, meaning it can only handle one action at a
time. To free the handler to take care of the next incoming event, you can user a circuits “worker”
to run the lengthy task. A worker can be a separate thread or a separate process, depending on
your needs.
The original action handler method is triggering a secondary task to do the real work of running
the action and then returning (which acknowledges the event in the Resilient Action Module). This
results in the Action Status in the Resilient platform showing up as “complete” even though the
action is still being run.
Example:
def do_expensive_thing(incident_id):
time.sleep(60)
return "finished"
class expensive_thing(circuits.Event):
pass
class MyComponent(ResilientComponent):
def __init__(self, opts):
super(MyComponent, self).__init__(opts)
circuits.Worker(process=False, workers=5,
channel=self.channel).register(self)
@handler("expensive_thing")
def _do_expensive_thing(self, inc_id):
yield self.call(circuits.task(do_expensive_thing, inc_id))
@handler("my_action")
def _start_expensive_action(self, event, source=None, headers=None,
message=None):
""" Handler that kicks off long-running task """
inc_id = event.message["incident"]["id"]
self.fire(expensive_thing(inc_id))
yield "Started expensive action"

Page 26

Custom Action Developer’s Guide

Resilient Incident Response Platform

5.8. Web UI and RESTful Components
The Resilient Circuits framework comes with a built-in web framework and webserver to create
your own REST API or Web UI.
Some applications, particularly ticketing systems, utilize webhooks as a means of integrating with
other applications. These types of integrations work by allowing a user access to a URL that data
is posted to when certain events occur, such as ticket creation and ticket update. A circuits based
REST API is well suited to this use case.
Another use case for the circuits web framework is building a custom webform to facilitate
incident creation by people who are not direct users of the Resilient platform. Refer to the
circuits.web documentation for more information.
The first step in building a web component for Resilient Circuits is to install the rc-webserver
package. From the same directory where you downloaded the package, run:
pip install rc-webserver --find-links .

The webserver requires a few configuration items in your app.config file, so next run:
resilient-circuits config -u

This adds the required configuration section with functional defaults, but you may wish to change
them.
Your web component must inherit from the circuits class BaseController. If you need access to
the Resilient REST API, you need to inherit from the ResilientComponent class. The “channel”
your component listens on corresponds to the first path element from your URL. For example, if
you set “self.channel=”/example”, then all requests starting with
www.:/example are routed to your component for handling.
The ‘exposeWeb’ decorator is then applied to methods to handle routes more specifically. For
example, putting “@exposeWeb(“test”)” above your method causes it to be called for all requests
to www.:/example/test.

5.9. Package the Integration
Once you have finished developing your component, you can package it so that it is installable
and automatically discoverable by Resilient Circuits. Your project structure should look similar to
the following:
my-circuits-project/
|-- setup.py
|-- README
|-- MANIFEST.in
|-- my_circuits_project/
|
|-- data/
|
|
|-- LICENSE
|
|
|-- sample_data.txt
|
|-- components/
|
|
|-- my_custom_component.py
|
|-- lib/
|
|
|-- helper_module1.py
|
|
|-- helper_module2.py

For an example of a setup.py file, see the Resilient community examples GitHub repository,
choose an “rc-“ integration and view its setup.py file. Your setup.py file should look similar. The
name of each project always has an “rc-“ prefix. That is for convenience so that they are readily
identifiable as Resilient Circuits integrations, but is not required.

Page 27

Custom Action Developer’s Guide

Resilient Incident Response Platform

The “entry_points” section of setup.py makes your integration discoverable by Resilient Circuits
as a component to run. The “resilient.circuits.components” key should be a set to a list of all
component classes defined in your integration. The “resilient.circuits.configsection” key should
point to a function in your integration package that returns a string containing a sample config
section. This is called to generate data for a config file when a user runs “resilient-circuits config –
u app.config”.
Once your integration is packaged and tested, you can share it with other Resilient users, as
described in Publish Your Function.

5.10. Test the Integration
Testing a Resilient Circuits component begins during development. Once you have a minimal
component running, you can use the standalone res-action-tool to submit test action data to your
component to quickly test changes to your logic. Support for running a suite of unit and/or
integration tests using the Pytest framework is also provided.

res-action-test
The res-action-test tool is an interactive command-line tool for manually submitting actions to a
component outside of a Resilient rule. The most common use case for this is to record real action
data from a Resilient rule, and then “replay” it via the command line tool.
To record a session interacting with the Action Module, first make a directory to log the data.
Then, run Resilient Circuits with the log-http-responses option.
mkdir logged_responses
resilient-circuits run -r --log-http-responses logged_responses/

Trigger the rule you want to record. Once you have seen the action received by the application,
you can kill Resilient Circuits. In the logged_responses directory, you should see a filename that
starts with “ActionMessage”.
ls logged_responses/ActionMessage*
logged_responses/ActionMessage_AddTask_2017-03-07T09:24:41.822231

Run Resilient Circuits again with the test-actions option so that it listens for test actions to be
submitted.
resilient-circuits run --test-actions

When Resilient Circuits is running, start the res-action-test tool in another shell. In the following
example, the saved action message is submitted as if it came in from the “add_task” queue. The
response that would have gone to the Resilient platform over the STOMP connection instead
displays in the test tool.
res-action-test
Welcome to the Resilient Circuits Action Test Tool. Type help or ? to list
commands.
(restest) submitfile add_task logged_responses/ActionMessage_AddTask_201703-07T09:24:41.822231
(restest)
Action Submitted
(restest)
RESPONSE: {"message": "action complete. task posted. ID
2253452", "message_type": 0, "complete": true}

Page 28

Custom Action Developer’s Guide

Resilient Incident Response Platform

Because the res-action-test tool is a separate process running independently from the main
Resilient Circuits application, it keeps running when the Resilient Circuits process is killed or
otherwise terminated. You see a “disconnected” message appear. As soon as Resilient Circuits
starts back up with the test-actions option, it automatically reconnects. This makes it easy to
submit a test action, make a change to your component and restart Resilient Circuits, and quickly
re-run the test action.
For a complete list of actions available in rest-action-test, type “help”. For usage of any individual
command, type “help ”.

Write and Run Tests Using pytest
Once an integration is packaged as an installable component, you can create a suite of tests for
your integration package. Several of our example components have tests written using the pytest
framework. Learn about using pytest by reading the documentation here. IBM Resilient provides
a plugin for pytest with several test fixtures that make writing Resilient Circuits tests easier.
You can download the pytest plugin from the Resilient GitHub repository and install it as follows:
pip install pytest_resilient_circuits-x.x.x.tar.gz

Resilient Pytest Fixtures
Once the plugin is installed, it makes several fixtures available in pytest. Each of these fixtures is
“class-scoped”, so it is initialized once per class of tests. The following describes each fixture:


circuits_app: Starts up Resilient Circuits with the specified appliance and credentials. The
appliance location and credentials are pulled from the following environment variables if they
are set. Otherwise, they must be provided as command line options when the test is run, as
described in the Run Tests section.
o
o
o
o



test_resilient_appliance
test_resilient_org
test_resilient_user
test_resilient_password

configure_resilient: Clears out all existing configuration items from the organization and
then automatically creates new ones as defined by your test class. Class members should be
set as follows to describe required configuration elements. Any that are not necessary can be
excluded.
destinations = ("", "", ...)
action_fields = {"": ("",
"", None),
"": ("select", "",
("", "")), ...}
custom_fields = {"": ("",
"", None),
"": ("select", "",
("", "")), ...}
automatic_actions = {"": ("",
"", (condition1, condition2, etc)),
"": ("", "", (condition1, condition2, etc))}
*note that conditions are a dict in ConditionDTO format
manual_actions ={"": ("",
"", ("",
"", ...)),
"": ("",
"", ("",
"", ...))}

Page 29

Custom Action Developer’s Guide

Resilient Incident Response Platform



new_incident: Provides a python dictionary containing data suitable for doing a PUT against
the /incidents endpoint in the Resilient platform. It has something valid populated for all
required fields and simplifies creating test data in the Resilient platform.

Run Tests
All test modules should be in a “tests” directory at the top level of your package.
Assuming you have configured a “test” command in your setup.py, you should now be able to
start your tests with the “setup.py test” command. This runs setup and your test suite in your
current Python environment. Use of a Python virtual environment is recommended.
python setup.py test -a "--resilient_email  -resilient_password  --resilient_host  -resilient_org '' tests"

If you have already installed your plugin, and thus do not need to run setup, you can kick off
pytest directly with:
pytest –s --resilient_email  --resilient_password  -resilient_host  --resilient_org “” tests

Run Tests with tox
Running with “setup.py test” runs your test suite in your current environment. Tox is a great way
to test your package in a clean environment across all supported Python versions. It generates a
new virtual environment for each supported Python version and runs setup and your tests. Read
more about tox here and install it with:
pip install tox

To get started, create a tox.ini file in your package at the same level as the setup.py script. Set
“envlist” to all the Python versions you want to support. Note that it can only run tests for those
versions you actually have installed on your system. Because the “Resilient”, “resilient_circuits”,
and “pytest_resilient_circuits” packages are all dependencies, make sure they are listed in the
“deps” section. Copy those packages to a pkgs directory and set an environment variable so that
pip can find them.
export PIP_FIND_LINKS=”/path/to/pkgs/"

Your package should look something like this:
my-circuits-project/
|-- setup.py
|-- tox.ini
|-- README
|-- MANIFEST.in
|-- my_circuits_project/
|
|-- data/
|
|
|-- LICENSE
|
|
|-- sample_data.txt
|
|-- components/
|
|
|-- my_custom_component.py
|
|-- lib/
|
|
|-- helper_module1.py
|
|
|-- helper_module2.py
|-- tests/
|
|-- tests_for_my_project.py

Now run your tests with:
tox -- --resilient_email  --resilient_password  -resilient_host  --resilient_org '' tests

Page 30

Custom Action Developer’s Guide

Resilient Incident Response Platform

Mock Resilient API
It is not always practical or possible to run tests against a live Resilient instance. The Resilient
package includes a simple framework built on Requests-Mock to enable mocking a subset of the
Resilient REST API. Only the endpoints used by your component need to be mocked. Some
endpoints, like /session, always needs to be mocked because the Resilient helper module and
Resilient Circuits packages use them.
Create a class derived from resilient.resilient_rest_mock.ResilientMock. Define a function for
each endpoint you wish to mock, returning a requests.Response object. To register which
endpoint you are mocking, use the @resilient_endpoint decorator on the function, passing it the
request type and a regex that matches the desired URL.
In this example, the /incident//members endpoint is mocked for PUT and GET requests:
from requests_mock import create_response
from resilient.resilient_rest_mock import ResilientMock,
resilient_endpoint
class MyMock(ResilientMock):
def __init__(self, *args, **kwargs):
super(MyResilientMock,self).__init__(*args, **kwargs)
self.members = []
@resilient_endpoint("GET", "/incident/[0-9]+/members$")
def get_members(self, request):
member_data = {"members": self.members, "vers": 22}
return create_response(request, status_code=200, json=member_data)
@resilient_endpoint("PUT", "/incident/[0-9]+/members$")
def put_members(self, request):
data = request.json()
if "members" not in data or "vers" not in data or not
isinstance(data.get("members"), list):
error_data = {"success": False, "message": "Unable to process
the supplied JSON."}
return create_response(request, status_code=400,
json=error_data)
self.members = data["members"]
member_data = {"members": self.members, "vers": 22}
return create_response(request, status_code=200, json=member_data)

5.11. Publish Your Function
In addition to deploying your integration to other Resilient platforms in your environment, you can
share your integration with the Resilient community if you are an IBM Technology partner or
employee. For information about becoming a technology partner, see the IBM PartnerWorld
page.
IBM Resilient provides two locations for sharing functions, IBM Security X-Force App Exchange,
and Resilient Community Apps on Github.
The IBM Security X-Force App Exchange allows you to make your integration available to others
in the Resilient community. You have the option to update the integration as needed. For more
information on submission requirements, see the Publishing Integrations page.
The Resilient Community Apps on Github also allows you to share your source code with others.
Members can copy, modify and enhance your integration using the pull request mechanism. See
the Resilient Community Apps page for a list of apps, with developer information at the bottom of
this web page.
You can choose to submit to one or both locations.

Page 31

Custom Action Developer’s Guide

Resilient Incident Response Platform

6. Developing Using the API
The following sections describe the steps you need to consider if not using the Resilient Circuits
framework.
You can write action processors in any language that allows TLS connections to a message
broker using the STOMP or ActiveMQ (OpenWire) protocol.
If you use a Java-based language, typically you would use the ActiveMQ client library, which uses
the OpenWire protocol. There are libraries that support STOMP and are available for most
modern programming languages. The STOMP Clients web page includes many different STOMP
client library options.
Before starting, you should be familiar with the Resilient API. To access the API Reference guide,
including schemas for all of the JSON sent and received by the API, log into the Resilient
platform, click your account name at the top right and select Help/Contact. For additional
information, see JSON Structures in the Resilient API in this guide.

6.1. User Authentication/Authorization
The action processors authenticate to the message broker using Resilient credentials. It is
recommended that you create dedicated service accounts for this purpose. These accounts can
be created with very strong passwords.
Accounts can be created from the Resilient command line using the following commands:
openssl rand –hex 32

sudo resutil newuser -email security@mycompany.com -org "My Company" first Security -last User
[sudo] password for resilient_admin: 
Enter the password for the user: 
Confirm the password for the user: 

When prompted for the new user password, enter the random value from the openssl rand
command. Because you use sudo to invoke the resutil tool, you may be prompted to enter your
current login user password first.
The openssl command generates a random password of 32 bytes of data encoded as a hex
string (which results in 64 characters). The second command adds a user using the random
password from the previous command.
The users created by the resutil command are administrative users. This may or may not be
required by your application. If it is not required, you can use the Resilient platform to remove the
administrative rights before you use it to connect for the first time.
Some action processors need to use the Resilient REST API to access or modify additional
Resilient data. This same user account can be used to authenticate with the REST API.
Once created, you can grant access to the message destinations to which it needs access. This
is done through the Resilient platform user interface. You grant access to message destinations
by adding the allowed users in the Users section of the message destination dialog box. Refer to
the Resilient Incident Response Platform Playbook Designer Guide for details.
NOTE: When making API calls, you need the JSESSIONID and csrf_token to create a session,
as shown in Example: Creating an Incident.

Page 32

Custom Action Developer’s Guide

Resilient Incident Response Platform

6.2. Message Destination and Org Prefix
On the Resilient platform, message destinations have a display name and a generated
programmatic name. When connecting to message destinations from your code, use the
programmatic name and include the organization ID as a prefix. The following figure illustrates
how to locate your organization ID in the Resilient platform.

If you created a message destination in the Resilient platform with a programmatic name of
“ticket” and your organization ID is 202 as it is in the previous figure, the name you would use in
your action processor code to read messages would be “actions.202.ticket”.
Some client libraries have you connect to the destination using a “/queue” or “/topic” prefix. For
example, if you were connecting to the ticket queue, you would use a name of
“/queue/actions.202.ticket”. Consult the documentation for your client library for more information.

Page 33

Custom Action Developer’s Guide

Resilient Incident Response Platform

6.3. Menu Item Rules and Activity Fields
There are two types of rules, automatic and menu item.
The menu item rule displays as an action in the object’s Actions drop-down menu and executes
only when a user invokes it. In some cases, it is necessary for the user to enter additional
information when selecting an action. For example, if you are developing a “Create ticket” action,
you may need to allow the user to select a priority for the ticket that is to be created. You do this
by creating an activity field. Activity fields are managed through the Resilient platform as part of
the menu item rule. Refer to the Resilient Incident Response Platform Playbook Designer Guide
for details.
The following figure illustrates the creation of a Ticket Priority field that is added to a menu item
rule. It is a select field that has four values, Low, Medium, High and Critical. The field value is
required.

Page 34

Custom Action Developer’s Guide

Resilient Incident Response Platform

Once you create the Ticket Priority field, you drag it to the rule’s layout as shown in the next
figure. You can also create a header that gives the user some additional information. Once you
create a field, it is available to all other menu item rules.

Page 35

Custom Action Developer’s Guide

Resilient Incident Response Platform

6.4. Action Data
Messages contain JSON data. The structure of the JSON data is described in the Resilient REST
API documentation in the ActionDataDTO type. This structure contains much of the data that you
need to implement with your action processors. However, if there is additional Resilient data that
you require, you can access it using the Resilient REST API. See the Resilient REST API with
Action Processors section for considerations when doing this.
The following table describes the top-level properties in the ActionDataDTO type. For specific
information about this type, consult the Resilient REST API documentation.
Field Name

Description

action_id

ID of the rule that caused the message.

type_id

Type of object that caused the message. The types and their associated IDs are available
through the REST API with the “/rest/orgs/{orgId}/types” endpoint.

incident

Incident object to which the invocation applies. Note that this value is set for items that
are subordinate to incidents. It is currently the case that all messages contain an incident.

task

Task to which the invocation applies (if any). Note that this value is set for items that are
subordinate to tasks, such as task notes and task attachments.

artifact

Artifact to which the invocation applies (if any).

note

Note to which the invocation applies (if any).

milestone

Milestone to which the invocation applies (if any).

attachment

Attachment to which the invocation applies (if any).

type_info

Contains information about types/fields that are referenced by the other data. See the
Action Data and Type Information section for more information.

properties

Contains the field values the user selected when invoking a menu item rule (if any).

user

Contains information about the user that invoked the action.

Page 36

Custom Action Developer’s Guide

Resilient Incident Response Platform

6.5. Action Data and Type Information
The data specified in the incident, task, artifact, note, milestone and attachment fields generally
contains only the ID values of objects they reference. For example, the incident “severity_code”
field is a select list. The “incident.severity_code” value specified in the message data contains an
integer (the severity ID). If your processor needs the severity text that was actually selected, you
can get it from the type_info field.
# Python example of retrieving severity text from type_info
# Convert message text into a dictionary object
json_obj = json.loads(message)
# Get severity_code from the incident
sev_id = json_obj['incident']['severity_code']
# Use type_info to get the severity's text value
sev_field = json_obj['type_info'] \
['incident'] \
['fields'] \
['severity_code']
text = sev_field['values'][str(sev_id)]['label']
print "Severity text is %s" % text

6.6. Message Headers
The Resilient platform includes various message headers that are needed (or in some cases just
helpful) in processing messages.
Header Name

Request/Reply

Description

Co3ContextToken

Request

A token value that must be specified if the action
processor calls back into the Resilient REST API. The
primary purpose of this token is to ensure that actions
processing does not result in an infinite loop. See the
Resilient REST API with Action Processors section for
additional information.

correlation-id

Request and
Reply

Identifies the rule invocation to which this message
applies. It must be included in acknowledgement
messages sent back to the Resilient platform. See the
Acknowledgements section for additional information. If
you are using a JMS client, this value can be retrieved
with the getJMSCorrelationID method.

reply-to

Request

Identifies a server-controlled message queue that must be
used when acknowledging (replying to) this message.
See the Acknowledgements section for additional
information. If using a JMS client, this value can be
retrieved with the getJMSReplyTo method.

Co3InvocationComplete

Reply

A boolean header that tells the Resilient platform whether
processing is complete. The default is true, so you need
to include it only if you are sending an informational
message and it is not complete. This header is ignored if
the reply message is JSON.

Page 37

Custom Action Developer’s Guide

Resilient Incident Response Platform

6.7. Acknowledgements
Some action processors consume messages and silently process them without returning any
indication of progress or status to the Resilient platform (“fire and forget”). Other action
processors return an acknowledgement when they have completed the processing of a message
(“request/response”). The Resilient platform supports either mode of operation through the
Expect Acknowledgement setting of the message destination, as shown in the following figure.

When a message destination is configured with an Expect Acknowledgement value of Yes, the
list of executed actions in the Resilient UI shows messages/invocations as Pending until the
expected acknowledgement is received. If an acknowledgement is not received within 24 hours,
the Resilient platform displays it as an error. Users can see the list of actions invoked on an
incident by selecting the Actions > Action Status option from the incident view.
If the message destination is configured with an Expect Acknowledgement value of No, the action
immediately displays with a status of Completed.
The following is a partial example of how to explicitly send a reply using the stomp.py Python
library:
# Simple reply using Python
class MyListener(object):
def __init__(self, conn):
self.conn = conn
def on_message(self, headers, message):
reply_headers = {'correlation-id': headers['correlation_id']}
reply_to = headers['reply-to']
reply_msg = "Processing complete"
conn.send(reply_to, reply_msg, reply_headers)

The Resilient platform accepts either JSON or just a simple text string for reply messages. Simple
plain text reply messages are a way to provide a success acknowledgement with minimal effort.
You can also use a more descriptive JSON string value, which is parsed by the server.

Page 38

Custom Action Developer’s Guide

Resilient Incident Response Platform

The format for the JSON messages is included in the Resilient REST API documentation (see the
ActionAcknowledgementDTO type). For convenience, the following table illustrates sample
values for error and informational reply messages.
Reply Type
Error

Information

Completed

Example JSON
{"message_type": 1,
"message": "Some error occurred ...",
"complete": true}
{"message_type": 0,
"message": "Started processing",
"complete": false}
{"message_type": 0,
"message": "Completed processing",
"complete": true}

Processors can send reply messages, even if they are not expected. This allows informational or
error messages to be returned even if no reply is expected. You may choose to utilize this
behavior if you expect that the processors will rarely fail. Unexpected replies are displayed in the
Action Status screen just as they are for expected ones.

6.8. TLS
Action processors must connect to the Resilient message broker using TLS v1.1 or higher. This
applies to both the connection to the message destination (STOMP over TLS and Active
MQ/OpenWire over TLS) and the Resilient REST API (HTTPS).
To ensure the security of the connection, action processors must properly validate the server
certificate. The exact mechanisms for doing this varies by programming environment and is
beyond the scope of this document. However, the following must be considered:


Is the certificate chain presented by the server trusted?



Is the certificate signature correct?



Has the certificate expired?



Was the certificate issued to the site to which the connection was made? That is, does the
certificate’s common name or subjectAltName match the connected server’s name?

Some of the common JMS libraries for Java do not perform checking on the certificate name (last
bullet above). There is a workaround for this, which is used in the Java examples.

Page 39

Custom Action Developer’s Guide

Resilient Incident Response Platform

6.9. Resilient REST API with Action Processors
Resilient action processors can make use of the Resilient REST API to update incidents, retrieve
additional information not included in the rule message data, etc.
The only restriction is that when making REST API requests you must specify the
X-Co3ContextToken HTTP header. The value to specify in this header is passed as the
Co3ContextToken message header. This ensures that any modifications done through the API do
not cause an infinite loop of message invocations. For example, if an incident rule has no
conditions specified then it triggers every time the incident is saved. If the downstream action
processor itself saves the incident, then you might end up in a never-ending loop. The
X-Co3ContextToken HTTP header tells the server to skip the rule that generated the original
message.
The following code is using the SimpleClient class that is included with the examples.
SimpleClient provides post, put and delete methods that take the token as an argument. See the
example processor code for additional details.
# Use Resilient REST API from Python processor
class MyListener(object):
def __init__(self, conn):
self.conn = conn
self.client = co3.SimpleClient(...)
def on_message(self, headers, message):
# Get the token from the message header, set into client object
self.client.context_header = headers['Co3ContextToken']
message_obj = json.loads(message)
inc_id = message_obj['incident']['id']
url = "/incidents/{}/comments".format(inc_id)
comment_data = {'text': 'Some comment for the incident'}
# Create the comment
self.client.post(url, comment_data)

6.10. HTTP Conflict (409) Errors
It is possible for the Resilient platform to return an HTTP Conflict (409) status when updating
(performing an HTTP PUT on) incidents using the REST API. This status code indicates that the
incident you are modifying has changed since you last read it. Your processor must be written to
handle this situation, generally by re-reading the incident object (using an HTTP GET), reapplying your changes and re-issuing the PUT.
The Resilient examples have accounted for this issue where necessary.

Page 40

Custom Action Developer’s Guide

Resilient Incident Response Platform

6.11. Using a Framework
There are frameworks that may simplify the development of Resilient action processors. You may
want to investigate tools that may simplify the creation of action processors, which generally
follows typical “Enterprise Integration Patterns”. See the following table for ESB and ESB-like
frameworks worthy of investigation.
NOTE: See http://www.enterpriseintegrationpatterns.com for more information about Enterprise
Integration patterns.
IBM Resilient provides a set of action processor components for Python, built with the Circuits
framework. Refer to IBM Resilient Python API for a list of Python library modules.
Product

Language

Description

Apache Camel

Java

An open source framework for creating processing
routes. For example, a route might:

http://camel.apache.org/






Read a message from a queue (Resilient
message destination)
Convert the message payload from a JSON
string to an object
Invoke an HTTP POST on some external service
Send a reply to the Resilient platform

Most of this can be done through XML- or DSL-based
configurations.
There is an example of how you can use Apache
Camel in the Resilient API examples distribution.
Apache ServiceMix ESB

Java

ServiceMix is an OSGi-based Enterprise Service Bus
(ESB). ServiceMix can work seamlessly with Apache
Camel to simplify route creation.

Java

A commercial Enterprise Service Bus (ESB) that
allows you to create graphically action processors
using a number of built-in connectors.

http://servicemix.apache.org/
Mulesoft ESB

http://www.mulesoft.com

There is an example of how you can use Mulesoft in
the Resilient API examples distribution.
Spring Integration

Java

Extends the Spring programming model to support
Enterprise Integration Patterns.

Python

An open source Python-based Enterprise Service
Bus (ESB).

http://projects.spring.io/spring
-integration/
Zato ESB

https://zato.io

6.12. Always Running
It is easy to write an action processor script that uses the Action Module to read rule messages
and perform an operation. When you are developing the script, you can run it from the command
line. However, when you exit the shell or log out of your desktop session, the program exits.
You should consider in advance how you are going to ensure that the program remains running
when the action processor is deployed in the production environment.
If using Python on Unix, consider using the systemd daemon.
If using Java, consider using the Apache Commons Daemon project.

Page 41

Custom Action Developer’s Guide

Resilient Incident Response Platform

6.13. Retry
You should consider how your action processor handles situations where external systems
(including the Resilient platform itself) are inaccessible.
It is generally desirable for action processors to retry their connection to the message destination
indefinitely. Indefinitely retrying to reconnect every 30-60 seconds is reasonable.
If other downstream operations fail, you need to decide how to proceed. It may be sufficient to
simply fail the operation and send a response message to the Resilient platform indicating the
failure, where these messages appear in the Action Status page.
This is one area where an integration framework can help. They generally have built-in support
for error handling. For an example, see the Resilient Action Module Apache Camel example in
the Resilient API distribution.

6.14. Processor Installation
Action processors are frequently written to assume the existence of certain message destinations
and rules. You can create these dependencies using one of the following methods:


Create them manually using the Resilient platform.



Write a program that uses the Resilient REST API to create them.

6.15. Testing Considerations
Many of the design considerations discussed in the previous section lead to useful test cases.
For example, the discussion on Retry leads a tester to a number of test cases dealing with how
the action processor handles situations where other systems are not running or return errors.
The following table contains test cases that serve as a starting point for testing an action
processor.
Test
TLS: Certificate Trust

Description
When you invoke the action processor, you must confirm that a “man-in-the-middle
certificate attack” causes an error and that no data is sent over the connection.
Otherwise, it would be possible for bad code to establish a connection, send
passwords then check for certificate trust. Sending the password over an untrusted
channel would be a security vulnerability.
The simplest way to test this is to configure the client (action processor in this case)
to NOT trust the Resilient platform certificate and confirm that the operation fails
due to a TLS error.

TLS: Certificate
Common Name

If an action processor thinks it is connecting to a host named
“Resilient.mycompany.com” then it is important that the TLS certificate is issued to
“Resilient.mycompany.com”. If not and you proceed sending data, it is possible for a
man-in-the-middle to present a certificate that was issued by a trusted source, but
issued to a different entity (such as www.someothercompany.com). The accepted
best practice for a TLS client to guard against this attack is to check that the
certificate’s common name (or subjectAltName) matches the host to which the
connection is being made.
The simplest way to test is to change your local hosts file to make “testhost” point to
the Resilient platform’s IP address, and then try to connect using testhost. The
connection should fail. Note that this should be performed against both the Resilient
REST API (port 443) and the Action Module server (port 65000 and/or 65001).

Page 42

Custom Action Developer’s Guide

Resilient Incident Response Platform

Test
Retry/Error
Reporting

Always Running

Conflicting Edits

Description
It is important for the action processor to continue operating in the face of
exceptions. The following should be tested:


Does the action processor have a log file?



Does the action processor report errors from external systems?



Does the action processor continue running when the Resilient platform is
down?

The action processor should generally be running.


Does the action processor start automatically when the host on which it runs is
restart?



Does the action processor process survive a user log out?

If the action processor updates the Resilient platform using the REST API, it must be
written to handle situations where another user edits the same object.


Has this situation been accounted for by the developer?



If you invoke a rule when the action processor is stopped, then make another
change to the object (say an incident), then start the action processor. Does the
action processor properly update the incident? Note: If it is not handled by the
developer, then you would likely get an error when the processor attempts to
do the PUT operation.

Action Status Sent

Does the action processor send a status or error message to the Resilient platform as
appropriate? These status messages appear in the Actions > Action Status dialog.

Infinite Loops

Is it possible for the action processor to get into an infinite loop? See the
Co3ContextToken discussion in the Message Headers section.

Page 43

Custom Action Developer’s Guide

Resilient Incident Response Platform

6.16. Example: Creating an Incident
The following is an example of how to create an incident using the API. The example uses the
RESTclient extension for Firefox which provides a curl alternative.
$ curl -X POST -k -H 'Content-Type: application/json' -i
'https://resilient.example.com/rest/session' --data '{"email" :
"resilient.admin@example.com","password":"*****"}' -v

In the response, you want the JSESSIONID and csrf_token.
< Set-Cookie: JSESSIONID=22EDC0CB8A2ECDE8C15A92C05ABC1F90; Path=/; Secure;
HttpOnly
Set-Cookie: JSESSIONID=22EDC0CB8A2ECDE8C15A92C05ABC1F90; Path=/; Secure;
HttpOnly
{"orgs":[{"id":201,"name":"Collaborationben","addr":null,"addr2":null,"cit
y":null,"state":null,"zip":null,"perms":{"administrator":false,"observer":
false,"master_administrator":true,"create_incs":true,"create_shared_layout
":true},"enabled":true,"attachments_enabled":true,"tasks_private":false,"h
as_saml":true,"require_saml":false,"twofactor_auth_domain":null,"has_avail
able_twofactor":false,"authorized_ldap_group":null,"supports_ldap":false,"
incident_deletion_allowed":true,"session_timeout":1200,"effective_permissi
ons":[49,50,51,52,53,85,54,55,56,58,59,60,61,62,63,101,102,103,104,105],"r
ole_handles":[1001],"twofactor_cookie_lifetime_secs":0},{"id":202,"name":"
NYC","addr":null,"addr2":null,"city":null,"state":null,"zip":null,"perms":
{"administrator":false,"observer":false,"master_administrator":true,"creat
e_incs":true,"create_shared_layout":true},"enabled":true,"attachments_enab
led":true,"tasks_private":false,"has_saml":false,"require_saml":false,"two
factor_auth_domain":null,"has_available_twofactor":false,"authorized_ldap_
group":null,"supports_ldap":false,"incident_deletion_allowed":true,"sessio
n_timeout":1200,"effective_permissions":[49,50,51,52,85,53,54,55,56,58,59,
60,61,62,63,101,102,103,104,105],"role_handles":[1013],"twofactor_cookie_l
ifetime_secs":0}],"user_id":15,"user_fname":"Resilient","user_lname":"Admi
n","user_email":"resilient.admin@example.com","saml_alias":null,"csrf_toke
n":"be8bc69380b686782b441e9790eef812","session_ip":"192.168.56.1","next_np
s_survey_date":null,"is_saml":false,"is_ldap":false}

Both the JSESSIONID and csrf_token need to be added as cookies to the next request, shown
below. You may not need to add the csrf_token to the cookies.
$ curl 'https://resilient.example.com/rest/orgs/201/incidents' -H 'Cookie:
CSRF_TOKEN=be8bc69380b686782b441e9790eef812;
JSESSIONID=22EDC0CB8A2ECDE8C15A92C05ABC1F90' -H 'Content-Type:
application/json' -H 'Accept-Language: en-US,en;q=0.9' -H 'Accept: */*' -H
'text_content_output_format: objects_convert' -H 'X-Requested-With:
XMLHttpRequest' -H 'X-sess-id: be8bc69380b686782b441e9790eef812' -H
'Connection: keep-alive' --data-binary
'{"name":"test","discovered_date":1524236957000,"due_date":null}' -k -v

If you do not add discovered_date, it will fail as follows.
{"success":false,"title":null,"message":"Field discovered date is
required.","hints":["field_defs"],"error_code":"generic"}

Page 44

Custom Action Developer’s Guide

Resilient Incident Response Platform

7. JSON Structures in the Resilient
API
JavaScript Object Notation (JSON) is the native format for messages in the Resilient REST API
and in the Actions Module. The following sections provide an outline of the JSON structures in the
Resilient Systems platform, including incidents, tasks, and other objects, without going into
specific details of the programming involved.
The Customer Success Hub contains the complete reference documentation on the REST API.
This reference material includes details of each of the REST methods, their parameters and their
return values. The documentation package is updated with each release of the Resilient platform.

7.1. Basics
An incident is represented as a JSON document, with its various properties (fields), such as the
following example:
{
"discovered_date": 1434029747498,
"name": "Phishing emails"
}
The order of the fields in a JSON document is not important. However, some values are lists,
and the order of items in a list is important.
Formatting and whitespace between the fields is not important. Quotation marks can be singlequote or double-quote, but must not be the “curly quotes” that word-processors like to use.
When you receive incident data from the Resilient platform, it is in the form of a JSON document
with all the incident’s properties. Some of these properties are for internal use and have no
meaning in your application; however, you should retain these properties when sending an
updated JSON document back to the platform.
When you create a new incident, you need only to specify the fields that are required. In a
standard installation without any field customizations, the only two required fields are name and
discovered_date.
In the REST API documentation, these JSON documents are referred to as Data Transfer
Objects (DTO) elements. The Java API includes a set of DTO classes that represent the same
data structures. There are a number of these DTOs. An incident might be represented as an
incidentDTO, or as a fullIncidentDataDTO (which includes more fields), or as a
partialIncidentDTO (which includes fewer fields), depending on the context.

Page 45

Custom Action Developer’s Guide

Resilient Incident Response Platform

7.2. Data Types
The basic data types include text, numbers, dates and times, lists, and more complex values.
Data Type
Text

Description
There are two types of text field: plain text, such as the incident name; and text areas.
Text areas can be multi-line and also have rich-text values, as described in the Rich Text
section.
JSON text values are quoted. To include a quote character within JSON text, it must be
escaped with a backslash. To include a literal backslash, it too must be escaped with a
backslash.

Numbers

Numeric fields in the Resilient platform are integers. They do not support fractional
values.
Fields such as dates and times, and object references are not numeric fields.

Date and Times

All dates and times in the Resilient platform are represented with a numeric value. This
encodes the number of milliseconds since January 1st 1970, UTC.
Depending on how you access the REST APIs, you often need to convert these into a
different representation for display, storage or processing. For example, the value
1439993716000 might be represented as “2015-08-19 14:15:16 UTC”, “08/19/15
09:15:16 -0400” or “Wednesday”.

Boolean

Boolean values are either true or false.

Null

Null values are null.

Lists

A list is a sequence of values. JSON lists are defined with square brackets. A list of
numbers would be represented as [1,2,3]. A list of strings would be represented as ["one",
"two", "three"].

7.3. Other values
Other types of value include object handles (references), which refer to a value that is defined
elsewhere; and structured values, where the value has several components.

Rich Text
Rich text can include a subset of HTML to describe the text formatting. A rich-text value includes
HTML tags such as 
and . If you update incident or other data (round-trip), it is best to keep text-area fields in their original format to avoid accidental updates that might cause loss of formatting or unnecessarily notify users of updates. Page 46 Custom Action Developer’s Guide Resilient Incident Response Platform Object Handles You will often encounter object handles in the Resilient REST API and Actions Module. The handle is a reference to an object that is defined elsewhere and can be referenced by ID. This allows the text of the object to change without having to go back and update every occurrence in the system. In database terms, object handles correspond to foreign keys. For example, the resolution_id field has several valid values: “Unresolved”, “Duplicate”, “Not an Issue” and “Resolved”. Each value has an ID, for example: 53, 54, 55, 56. Internally, the incident stores a reference to the value using its ID. This value may appear in the incident JSON as the ID, { "resolution_id": 53 } or as the string value, { "resolution_id": "Unresolved" } or as the full object: { "resolution_id": {"id": 55, "name": "Unresolved"}} Data is returned from the server with the ID values by default. If you wish to receive name values back for object handle fields from the server instead, you can set handle_format=names either in an HTTP header or a query string; for example: https://example.mycompany.com/rest/orgs/:orgId/incidents?handle_format=nam es) For a description of the possible values of the handle_format query string parameter/HTTP header, refer to objectHandleFormat in the REST API documentation. When setting object handle values, the server works with either format. Numeric values (not quoted) are interpreted as IDs, and string values (surrounded by quotes) are resolved to the underlying IDs by the server. You can also specify the format by setting handle_format=ids in the query string or HTTP header. Structured Values and Custom Fields Some values have multiple parts. For example, the full incident DTO produced by the server includes information about the creator, which is represented as a field with a structured value containing the creator’s name, id, and so on. Custom fields in an incident are represented in a similar way, as values within a group “properties”. For example, if you have defined custom fields with API names “source_types” (a multi-select field), “external_case_id” (a text field) and “cmdb_info” (a hidden text field), the incident JSON might show: { "id": 2269, "properties": { "source_types": [], "external_case_id": "INC00020478", "cmdb_info": null }, "phase_id": 1005 /* etc */ } Page 47

Source Exif Data:
File Type                       : PDF
File Type Extension             : pdf
MIME Type                       : application/pdf
PDF Version                     : 1.5
Linearized                      : No
Page Count                      : 47
Language                        : en-US
Tagged PDF                      : Yes
Producer                        : Microsoft® Word 2013
Creator                         : Microsoft® Word 2013
Create Date                     : 2019:01:03 09:26:19-05:00
Modify Date                     : 2019:01:03 09:26:19-05:00
EXIF Metadata provided by EXIF.tools

Navigation menu