Custom Actions
Custom Actions send a snapshot of the incident data to external code — action processors — when triggered by Resilient rules and workflows. This external code can then perform integration work, for example:
- Performing a lookup for information about a user or machine in an asset database, then updating a data table with the result,
- Searching SIEM logs for additional information related to an IP address, a URL or a server name, then creating a file attachment with the result,
- Using information from the incident, task or artifact to open a ticket in an ITSM system, then tracking the ticket for updates,
- or triggering and updating from any other activity.
In the Resilient platform, a Rule is configured on an incident, an artifact, or other object. When the rule fires, it sends that object to a Message Destination (queue or topic). The Custom Action Processor receives that message, acts on it, and updates the Resilient playbook with the result. This can also be triggered by adding the message destination to a Workflow.
Writing a Custom Action Processor in Python
The Resilient Circuits framework in the Python SDK 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 an Action Message arrives on a Message Destination.
Code Example
This simple script is a component that subscribes to a message destination (type queue) named "example", and handles a custom action named "example_action". The name of the Python class ("MyExampleComponent") is not important, nor is the filename. The class property "channel" determines the name of the message destination that should be subscribed. The class has a method, decorated with @handler() that determines the action(s) to be sent to this custom action.
# 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"])) 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) If the handler function returns a string, that is shown to the Resilient user in the Action Status dialog:
return "Action Processed OK" Configuring Custom Actions
First, configure the Message Destination. Each message destination has an access control list; be sure to add your integration user (the credentials used by your integration to connect to the Resilient platform) to this list.
Next, configure the Resilient platform to send a message to this destination when the action is triggered.
There are several ways to trigger the action message:
- A Menu-Item Rule that posts the transaction to a message destination. The menu-item shows an action on its object (incident, task, etc.) when the conditions are met. With a menu-item rule, such as the example pictured here, you can add Activity Fields for additional user input that is also sent with the message.
- An Automatic Rule that posts the transaction to a Message Destination. The message is sent when an object (incident, task, etc.) 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 at the desired step. Workflows provide lots of flexibility in how these custom actions are coordinated, and are ideal for complex scenarios including task completion, decision logic, scripts, and timers.
Running the Example
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,startupMaxReconnectAttempts=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. 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
The custom menu-item action can be found on the "Actions" menu at the top right of the incident.
If your menu-item action is for Artifact objects, you'll find the menu available from the [...] button beside the artifact; similarly for tasks, notes, and so on.
Select Example Action from the actions menu.
Since this menu-item action includes Action Fields, the Resilient platform shows a dialog for you to complete these fields. Custom actions triggered from automatic rules do not use this.
Press Execute to send the action message to its destination.
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.
Additional Resources
Custom Action Developer's Guide