Tines

runZero integrates with Tines to help you automate workflows related to your asset data. This helps teams leverage runZero to the fullest while optimizing the team’s workflows with automation. A video demo is available to show the final outcome of these instructions.

Requirements

  • A Tines account
  • runZero Export API and Organization API tokens

There are two ways to integrate runZero and Tines:

Tines custom story

A Tines story is a collection of actions that work together towards a specific goal, like a playbook. Tines has a Story Library that contains ready-made automated playbooks, or you can create a your own custom story if they don’t have one that matches your needs. That’s what we’ll need to do here.

Step 1: Creating a Tines story and adding runZero API credentials

  1. After logging in to Tines, create a new story.
  2. Use the + in the credentials section to add a text credential.
  3. Use the + in the credentials section to add another text credential.

Step 2: Creating a Tines webhook action

  1. Add a Webhook action to your story.
  2. Click the Webhook action and copy the webhook URL, which will look like https://<tenant-name>.tines.com/webhook/<guid>.

Step 3: Creating a runZero alert template

  1. Create an alert template in runZero:
    • Name: name for template
    • Template type: JSON
    • Subject line for message: leave empty
    • Body of message: the following JSON example will include the rule name and the search URL in the alert message body: {"rule_name":"{{rule.name}}","search_url":"{{search.url}}"}
  2. Create an alert channel in runZero:
    • Name: name for alert channel
    • Channel type: webhook
    • Webhook URL: the webhook URL you copied from Tines

Step 4: Creating a rule in runZero

Now that you have your template ready to go, you will want to identify which triggers to alert on. Some common examples are:

  • Asset query results - When there is a match on a query in runZero after a scan completes
  • New assets found - When a scan completes with new assets
  • Agent offline - When your runZero Explorer stops checking in to the console
  • Task failed - When a task fails for any reason

We will use the asset query results selection for the rest of the steps. Our example will be any asset that has an open Telnet port port:23. You can see more example queries here.

  1. Create an alert rule.
  2. Select asset-query-results and click Configure rule.
  3. Input values for the rule:
    • Name: name of the rule.
    • Conditions: optional parameters that will trigger the alert when all conditions match.
      • Query: query the assets must match, such as port:23 for our example.
      • Number of matches: the numeric comparison logic for the value.
      • Value: the threshold of matches to trigger the rule.
      • Limit to organization: allows you to limit the alert to a specific organization in runZero
      • Limit to site: allows you to limit the alert to a specific site in runZero
      • Action: notify
        • Notification channel: name of the alert channel you created in step 2.
        • Notification template: name of the alert template you created in step 2.

Step 5: Handling the data in Tines

  1. The Webhook action created in Step 2 will be the entry point for the runZero alert in Tines.
  2. Add an Event Transform to parse the search from the URL provided in the runZero alert. If you connect the Webhook action to this one, some parameters will automatically populate.
    • Mode: extract
    • Matchers:
      • Path: path_to_alert_search, for example receive_alerts_from_runzero.body.search_url if your Webhook action is named “RECEIVE alerts from runZero”
      • Regex: \?.*
      • Extract to: search
  3. Add an Event Transform that takes the output of the previous step. If you connect the previous Event Transform action with this one, some parameters will automatically populate.
    • Mode: explode
    • Matchers:
      • Path: path_to_extraction_transform, for example get_search_from_url.search if your previous Event Transform action is named “GET search from URL”
      • To: individual_item
  4. Add an HTTP Request to make an API call to the runZero Export API.
    • URL: the path_to_explosion_transform added to the end of the runZero API URL endpoint, for example https://console.runZero.com/api/v1.0/export/org/assets.json<<get_search_from_regex.individual_item>> if your previous Event Transform action is named “GET search from regex”
    • Content Type: JSON
    • Method: get
    • Use the + Option button to add Headers:
      • Change header to Authorization
      • Change value to Bearer CREDENTIAL.runzero_export_token
  5. Add an Event Transform that takes the runZero Export API output and loops through each value.
    • Mode: explode
    • Path: path_to_HTTP_request, for example get_assets_from_runzero.body if your HTTP Request action is named “GET assets from runZero”
    • To: individual_item

Step 6: Personalized automation in Tines

Now that you have received the alert, parsed the search, and obtained the assets from the runZero Export API, it’s time to add your own flare. While you will likely want to do something more crafty, the sample story provided includes these two actions as examples.

  1. Send an email to the destination of your choice for each asset. The sample JSON shows how you might customize it to put the context you’d like in the Subject and Body of the email.
  2. The HTTP Request action shows how you might reach back into runZero to add tags to the assets after other data is gathered.

runZero sample story

The sample story below can be imported to Tines to do all of the actions outlined in the steps above. Simply save a JSON file with the contents below, and use the Import button in Tines to upload it. After importing, you will need to complete the following steps.

Step 1: Update credentials in Tines

  1. Replace the runzero_export_token credential:
  2. Replace the runzero_org_token credential:

Step 2: Create runZero alert template

  1. Create an alert template in runZero:
    • Name: name for template
    • Template type: JSON
    • Subject line for message: leave empty
    • Body of message: the following JSON example will include the rule name and the search URL in the alert message body: {"rule_name":"{{rule.name}}","search_url":"{{search.url}}"}
  2. Create an alert channel in runZero:
    • Name: name for alert channel
    • Channel type: webhook
    • Webhook URL: the webhook URL you copied from Tines

Step 3: Create the rule in runZero

Now that you have your template ready to go, you will want to identify which triggers to alert on. Some common examples are:

  • Asset query results: when there is a match on a query in runZero after a scan completes.
  • New assets found: when a scan completes with new assets.
  • Agent offline: when your runZero Explorer stops checking in to the console.
  • Task failed: when a task fails for any reason.

We will use the asset query results selection for the rest of the steps. Our example will be any asset that has an open Telnet port port:23. You can see more example queries here.

  1. Create a new alert rule.
  2. Select asset-query-results and click Configure rule.
  3. Input values for the rule:
    • Name: name of the rule.
    • Conditions: optional parameters that will trigger the alert when all conditions match.
      • Query: query the assets must match, such as port:23 for our example.
      • Number of matches: the numeric comparison logic for the value.
      • Value: the threshold of matches to trigger the rule.
      • Limit to organization: allows you to limit the alert to a specific organization in runZero
      • Limit to site: allows you to limit the alert to a specific site in runZero
      • Action: notify
        • Notification channel: name of the alert channel you created in step 2.
        • Notification template: name of the alert template you created in step 2.

runZero sample story JSON

{
  "schema_version": 4,
  "standard_lib_version": 6,
  "name": "runZero Sample Story",
  "description": null,
  "guid": "7706b502e51b4c68f0dbe9721c88d665",
  "slug": "runzero_sample_story",
  "exported_at": "2022-10-27T22:22:37Z",
  "agents": [
    {
      "type": "Agents::WebhookAgent",
      "name": "RECEIVE alerts from runZero",
      "disabled": false,
      "guid": "ab1f5bf7be49c943d893ab993ade9421",
      "options": {
        "path": "da6e90c0b276bdda97e6bfa31ad50787",
        "secret": "5e290305e0a483bf843f1213f0f21dda",
        "verbs": "get,post"
      },
      "reporting": {
        "time_saved_value": 0,
        "time_saved_unit": "minutes"
      },
      "monitoring": {
        "monitor_all_events": false,
        "monitor_failures": false,
        "monitor_no_events_emitted": null
      },
      "width": null
    },
    {
      "type": "Agents::HTTPRequestAgent",
      "name": "GET assets from runZero",
      "disabled": false,
      "guid": "d54d8f3f5b0ea857308f45f61a224547",
      "options": {
        "url": "https://console.runZero.com/api/v1.0/export/org/assets.json<<get_search_from_regex.individual_item>>",
        "content_type": "application_json",
        "method": "get",
        "headers": {
          "Authorization": "Bearer <<CREDENTIAL.runzero_export_token>>"
        }
      },
      "reporting": {
        "time_saved_value": 0,
        "time_saved_unit": "minutes"
      },
      "monitoring": {
        "monitor_all_events": false,
        "monitor_failures": false,
        "monitor_no_events_emitted": null
      },
      "width": null,
      "schedule": []
    },
    {
      "type": "Agents::EventTransformationAgent",
      "name": "GET search from URL",
      "disabled": false,
      "guid": "d62ddd189bb9080d778d900f2292504d",
      "options": {
        "mode": "extract",
        "matchers": [
          {
            "path": "=receive_alerts_from_runzero.body.search_url",
            "regexp": "\\?.*",
            "to": "search"
          }
        ]
      },
      "reporting": {
        "time_saved_value": 0,
        "time_saved_unit": "minutes"
      },
      "monitoring": {
        "monitor_all_events": false,
        "monitor_failures": false,
        "monitor_no_events_emitted": null
      },
      "width": null,
      "schedule": null
    },
    {
      "type": "Agents::EventTransformationAgent",
      "name": "GET search from regex",
      "disabled": false,
      "guid": "41afc5c4d4c0fdb694d14e1eb380688a",
      "options": {
        "mode": "explode",
        "path": "=get_search_from_url.search",
        "to": "individual_item"
      },
      "reporting": {
        "time_saved_value": 0,
        "time_saved_unit": "minutes"
      },
      "monitoring": {
        "monitor_all_events": false,
        "monitor_failures": false,
        "monitor_no_events_emitted": null
      },
      "width": null,
      "schedule": null
    },
    {
      "type": "Agents::EventTransformationAgent",
      "name": "LOOP through assets for follow up actions",
      "disabled": false,
      "guid": "b9ada61162bdf006f09d264845ebd304",
      "options": {
        "mode": "explode",
        "path": "=get_assets_from_runzero.body",
        "to": "individual_item"
      },
      "reporting": {
        "time_saved_value": 0,
        "time_saved_unit": "minutes"
      },
      "monitoring": {
        "monitor_all_events": false,
        "monitor_failures": false,
        "monitor_no_events_emitted": null
      },
      "width": null,
      "schedule": null
    },
    {
      "type": "Agents::EmailAgent",
      "name": "SEND Email Action",
      "disabled": false,
      "guid": "0e9647b114f315d480f1f85c58e481d3",
      "options": {
        "recipients": "youremail@email.com",
        "reply_to": "youremail@email.com",
        "sender_name": "Your Name",
        "subject": "<<receive_alerts_from_runzero.body.rule_name>>",
        "body": "Alert: <<receive_alerts_from_runzero.body.rule_name>>\n\\<br />\n\\<br />\nLink to asset: https://console.runzero.com/inventory/<<loop_through_assets_for_follow_up_actions.individual_item.id>>\n\\<br />\n\\<br />\nAddresses: <<loop_through_assets_for_follow_up_actions.individual_item.addresses>>\n\\<br />\n\\<br />\nServices:\n<<NEWLINE_TO_BR(NEAT_JSON(loop_through_assets_for_follow_up_actions.individual_item.services))>>"
      },
      "reporting": {
        "time_saved_value": 0,
        "time_saved_unit": "minutes"
      },
      "monitoring": {
        "monitor_all_events": false,
        "monitor_failures": false,
        "monitor_no_events_emitted": null
      },
      "width": null,
      "schedule": null
    },
    {
      "type": "Agents::HTTPRequestAgent",
      "name": "TAG assets in runZero",
      "disabled": false,
      "guid": "c3171fed91ec40d39572260295a63ae0",
      "options": {
        "url": "https://console.runZero.com/api/v1.0/org/assets/<<loop_through_assets_for_follow_up_actions.individual_item.id>>/tags",
        "content_type": "application_json",
        "method": "patch",
        "headers": {
          "Authorization": "Bearer <<CREDENTIAL.runzero_org_token>>"
        },
        "payload": {
          "tags": "hello=from_tines"
        }
      },
      "reporting": {
        "time_saved_value": 0,
        "time_saved_unit": "minutes"
      },
      "monitoring": {
        "monitor_all_events": false,
        "monitor_failures": false,
        "monitor_no_events_emitted": null
      },
      "width": null,
      "schedule": []
    }
  ],
  "diagram_notes": [
    {
      "content": "Hello! Thanks for importing the runZero Sample Story. \n\nThis story is a basic example of what you can do with runZero and Tines. \n\nPrerequisites:\n1. Create a text [credential](https://www.tines.com/docs/credentials/text) called `runzero_export_token`. Set the value as your [runZero export token](docs/leveraging-the-api.md), which can be obtained from the desired [runZero organization](https://console.runzero.com/organizations) page. Export tokens start with `ET`.\n2. Create a text [credential](https://www.tines.com/docs/credentials/text) called `runzero_org_token`. Set the value as your as your [organization API token](docs/leveraging-the-api.md), which can be obtained from the desired [runZero organization](https://console.runzero.com/organizations). Organization API tokens start with `OT`. \n\nThe steps are as follows:\n\n1. **RECEIVE alerts** provides the webhook destination for your runZero alerts \n\n2. **GET search from URL** parses out the search string from the URL provided in the runZero alert \n\n3. **GET search from regex** takes the list provided in step 2 and allows you to use the individual value \n\n4. **GET assets from runZero** uses the runZero Export API to get the list of assets related to the alert \n\n5. **LOOP through assets for follow up actions** takes the list of assets and sends each to the next steps individually \n\n6. **NOTE**: this is the step that you could implement more custom logic in most cases. All of the initial runZero and Tines data transfer is done, but it's your chance to customize this story to fit your use case. \n\n7. **SEND email action** simply sends an email to the destination of your choice \n\n8. **TAG assets in runZero** adds a tag in runZero to each asset showing an example of how you might reach back into runZero after doing other automated activities ",
      "position": [
        165.0,
        180.0
      ],
      "guid": "0e4b9b331dc65316849f7b089bf7bde2",
      "width": 375
    }
  ],
  "links": [
    {
      "source": 0,
      "receiver": 2
    },
    {
      "source": 1,
      "receiver": 4
    },
    {
      "source": 2,
      "receiver": 3
    },
    {
      "source": 3,
      "receiver": 1
    },
    {
      "source": 4,
      "receiver": 6
    },
    {
      "source": 4,
      "receiver": 5
    }
  ],
  "diagram_layout": "{\"ab1f5bf7be49c943d893ab993ade9421\":[555,180],\"d54d8f3f5b0ea857308f45f61a224547\":[555,450],\"d62ddd189bb9080d778d900f2292504d\":[555,270],\"41afc5c4d4c0fdb694d14e1eb380688a\":[555,360],\"b9ada61162bdf006f09d264845ebd304\":[555,555],\"0e9647b114f315d480f1f85c58e481d3\":[555,690],\"c3171fed91ec40d39572260295a63ae0\":[780,690]}",
  "send_to_story_enabled": false,
  "entry_agent_guid": null,
  "exit_agent_guids": [],
  "exit_agent_guid": null,
  "keep_events_for": 604800,
  "reporting_status": true,
  "send_to_story_access": null,
  "send_to_stories": [],
  "form": null,
  "forms": []
}