CyberArk Identity Event Collector

This integration collects events from the Idaptive Next-Gen Access (INGA) using REST APIs.

Analytics & SIEM · CyberArk Identity

Details

IDCyberArk Identity Event Collector
ProviderCyberArk
CategoryAnalytics & SIEM
From Version6.8.0
Docker Imagedemisto/py3-tools:1.0.0.10120494
Supported ModulesAgentix XSIAM

README

CyberArk Identity log event collector integration for Cortex XSIAM.
This integration was integrated and tested with version 22.4 of CyberArk Identity Event Collector.

Configure CyberArk Identity Event Collector in Cortex

Parameter Description Required
Server URL The CyberArk Identity URL to get the logs from. For example, https://{{tenant}}.my.idaptive.app. True
App ID The application ID to fetch the logs from. True
User name The user that was created in CyberArk for the XSIAM integration. For example, admin@example.com. True
Password The password for the user that was created in CyberArk for the XSIAM integration. True
First fetch time The period to retrieve events for.
Format: <number> <time unit>, for example 12 hours, 1 day, 3 months.
Default is 3 days.
True
Maximum number of events per fetch The maximum number of items to retrieve per request from CyberArk’s API. True
Trust any certificate (not secure) When selected, certificates are not checked. False
Use system proxy settings Runs the integration instance using the proxy server (HTTP or HTTPS) that you defined in the server configuration. False

Commands

You can execute these commands from the Cortex XSIAM Alerts War Room 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.

cyberarkidentity-get-events


Returns a list of events

Base Command

cyberarkidentity-get-events

Input

Argument Name Description Required
should_push_events Set this argument to True to create events, otherwise events will only be displayed. Default is False. Required
limit The maximum number of events per fetch. Default is 1000. Optional
from The first fetch time (<number> <time unit>, for example 12 hours, 1 day, 3 months). Default is 3 days. Optional

Context Output

There is no context output for this command.

Command example

!cyberarkidentity-get-events should_push_events=false limit=10 from="3 days"

Human Readable Output

CyberArkIdentity RedRock records

Auth Method Directory Service Uuid From IP Address ID Level Normalized User Request Device OS Request Host Name Request Is Mobile Device Tenant User Guid When Logged When Occurred _ Table Name
None 123456abcdef.123456.abcdef 1.1.1.1 123456abcdef.123456.abcdef Info admin@example.com.11 Unknown 1.1.1.1 false AAM4730 123456abcdef.123456.abcdef /Date(1652376432605)/ /Date(1652376432605)/ events
None 123456abcdef.123456.abcdef 1.1.1.1 123456abcdef.123456.abcdeg Info admin@example.com.11 Unknown 1.1.1.1 false AAM4730 123456abcdef.123456.abcdef /Date(1652376492682)/ /Date(1652376492682)/ events
None 123456abcdef.123456.abcdef 1.1.1.1 123456abcdef.123456.abcdeh Info admin@example.com.11 Unknown 1.1.1.1 false AAM4730 123456abcdef.123456.abcdef /Date(1652376552546)/ /Date(1652376552546)/ events

Configuration parameters

  • url — Server URL (required)
  • app_id — App ID (required)
  • credentials — User name (required)
  • from — First fetch time (required)
  • limit — Maximum number of events per fetch (required)
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings

Commands (1)

  • cyberarkidentity-get-events

    Returns a list of events

# pylint: disable=no-name-in-module
# pylint: disable=no-self-argument
import urllib3
from SiemApiModule import *  # noqa: E402

urllib3.disable_warnings()

# -----------------------------------------  GLOBAL VARIABLES  -----------------------------------------
DATETIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%f"
EVENT_FIELDS = [
    "ID",
    "EventType",
    "AuthMethod",
    "DirectoryServiceUuid",
    "DirectoryServicePartnerName",
    "EntityName",
    "EntityType",
    "EntityUuid",
    "FromIPAddress",
    "ImpersonatorUuid",
    "Level",
    "NewEntity",
    "NormalizedUser",
    "OldEntity",
    "RequestDeviceOS",
    "RequestHostName",
    "RequestIsMobileDevice",
    "Tenant",
    "UserGuid",
    "WhenLogged",
    "WhenOccurred",
    "ObjectName",
    "ObjectType",
    "RoleId",
    "Role",
    "Changer",
    "ChangerUuid",
    "Result",
    "Alias",
    "ReplaceDomain",
    "Type",
    "Id",
    "ProfileName",
    "Thumbprint",
    "TargetUserID",
    "TargetUser",
    "Uuid",
    "Key",
    "Value",
    "UserState",
    "PreviousUserState",
    "FailedMessage",
    "Exception",
    "DSType",
    "DSName",
    "DSUuid",
    "ImpersonateTargetUuid",
    "ImpersonateTargetName",
    "EmailAddress",
    "Session",
    "MfaResult",
    "MfaReason",
    "SetPath",
    "ProxyId",
    "MachineName",
    "ClientAddress",
    "ConnectorUuid",
    "HostAddress",
    "UserName",
    "Target",
    "Cname",
    "OldState",
    "NewState",
    "AffectedTenant",
    "OU",
    "DeviceID",
    "EnrollProfileUser",
    "LocalAccountUuid",
    "DeviceName",
    "FailureReason",
    "From",
    "To",
    "Description",
    "DeleteReason",
    "LicenseType",
    "NewLicenseType",
    "OldLicenseType",
    "ApplicationType",
    "ApplicationName",
    "ApplicationID",
    "MobileAppType",
    "AppId",
    "AppName",
    "JobUniqueId",
    "SyncAction",
    "SyncActionReason",
    "SyncResult",
    "SessionId",
]
PRODUCT = "identity"
VENDOR = "cyberark"


class CyberArkIdentityEventsOptions(IntegrationOptions):
    app_id: str


class CyberArkIdentityEventsRequest(IntegrationHTTPRequest):
    method: Method = Method.POST
    headers: dict = {"Accept": "*/*", "Content-Type": "application/json"}


class CyberArkIdentityEventsClient(IntegrationEventsClient):
    request: IntegrationHTTPRequest
    options: CyberArkIdentityEventsOptions

    def __init__(
        self,
        request: CyberArkIdentityEventsRequest,
        options: CyberArkIdentityEventsOptions,
        credentials: Credentials,
        session=requests.Session(),
    ) -> None:
        self.access_token = None
        self.credentials = credentials
        super().__init__(request, options, session)

    def set_request_filter(self, after: Any):
        return after

    def authenticate(self):
        credentials = base64.b64encode(f"{self.credentials.identifier}:{self.credentials.password}".encode()).decode()
        request = IntegrationHTTPRequest(
            method=Method.POST,
            url=f"{str(self.request.url).removesuffix('/RedRock/Query')}/oauth2/platformtoken",  # type: ignore[arg-type]
            headers={"Authorization": f"Basic {credentials}"},
            data={"grant_type": "client_credentials", "scope": "siem"},
            verify=self.request.verify,
        )

        response = self.call(request)
        if response.ok:
            demisto.debug("authenticated successfully")
            self.access_token = response.json()["access_token"]
            self.request.headers["Authorization"] = f"Bearer {self.access_token}"
        else:
            demisto.debug(f"authentication failed: {response.json()}")


class CyberArkIdentityGetEvents(IntegrationGetEvents):
    client: CyberArkIdentityEventsClient

    @staticmethod
    def get_last_run_ids(events: list) -> list:
        return [event.get("ID") for event in events]

    @staticmethod
    def get_last_run_time(events: list) -> str:
        # The date is in timestamp format and looks like {'WhenOccurred': '/Date(1651483379362)/'}
        last_timestamp = max([int(e.get("WhenOccurred", "").removesuffix(")/").removeprefix("/Date(")) for e in events])

        return datetime.utcfromtimestamp(last_timestamp / 1000).strftime(DATETIME_FORMAT)

    def get_last_run(self, events: list) -> dict:  # type: ignore
        return {"from": self.get_last_run_time(events), "ids": self.get_last_run_ids(events)}

    def _iter_events(self):
        self.client.authenticate()

        result = self.client.call(self.client.request).json()["Result"]

        events = result.get("Results")
        if events:
            fetched_events_ids = demisto.getLastRun().get("ids", [])
            yield [event.get("Row") for event in events if event.get("Row", {}).get("ID") not in fetched_events_ids]


def get_request_params(**kwargs: dict) -> dict:
    fetch_from = str(kwargs.get("from", "3 days"))
    default_from_day = datetime.now() - timedelta(days=3)
    from_time = datetime.strftime(dateparser.parse(fetch_from, settings={"TIMEZONE": "UTC"}) or default_from_day, DATETIME_FORMAT)

    params = {
        "url": f"{str(kwargs.get('url', '')).removesuffix('/')}/RedRock/Query",
        "data": json.dumps(
            {
                "Script": f"Select {', '.join(EVENT_FIELDS)} from Event where WhenOccurred > '{from_time}'",
                "args": {"PageNumber": 1, "PageSize": kwargs.get("limit", 1000)},
            }
        ),
        "verify": not kwargs.get("insecure"),
    }
    return params


def main(command: str, demisto_params: dict):
    credentials = Credentials(**demisto_params.get("credentials", {}))
    options = CyberArkIdentityEventsOptions(**demisto_params)
    request_params = get_request_params(**demisto_params)
    request = CyberArkIdentityEventsRequest(**request_params)
    client = CyberArkIdentityEventsClient(request, options, credentials)
    get_events = CyberArkIdentityGetEvents(client, options)

    try:
        if command == "test-module":
            get_events.run()
            demisto.results("ok")

        if command in ("fetch-events", "cyberarkidentity-get-events"):
            events = get_events.run()

            if command == "fetch-events" or demisto_params.get("should_push_events"):
                send_events_to_xsiam(events, vendor=VENDOR, product=PRODUCT)
                if events:
                    last_run = get_events.get_last_run(events)
                    demisto.debug(f"Set last run to {last_run}")
                    demisto.setLastRun(last_run)

            if command == "cyberarkidentity-get-events":
                command_results = CommandResults(
                    readable_output=tableToMarkdown(
                        "CyberArk Identity RedRock records", events, removeNull=True, headerTransform=pascalToSpace
                    ),
                    raw_response=events,
                )
                return_results(command_results)

    except Exception as e:
        return_error(str(e))


if __name__ in ("__main__", "__builtin__", "builtins"):
    # Args is always stronger. Get getIntegrationContext even stronger
    demisto_params_ = demisto.params() | demisto.args() | demisto.getLastRun()
    main(demisto.command(), demisto_params_)