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

More Code Examples