Chronicle Search API

The Chronicle APIs enable customers to programmatically access their security data directly through API calls to the Chronicle platform that stores and processes the data. This is the same security data presented in the Chronicle UI through your Chronicle customer account.

This capability enables you to develop new applications or modify existing applications to retrieve and process all your security data currently stored in Chronicle.

How to authenticate with the Chronicle API

This Chronicle API uses the OAuth 2.0 protocol for authentication and authorization. Your application can complete these tasks using either of the following implementations:

  • Using the Google API client library for your computer language.

  • Directly interfacing with the OAuth 2.0 system using HTTP.

See the reference documentation for the Google Authentication library in Python.

Google Authentication libraries are a subset of the Google API client libraries. See other language implementations.

Getting API authentication credentials

Your Chronicle representative will provide you with a Google Developer Service Account Credential to enable the API client to communicate with the API.

You also need to provide the Auth Scope when initializing your API client. OAuth 2.0 uses a scope to limit an application's access to an account. When an application requests a scope, the access token issued to the application is limited to the scope granted.

Use the following scope to initialize your Google API client:

https://www.googleapis.com/auth/chronicle-backstory

Python example(:.hide-from-toc}

The following Python example demonstrates how to use the OAuth2 credentials and HTTP client using google.oauth2 and googleapiclient.

# Imports required for the sample - Google Auth and API Client Library Imports.
# Get these packages from https://pypi.org/project/google-api-python-client/ or run $ pip
# install google-api-python-client from your terminal
from google.oauth2 import service_account
from googleapiclient import _auth

SCOPES = ['https://www.googleapis.com/auth/chronicle-backstory']

# The apikeys-demo.json file contains the customer OAuth 2 credentials.
# SERVICE_ACCOUNT_FILE is the full path to the apikeys-demo.json file
# ToDo: Replace this with the full path to your OAuth2 credentials
SERVICE_ACCOUNT_FILE = '/customer-keys/apikeys-demo.json'

# Create a credential using Google Developer Service Account Credential and Chronicle API
# Scope.
credentials = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)

# Build an HTTP client to make authorized OAuth requests.
http_client = _auth.authorized_http(credentials)

# <your code continues here>

Examples (in Python) for making OAuth authenticated requests to the Chronicle API are provided for each API call referenced in this document.

Search API query limits

The Search API enforces limits on the volume of requests that can be made by any one customer against the Chronicle platform. If you reach or exceed the query limit, the Chronicle API server returns HTTP 429 (RESOURCE_EXHAUSTED) to the caller. When developing applications for the Chronicle API, Chronicle recommends that you enforce rate limits within your system to avoid resource exhaustion. These limits apply to all of the Chronicle APIs, including Search, Customer Management, and Tooling.

The following limits are currently being enforced and are measured in queries per second (QPS):

API API Method Limit
Search List Alerts 1 QPS
ListEvents 1 QPS
ListIocs 1 QPS
ListIocDetails 1 QPS
ListAssets 5 QPS

Frequently asked questions

How Do You Specify Time?

For all of the methods requiring time values, enter time using the time standard defined in RFC 3339. Time is represented by the span of UTC time since Unix epoch 1970-01-01T00:00:00Z.

What is the Page Size Property?

For each API call, you can specify the page_size property to limit the maximum number of returned results. There is no next page token, so if you need to limit the volume of data returned, specify a narrower time range.

What Is an Artifact?

An artifact is an identifier like a website domain, file hash, or IP address that is used to identify a malicious website, file, or computer system that might be contacted or used by a device in your environment.

Artifacts can be any of the following:

  • Domain name
  • Destination IP address
  • File hash (MD5, SHA1, SHA256)

What is an Asset?

An asset is a system within your enterprise that might have been impacted by a security incident. Assets are identified by any of the following:

  • Hostname
  • IP address
  • MAC address
  • Product ID

Search API reference

ListAlerts

Returns information about both asset-based and user-based alerts with event timestamps within the specified time range.

Request

https://backstory.googleapis.com/v1/alert/listalerts?start_time=time&end_time=time&page_size=size
Sample request
https://backstory.googleapis.com/v1/alert/listalerts?start_time=2019-10-15T00:00:00Z&end_time=2019-10-17T00:00:00Z&page_size=1
URL parameters
Parameter names Value Description
start_time string RFC 3339 formatted date and time string which is the earliest event timestamp of alerts returned. For example, "2020-09-17T07:40:48.129Z"
end_time string RFC 3339 formatted date and time string which is the latest event timestamp of the alerts returned. For example, "2020-09-18T07:16:15.000Z"
page_size integer Specify the maximum number of alerts to return. You can specify between 1 and 100,000. The default is 10,000.

Response

The response returned is a tuple containing two items:

  • Position 0—Contains a response object which stores the status of the request and other information.
  • Position 1—Contains the alerts if the call is successful. This is a JSON string with two top level keys: alerts and userAlerts.
    • The alert key stores a list of one or more JSON strings. Each item in the list is a single asset-based alert.
    • The userAlert key stores a list of one or more JSON strings. Each item in the list is a single user-based alert.

Each alert returned contains the original event in two different formats:

  • Raw log event is stored as a base64-encoded string using the uri key.
  • UDM-structured event is stored using the udmEvent key.

Each alert returned contains the original event in two different formats:

The following example response contains one asset-based alert and one user-based alert.

{
 "alerts": [{
   "asset": {
     "hostname": "host1234.altostrat.com"
   },
   "alertInfos": [{
      "name": "Antimalware Action Taken",
      "sourceProduct": "Microsoft ASC",
      "severity": "HIGH",
      "timestamp": "2020-11-15T07:21:35Z",
      "rawLog": "<omitted for simplicity>",
      "uri": ["<omitted for simplicity>"],
      "udmEvent":{
          "metadata": {
          "eventTimestamp": "2020-11-15T07:21:35Z",
          "eventType": "SCAN_FILE",
          "vendorName": "Microsoft",
          "productName": "ASC",
          "productEventType": "Antimalware Action Taken",
          "description": "<omitted for simplicity>",
          "urlBackToProduct": "<omitted for simplicity>",
          "ingestedTimestamp": "2020-11-30T19:01:11.486605Z"
          },
     "principal": {
     "hostname": "host1234.altostrat.com"
     },
       "target": {
         "file": {
         "fullPath": "<omitted for simplicity>"
         }
        },
       "securityResult": [{
          "threatName": "WS.Reputation.1",
          "ruleName": "AntimalwareActionTaken",
          "summary": "Antimalware Action Taken",
          "description": "<omitted for simplicity>",
          "severity": "HIGH"
        }]
      }
   }]
 }],
 "userAlerts": [{
   "user": {
     "email": "john.doe@altostrat.com"
   },
   "alertInfos": [{
     "name": "<omitted for simplicity>",
     "sourceProduct": "Office 365 Security and Compliance",
     "timestamp": "2020-11-15T13:15:00Z",
     "rawLog": "<omitted for simplicity>",
     "uri": ["<omitted for simplicity>"],
     "udmEvent": {
       "metadata": {
         "eventTimestamp": "2020-11-15T13:15:00Z",
         "eventType": "EMAIL_TRANSACTION",
         "vendorName": "Microsoft",
         "productName": "Office 365 Security and Compliance",
         "productEventType": "<omitted for simplicity>",
         "description": "<omitted for simplicity>",
         "ingestedTimestamp": "2020-11-30T18:29:36.164727Z"
       },
       "securityResult": [{
         "ruleName": "ThreatManagement",
         "summary": "Email reported by user as malware or phish",
         "description": "<omitted for simplicit>",
         "severity": "INFORMATIONAL"
       }],
       "network": {
         "email": {
           "from": "Webinars\\\\u003cwebinars@example.com\\\\u003e",
           "to": ["john.doe@altostrat.com"]
         }
       }
     }
   }]
 }]
}

Python sample code

def call_list_alerts():
  # Imports required for the sample - Google Auth and API Client Library Imports.
  # Get these packages from https://pypi.org/project/google-api-python-client/ or 
  # run $ pip install google-api-python-client from your terminal
  import os
  from google.oauth2 import service_account
  from googleapiclient import _auth

  # Constants
  SCOPES = ['https://www.googleapis.com/auth/chronicle-backstory']
  # Change to the location you placed your JSON file.
  SERVICE_ACCOUNT_FILE = os.path.join(os.environ['HOME'], 'bk_credentials.json') 

  # Create a credential using Google Developer Service Account Credential and Chronicle API scope.
  credentials = service_account.Credentials.from_service_account_file(
        SERVICE_ACCOUNT_FILE, scopes=SCOPES)

  # Build an HTTP client which can make authorized OAuth requests.
  http_client = _auth.authorized_http(credentials)

  # Construct the URL
  BACKSTORY_API_V1_URL = 'https://backstory.googleapis.com/v1'
  LIST_ALERTS_URL = '{}/alert/listalerts?start_time=2019-10-15T00:00:00Z&end_time=2019-10-17T00:00:00Z&page_size=1'.format
  (BACKSTORY_API_V1_URL)

  # Make a request
  response = http_client.request(LIST_ALERTS_URL, 'GET')

  # Parse the response
  if response[0].status == 200:
    alerts = response[1]
    # List of alerts returned for further processing
    print(alerts)
  else:
    # Something went wrong. See the response for details.
    err = response[1]
    print(err)

ListAssets

For your enterprise, given the specified artifact, list all the assets that accessed it within the specified time period, including the first and last time those assets accessed the artifact. This call returns a maximum of 100 assets per request. You can specify a narrower time period to reduce the number of assets returned.

Request

https://backstory.googleapis.com/v1/artifact/listassets?start_time=time&end_time=time&artifact.type=value&page_size=size

Sample request

https://backstory.googleapis.com/v1/artifact/listassets?start_time=2019-10-15T00:00:00Z&end_time=2019-10-17T00:00:00Z&artifact.domain_name=www.altostrat.com&page_size=1

URL parameters

Parameter name Value Description
artifact.domain_name domain name Specify the artifact indicator associated with the assets. You can only specify a single artifact. The artifact indicator may either be a domain name, a destination IP address, or a file hash (one of MD5, SHA1, SHA256).
artifact.destination_ip_address destination IP address
artifact.hash_md5 MD5 hash
artifact.hash_sha1 SHA1 hash
artifact.hash_sha256 SHA256 hash
start_time time Start time for your request.
end_time time End time for your request.
page_size integer Specify the maximum number of assets to return. You can specify between 1 and 10,000. The default is 10,000.

Response

This method responds with a list of the assets associated with the artifact, as well as a URI to link to asset view in the Chronicle user interface.

The assets are identified by their asset indicator and could be any of the following:

  • Hostname
  • IP address
  • MAC address
  • Product ID

Sample response

{
  assets: [
    {
      asset:  {
        hostname: "rick"
      },
      firstSeenArtifactInfo: {
        artifactIndicator: {
          domainName: "www.altostrat.com"
         },
        seenTime: "2018-09-14T20:10:27.157476Z"
      },
      lastSeenArtifactInfo:  {
        artifactIndicator: {
          domainName: "www.altostrat.com"
         },
        seenTime: "2019-10-24T22:04:04.327829Z"
      }
    },
    {
      asset:  {
        hostname: "morty"
      },
      firstSeenArtifactInfo: {
        artifactIndicator: {
          domainName: "www.altostrat.com"
        },
       seenTime:  "2019-06-17T21:22:44.812738Z"
       },
       lastSeenArtifactInfo: {
         artifactIndicator: {
           domainName: "www.altostrat.com"
         }, 
         seenTime: "2019-10-24T20:40:54.846676Z"
        }
      }],
  uri: ["https://sample.backstory.chronicle.security/domainResults?domain=
       altostrat.com&selectedList=DomainViewDistinctAssets&whoIsTimestamp=
       2020-01-08T21%3A09%3A13.000Z"]
}

Python sample code

def call_list_assets():
  # Imports required for the sample - Google Auth and API Client Library Imports.
  # Get these packages from https://pypi.org/project/google-api-python-client/ or 
  # run $ pip install google-api-python-client from your terminal
  import os
  from google.oauth2 import service_account
  from googleapiclient import _auth

  # Constants
  SCOPES = ['https://www.googleapis.com/auth/chronicle-backstory']
  # Change to the location you placed your JSON file.
  SERVICE_ACCOUNT_FILE = os.path.join(os.environ['HOME'], 'bk_credentials.json') 

  # Create a credential using the Google Developer Service Account Credential and Chronicle API scope.
  credentials = service_account.Credentials.from_service_account_file(
        SERVICE_ACCOUNT_FILE, scopes=SCOPES)

  # Build an HTTP client which can make authorized OAuth requests.
  http_client = _auth.authorized_http(credentials)

  # Construct the URL
  BACKSTORY_API_V1_URL = 'https://backstory.googleapis.com/v1'
  LIST_ASSETS_URL = '{}/artifact/listassets?start_time=2019-10-15T00:00:00Z&end_time=2019-10-17T00:00:00Z&artifact.domain_name=
  www.altostrat.com&page_size=1'.format(BACKSTORY_API_V1_URL)

  # Make a request
  response = http_client.request(LIST_ASSETS_URL, 'GET')

  # Parse the response
  if response[0].status == 200:
    assets = response[1]
    # List of Assets returned for further processing
    print(assets)
  else:
    # Something went wrong. See the response for details.
    err = response[1]
    print(err)

ListEvents

List all the events discovered within your enterprise on a particular device within the specified time range. If you receive the maximum number of events you specified using the page_size parameter (or 10,000, the default), there might still be more events within your Chronicle account. You can narrow the time range and issue the call again to ensure you have visibility into all possible events.

Request

https://backstory.googleapis.com/v1/asset/listevents?start_time=time&page_size=size&end_time=time&reference_time=time&asset.indicator=indicator

Sample request

https://backstory.googleapis.com/v1/asset/listevents?start_time=2019-11-17T20:37:00Z&page_size=10&end_time=2019-11-18T20:37:00Z&reference_time=2019-11-17T20:37:00Z&asset.hostname=enterprise.service.altostrat.com

URL parameters

Parameter name Value Description
asset._indicator string Specify the indicator for the asset you are investigating. The _indicator can be any of the following: hostname, asset_ip_address, mac address, product_id (combined product ID type and product ID value, for example CS:1234-5678)
start_time time Start time for your request.
end_time time End time for your request.
reference_time time Specify the reference time for the asset you are investigating.
page_size integer Specify the maximum number of events to return. You can specify between 1 and 10,000. The default is 10,000.

Response

{
  "events": [
    {
      "metadata": {
        "eventTimestamp": "2019-11-18T20:36:58.069290Z",
        "collectedTimestamp": "2019-11-18T20:36:58.069290Z",
        "eventType": "NETWORK_DNS"
      },
      "principal": {
        "hostname": "enterprise.service.example.com",
        "ip": ["203.0.113.100"]
      },
      "target": {
        "ip": ["10.0.2.8"]
      },
      "network": {
        "applicationProtocol": "DNS",
        "dns": {
          "questions": [
            {
              "name": "www.altostrat.com",
              "type": 1
            }
          ],
          "answers": [
            {
              "name": "www.altostrat.com",
              "type": 1,
              "class": 1,
              "data": "203.0.113.100"
            }
          ]
        }
      }
    },
    {
      "metadata": {
        "eventTimestamp": "2019-11-18T20:36:58.069290Z",
        "collectedTimestamp": "2019-11-18T20:36:58.069290Z",
        "eventType": "NETWORK_DHCP"
      },
      "principal": {
        "ip": ["10.0.2.8"]
      },
      "target": {
        "ip": ["198.51.152"]
      },
      "network": {
        "applicationProtocol": "DHCP"
      }
    },
    {
      "metadata": {
        "eventTimestamp": "2019-11-18T20:36:58.069290Z",
        "collectedTimestamp": "2019-11-18T20:36:58.069290Z",
        "eventType": "NETWORK_HTTP"
      },
      "principal": {
        "ip": ["10.0.2.18"]
      },
      "target": {
        "hostname": "www.altostrat.com",
        "url": "http://www.altostrat.com/robots.txt"
      },
      "network": {
        "ipProtocol": "HTTP",
        "http": {
          "method": "METHOD_GET",
          "responseCode": 200
        }
      }
    }
  ]
  uri: ["https://sample.backstory.chronicle.security/assetResults?assetIdentifier=
       sample_asset&referenceTime=2019-12-18T18%3A40%3A34.965Z&selectedList=AssetViewTimeline&
       startTime=2019-12-18T17%3A20%3A35.445Z&endTime=2019-12-18T19%3A20%3A35.445Z"]
}

Python sample code

def call_list_events():
  # Imports required for the sample - Google Auth and API Client Library Imports.
  # Get these packages from https://pypi.org/project/google-api-python-client/ 
  # or run $ pip install google-api-python-client from your terminal
  import os
  from google.oauth2 import service_account
  from googleapiclient import _auth

  # Constants
  SCOPES = ['https://www.googleapis.com/auth/chronicle-backstory']
  # Change to the location you placed your JSON file.
  SERVICE_ACCOUNT_FILE = os.path.join(os.environ['HOME'], 'bk_credentials.json') 

  # Create a credential using Google Developer Service Account Credential and Chronicle API scope.
  credentials = service_account.Credentials.from_service_account_file(
        SERVICE_ACCOUNT_FILE, scopes=SCOPES)

  # Build an HTTP client that can make authorized OAuth requests.
  http_client = _auth.authorized_http(credentials)

  # Construct the URL
  BACKSTORY_API_V1_URL = 'https://backstory.googleapis.com/v1'
  LIST_EVENTS_URL = '{}/asset/listevents?start_time=2019-11-17T20:37:00Z&page_size=10&end_time=2019-11-18T20:37:00Z&reference_time=
  2019-11-17T20:37:00Z&asset.hostname=enterprise.service.altostrat.com'.format(BACKSTORY_API_V1_URL)

  # Make a request
  response = http_client.request(LIST_EVENTS_URL, 'GET')

  # Parse the response
  if response[0].status == 200:
    asset_events = response[1]
    # List of events returned for further processing
    print(asset_events)
  else:
    # Something went wrong, please see the response detail
    err = response[1]
    print(err)

ListIoCs

List all the IoCs discovered within your enterprise within the specified time range. If you receive the maximum number of IoCs you specified using the page_size parameter (or 10,000, the default), there might still be more IoCs discovered in your Chronicle account. You might want to narrow the time range and issue the call again to ensure you have visibility on all possible IoCs.

Request

https://backstory.googleapis.com/v1/ioc/listiocs?start_time=time&page_size=size

Sample request

https://backstory.googleapis.com/v1/ioc/listiocs?start_time=2019-10-15T20:37:00Z&page_size=1

URL parameters

Parameter name Value Description
start_time time Start time for your request.
page_size integer Specify the maximum number of IoCs to return. You can specify between 1 and 10,000. The default is 10,000.

Response

{
  matches: [{
    artifact: {
      domainName: "www.example.com"
     },
    firstSeenTime: "2018-05-25T20:47:11.048998Z",
    iocIngestTime: "2019-08-14T21:00:00Z",
    lastSeenTime:  "2019-10-24T16:19:46.880830Z",
    sources: [{
      category: "Spyware Reporting Server",
      confidenceScore: {
          intRawConfidenceScore: 0,
          normalizedConfidenceScore: "Low"
      },
      rawSeverity: "Medium",
      source: "ET Intelligence Rep List"
      }],
      uri: ["https://sample.backstory.chronicle.security/assetResults?assetIdentifier=sample_asset&
      referenceTime=2019-12-18T18%3A40%3A34.965Z&selectedList=AssetViewTimeline&
      startTime=2019-12-18T17%3A20%3A35.445Z&endTime=2019-12-18T19%3A20%3A35.445Z"]
  }],
  moreDataAvailable: true
  }

Python sample code

def call_list_iocs():
  # Imports required for the sample - Google Auth and API Client Library Imports.
  # Get these packages from https://pypi.org/project/google-api-python-client/ 
  # or run $ pip install google-api-python-client from your terminal
  import os
  from google.oauth2 import service_account
  from googleapiclient import _auth

  # Constants
  SCOPES = ['https://www.googleapis.com/auth/chronicle-backstory']
  # Change to the location you placed your JSON file.
  SERVICE_ACCOUNT_FILE = os.path.join(os.environ['HOME'], 'bk_credentials.json') 

  # Create a credential using the Google Developer Service Account Credential and Chronicle API scope.
  credentials = service_account.Credentials.from_service_account_file(
        SERVICE_ACCOUNT_FILE, scopes=SCOPES)

  # Build an HTTP client which can make authorized OAuth requests.
  http_client = _auth.authorized_http(credentials)

  # Construct the URL
  BACKSTORY_API_V1_URL = 'https://backstory.googleapis.com/v1'
  LIST_IOCS_URL = '{}/ioc/listiocs?start_time=2019-10-15T20:37:00Z&page_size=1'.format(BACKSTORY_API_V1_URL)

  # Make a request
  response = http_client.request(LIST_IOCS_URL, 'GET')

  # Parse the response
  if response[0].status == 200:
    iocs = response[1]
    # List of IoCs returned for further processing
    print(iocs)
  else:
    # Something went wrong. See the response for details.
    err = response[1]
    print(err)

ListIoCDetails

Use this method to submit an artifact indicator and return any threat intelligence associated with that artifact. The threat intelligence information is drawn from your enterprise security systems and from Google's IoC partners (for example, the DHS threat feed).

Request

https://backstory.googleapis.com/v1/artifact/listiocdetails?artifact.type=<value>
Sample request
https://backstory.googleapis.com/v1/artifact/listiocdetails?artifact.domain_name=www.altostrat.com
URL parameters
Parameter name Value Description
artifact.domain_name domain name Specify the artifact indicator associated with the assets. You can only specify a single artifact. The artifact indicator may either be a domain name or an IP address.
artifact.destination_ip_address destination IP address

Response

{
  sources: [{
    addresses: [{
      domain: "www.altostrat.com",
      port:   [80]
     }],
    category: "Spyware Reporting Server",
    confidenceScore: {strRawConfidenceScore: "25"},
    firstActiveTime: "2013-08-04T00:00:00Z",
    lastActiveTime: "2019-08-13T00:00:00Z",
    rawSeverity: "Medium",
    sourceUrl:"http://tools.emergingthreats.net/docs/ET%20Intelligence%20Rep%20List%20Tech%20Description.pdf"
  }],
  uri: ["https://sample.backstory.chronicle.security/domainResults?
        domain=altostrat.com&selectedList=DomainViewDistinctAssets&
        whoIsTimestamp=2020-01-09T01%3A29%3A59.526Z"
        ]
}

Python sample code

def call_list_ioc_details():
  # Imports required for the sample - Google Auth and API Client Library Imports.
  # Get these packages from https://pypi.org/project/google-api-python-client/ 
  # or run $ pip install google-api-python-client from your terminal
  import os
  from google.oauth2 import service_account
  from googleapiclient import _auth

  # Constants
  SCOPES = ['https://www.googleapis.com/auth/chronicle-backstory']
  # Change to the location you placed your JSON file.
  SERVICE_ACCOUNT_FILE = os.path.join(os.environ['HOME'], 'bk_credentials.json')

  # Create a credential using the Google Developer Service Account Credential and Chronicle API scope.
  credentials = service_account.Credentials.from_service_account_file(
        SERVICE_ACCOUNT_FILE, scopes=SCOPES)

  # Build an HTTP client which can make authorized OAuth requests.
  http_client = _auth.authorized_http(credentials)

  # Construct the URL
  BACKSTORY_API_V1_URL = 'https://backstory.googleapis.com/v1'
  LIST_IOC_DETAILS_URL = '{}/artifact/listiocdetails?artifact.domain_name=www.altostrat.com'
  .format(BACKSTORY_API_V1_URL)

  # Make a request
  response = http_client.request(LIST_IOC_DETAILS_URL, 'GET')

  # Parse the response
  if response[0].status == 200:
    iocs = response[1]
    # List of sources returned for further processing
    print(iocs)
  else:
    # Something went wrong. See the response for details.
    err = response[1]
    print(err)