Armorblox

Armorblox is an API-based platform that stops targeted email attacks, protects sensitive data, and automates incident response.

Email · Armorblox

Details

IDArmorblox
ProviderCisco Systems
CategoryEmail
From Version6.0.0
Docker Imagedemisto/armorblox:1.0.0.10120494
Supported ModulesAgentix XSIAM

README

Armorblox is an API-based platform that stops targeted email attacks,
protects sensitive data, and automates incident response.
This integration was integrated and tested with version 4.3.0 of Armorblox

Configure Armorblox on Cortex XSOAR

  1. Navigate to Settings > Integrations > Servers & Services.
  2. Search for Armorblox.
  3. Click Add instance to create and configure a new integration instance.
  4. Select Fetches incidents to pull incidents from Armorblox to Cortex
  5. Select Classifier as Armorblox-Classifier
  6. Select Mapper as Armorblox-Mapper

    Parameter Required
    Armorblox tenant name True
    Incident type False
    API key True
    Fetch limit False
    First fetch timestamp (last <number> <time unit>, e.g., last7Days) False
    Incidents Fetch Interval False
    Trust any certificate (not secure) False
    Use system proxy settings False
    Fetch incidents False
  7. Click Test to validate the URLs, token, and connection.
  8. Save and Exit to enable the instance.

Commands

You can execute these commands from the Cortex XSOAR CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.

armorblox-check-remediation-action


Check the recommended remediation action for any incident

Base Command

armorblox-check-remediation-action

Input

Argument Name Description Required
incident_id The incident id of the incident under inspection. Required

Context Output

Path Type Description
Armorblox.Threat.remediation_actions string  

Command Example


#### Context Example

{
“Armorblox”:
{
“Threat”:
{
“incident_id”: “5375”,
“remediation_actions”: “NEEDS REVIEW”
}
}
}
```

Human Readable Output

incident_id 5375
remediation_actions NEEDS REVIEW

fetch-incidents


Gets a list of armorblox incidents

Base Command

fetch-incidents

Context Output

There is no context output for this command.

Configuration parameters

  • tenantName — Armorblox tenant name (required)
  • incidentType — Incident type
  • apikey — API key (required)
  • max_fetch — Fetch limit
  • first_fetch — First fetch timestamp
  • incidentFetchInterval — Incidents Fetch Interval
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings
  • isFetch — Fetch incidents

Commands (2)

  • armorblox-check-remediation-action

    Check the recommended remediation action for any incident.

  • fetch-incidents

    Gets a list of armorblox incidents.

import collections
import json
from typing import Any

import dateparser
import demistomock as demisto  # noqa: F401
import urllib3
from armorblox.client import Client as AbxBaseClient  # pylint: disable=E0401,E0611
from CommonServerPython import *  # noqa: F401

# disable insecure warnings
urllib3.disable_warnings()

DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
MAX_INCIDENTS_TO_FETCH = demisto.params().get("max_fetch")
FIRST_FETCH = demisto.params().get("first_fetch")
TENANT_NAME = demisto.params().get("tenantName")
INSECURE = demisto.params().get("insecure")
PROXY = demisto.params().get("proxy")
API_KEY = demisto.params().get("apikey")
verify_certificate = not demisto.params().get("insecure", False)
proxy = demisto.params().get("proxy", False)


class Client(AbxBaseClient):
    """Client class to interact with the service API
    This Client implements API calls, and does not contain any Demisto logic.
    Should only do requests and return data.
    """

    def get_incidents(self, orderBy="ASC", pageSize=None, pageToken=None, first_fetch=None):
        request_params = {"orderBy": orderBy}

        if pageToken == -1 and first_fetch:
            request_params["timeFilter"] = first_fetch
        elif pageToken and first_fetch:
            request_params["timeFilter"] = first_fetch
            request_params["pageToken"] = pageToken

        if pageSize:
            request_params["pageSize"] = pageSize

        response_json, next_page_token, total_count = self.incidents.list(params=request_params)
        return response_json, next_page_token

    def get_incident_details(self, incident_id):
        return self.incidents.get(incident_id)


def makehash():
    return collections.defaultdict(makehash)


def test_module(client: Client) -> str:  # pragma: no coverage
    """Tests API connectivity and authentication'
    Returning 'ok' indicates that the integration works like it is supposed to.
    Connection to the service is successful.
    Raises exceptions if something goes wrong.
    :type client: ``Client``
    :param Client: Armorblox client to use
    :type name: ``str``
    :return: 'ok' if test passed, anything else will fail the test.
    :rtype: ``str``
    """

    try:
        client.get_incidents(pageSize=1)

    except DemistoException as e:
        if "Forbidden" in str(e):
            return "Authorization Error: make sure API Key is correctly set"
        else:
            raise e
    return "ok"


def get_incidents_list(client, pageToken, first_fetch):
    """
    Hits the Armorblox API and returns the list of fetched incidents.
    """
    results, next_page_token = client.get_incidents(pageSize=MAX_INCIDENTS_TO_FETCH, pageToken=pageToken, first_fetch=first_fetch)
    # For each incident, get the details and extract the message_id
    for result in results:
        result["message_ids"] = get_incident_message_ids(client, result["id"])
    return results, next_page_token


def get_incident_message_ids(client, incident_id):
    """
    Returns the message ids for all the events for the input incident.
    """

    detail_response = client.get_incident_details(incident_id)
    message_ids = []
    # loop through all the events of this incident and collect the message ids
    if "events" in detail_response:
        for event in detail_response["events"]:
            message_ids.append(event["message_id"])

    if "abuse_events" in detail_response:
        for event in detail_response["abuse_events"]:
            message_ids.append(event["message_id"])
    return message_ids


def get_remediation_action(client, incident_id):
    """
    Returns the remediation action(s) for the input incident.
    """

    detail_response = client.get_incident_details(incident_id)
    remediation_actions = None
    if "remediation_actions" in detail_response:
        remediation_actions = detail_response["remediation_actions"][0]
    else:
        remediation_actions = None
    contxt = makehash()
    human_readable = makehash()
    human_readable["incident_id"] = incident_id
    human_readable["remediation_actions"] = remediation_actions
    contxt["incident_id"] = incident_id
    contxt["remediation_actions"] = remediation_actions
    return CommandResults(outputs_prefix="Armorblox.Threat", outputs=contxt)


def fetch_incidents_command(client):
    last_run = demisto.getLastRun()
    start_time: Any
    # pageToken fetched from demisto lastRun
    pageToken = 0
    incidents = []
    if "start_time" not in last_run:
        pageToken = -1
        response, next_page_token = client.get_incidents(pageSize=1, pageToken=pageToken, first_fetch=FIRST_FETCH)
        if response:
            response = response[0]
            start_time = response.get("date")
            start_time = dateparser.parse(start_time)
            message_ids = get_incident_message_ids(client, response.get("id"))
            response["message_ids"] = message_ids
            curr_incident = {"rawJSON": json.dumps(response), "details": json.dumps(response)}
            incidents.append(curr_incident)

    if last_run and "pageToken" in last_run:
        pageToken = last_run.get("pageToken")

    if last_run and "start_time" in last_run:
        start_time = dateparser.parse(last_run.get("start_time"))

    start_time = start_time.timestamp()
    incidents_data, pageToken = get_incidents_list(client, pageToken=pageToken, first_fetch=FIRST_FETCH)
    last_time = start_time

    for incident in incidents_data:
        dt = incident.get("date")
        parsed_date = dateparser.parse(dt)
        assert parsed_date is not None, f"failed parsing {dt}"
        dt = int(parsed_date.timestamp())
        # Update last run and add incident if the incident is newer than last fetch
        if dt > int(start_time):
            curr_incident = {"rawJSON": json.dumps(incident), "details": json.dumps(incident)}
            last_time = dt
            incidents.append(curr_incident)
    # Save the next_run as a dict with the start_time key to be stored
    demisto.setLastRun({"start_time": str(last_time), "pageToken": pageToken})
    return incidents


def main():  # pragma: no coverage
    """EXECUTION"""
    demisto.info(f"Command being called is {demisto.command()}")
    try:
        client = Client(api_key=API_KEY, instance_name=TENANT_NAME)
        if demisto.command() == "fetch-incidents":
            incident_results = fetch_incidents_command(client)
            demisto.incidents(incident_results)
            return_results("Incidents fetched successfully!!")
            # return_results(fetch_incidents_command(client))
        if demisto.command() == "armorblox-check-remediation-action":
            incident_id = demisto.args().get("incident_id")
            return_results(get_remediation_action(client, incident_id))

        elif demisto.command() == "test-module":
            result = test_module(client)
            return_results(result)
    except Exception as e:
        return_error(str(e))


if __name__ in ["__main__", "builtin", "builtins"]:
    main()