Best Practices for Building Playbooks
This guide offers essential best practices for designing and building effective playbooks, emphasizing workflow design, sub-playbook efficiency, scalability considerations, and user inputs. Whether optimizing existing playbooks or creating new ones, this document serves as a valuable reference for achieving your playbook development goals.
Designing the Playbook
Effective playbook design is crucial for streamlined automation and orchestration. Begin by carefully crafting an end-to-end workflow, illustrated in a high-level flow diagram. This foundational step provides clarity on the overall process, guiding efficient playbook development. For instance, when creating a playbook to automatically block malicious threats, a simple flow diagram helps visualize and plan the playbook design effectively. The below diagram shows an example.
Efficient Sub-Playbook Design
Here are some of the best practices for using sub-playbooks in playbooks.
Modularity and Reusability: Sub-playbooks must exhibit modularity, ensuring they are easily adaptable for various use cases or integration into master playbooks. For example threat intel enrichment helps provides additional context about incidents and helps resolve the incident faster. Hence, the Enrich Indicators using AbuseIPDB action is a good example of a sub-playbook and can be used as an action in many other playbooks.
Standardized Input and Output: Develop sub-playbooks with standardized inputs and outputs. For instance, a playbook processing IOC values and providing verdict summaries can be reused across diverse scenarios, enhancing flexibility.
Reusable Steps: Identify steps within workflows that are recurrent and may be required multiple times. Design sub-playbooks for such steps, promoting efficiency and consistency in the main workflow.
Asynchronous Sub-Playbooks: Consider the creation of asynchronous sub-playbooks for tasks requiring minimal input from the master playbook. This is beneficial for smaller, independent tasks, such as updating incident notes after creating an incident in the master workflow.
Understanding Scale for Playbook Development
It is important to understand the data utilized by the playbook and the number of sub-playbooks you want to batch to the master playbook. This will help you design the playbook within the features and limits offered by Orchestrate. Here are some of the best practices for understanding the scale of your playbook development.
Assess Data Scale: Before developing a playbook, it's crucial to comprehend the scale it will operate within. Analyze the volume of data to be retrieved or the expected number of source events over a specific time frame to gauge the scale effectively.
Optimize with Batching: Optimize scale by employing batching techniques. Develop sub-playbooks to execute identical tasks with different inputs concurrently. Batching source events can also enhance efficiency, particularly if supported by the data source.
Sub-Playbook Trigger Methods: Optimize scale by choosing the appropriate method for triggering sub-playbooks. Evaluate whether synchronous or asynchronous execution is more suitable based on the nature of the tasks and overall playbook requirements.
User Inputs in Playbook Design
Dependency on User Inputs: Playbook design often involves elements dependent on user inputs, influencing the playbook's behavior during runtime. For example, you can design the playbook to get confirmation from the user before taking a response action. In the below example flowchart, the Await Analyst Confirmation node can be used for user inputs.
Configurable Attributes Using Persistent Lists: Attributes like incident category, incident assignment, or email address of stakeholders, which remain relatively stable, can be configured in advance by users. Utilizing persistent lists to store such variables and values, referenced within the playbook, ensures flexibility. Memory nodes also serve as an alternative to Persistent Lists.
The below example shows a persistent list that contains names and email addresses of customers for sending emails on a daily schedule.
[ { "email_day":"1", "customer_name":"Customer 1", "customer_email":"customer-1@example.com" }, { "email_day":"2", "customer_name":"Customer 2", "customer_email":"customer-2@example.com" } ]
Know more about Persistent List.
Dynamic Variables Requiring User Input: Variables with values frequently changing during each execution, such as approvals for actions or the selection of incident remediation steps, demand user input in real-time. These variables necessitate re-evaluation and user input with each execution for dynamic and adaptable playbook behavior. For example, Incident Unique ID is a variable that changes for every incident data. See Use Email Template in Playbook.
Building the Playbook
Orchestrate's playbook editor simplifies playbook creation. Follow these best practices to create a playbook.
Consistent Naming
Always adhere to a naming convention for clarity and consistency in your documentation or projects. For instance, use the format <primary_technology> :: <use case> to structure your names effectively. This ensures a standardized and easily understandable naming pattern. For example, Splunk :: Threat Hunting.
Node Optimization Guidelines
Memory Nodes
Utilize memory nodes for storing static variables used frequently in the playbook.
Place a memory node at the start for easy modification of declared variables.
Use memory nodes to initialize and store results to be returned via the playbook.
Helpful for playbooks returning multiple data items based on conditional nodes.
Ensures a value is present when returning data from sub-playbooks, even if branches don't execute.
Declare data with a memory node before branching in playbooks with multiple branches.
Learn more about Memory Node
Action Nodes
Enable Abort playbook if this node fails selectively for non-critical path nodes.
Disable Abort playbook if this node fails to handle errors in subsequent custom nodes.
Use Save Node Input to skip saving excessive or sensitive returned data in run logs.
Employ Save Customized Results to parse and retain only required data fields from third-party APIs.
Learn more about Action Nodes
Condition Nodes
Ensure custom condition nodes return boolean values.
Use a single condition node with multiple conditions when executing only one condition is required.
For simultaneous execution of multiple conditions, define each separately in condition nodes. Initialize and save output data from each branch in a memory node for collation if needed.
Learn more about Condition Node
Custom Nodes
Provide comments for better code readability and maintenance.
Adopt a descriptive naming convention. For example, QRadar :: Format Alert Data.
Create one custom node per task for easier maintenance.
Optimize Python scripts for space and time complexity in custom nodes.
Save commonly used Python code, such as loops and conditionals, as code snippets. You can then use these snippets to create custom nodes such as actions and conditions in playbooks.
Learn more about Custom Action Node and Custom Condition Node
Dynamic Paths Best Practices
Use the following best practices to create dynamic paths for playbook creation.
Enhance Reusability: Always use
__instance__
as a placeholder for your app instance name. This enhances playbook reusability.Refer to Cyware Techdocs: Consult Cyware Techdocs for a comprehensive list of keywords and default paths applicable to your playbook. See Use Dynamic Paths.
Utilize Dynamic Paths in Various Scenarios: Dynamic paths are versatile and can be applied in different scenarios:
Fetch input details from previous node output:
${<node number>::__instance__::results::<key>}
Fetch event details as input:
${event::data::<key>}
Fetch input data from memory node:
${const::variable key}
Input data from Input Node:
${_node number::io::field_identifier}
Use various predefined functions or data structures. Examples include:
Current time:
${utils::datetime::now}
Epoch time:
${utils::time::time}
List input:
$LIST[val1, val2, ...]
JSON input:
$JSON[{“key”:”value”}]
Default Value Data Filters: Employ default value data filters to set a default value if the dynamic path fails to receive expected data. Examples include:
${<dynamic path> | default::str::<this is default title>}
${<dynamic path> | default::int::<1>}
${<dynamic path> | default::list::[1,2,3]}
Follow Playbooks
Always ensure to follow playbooks in production environments to stay informed on updates/errors. To learn about different types of notifications in Orchestrate, see Notifications.
Conclusion
In conclusion, navigating the realm of playbook development is an exciting journey. We have covered essential tips for effective design, sub-playbook efficiency, and scalability. To further enhance your skills, feel free to explore additional resources for advanced techniques and the latest updates in playbook development. Below are some useful resources for you to get started.