Drill down to raw events from alert

Hi folks.
Wanted to share with you the way I created a sort-of drill down from an alert generated by a watcher to the raw events that had triggered the alert.
First of all let me throw in some context.

  1. All the described below was designed and tested for Windows event logs as it is based on the winlog.record_id field, yet it could be easily adopted to any other log types with slight modifications (change winlog.record_id in the URL to some unique event ID from a different log)
  2. I have a watcher module running and an alert that triggers when some certain event(s) show up in the logs
  3. The generated alert is saved in a dedicated watcher-alerts index and is enriched with some data from the original event(s) that triggered it
    The task that I wanted to accomplish was to include a dynamically generated link (that would point to the raw event(s) that had triggered the alert) in some field of the alert.

And here is how it was done:

  1. A new field was created in the alert called “raw_events”.
  2. The “raw_events” field contains the link to the events that had triggered the alert. Below is the link template:
    <kibana_URL>/app/kibana#/discover?_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from: '<timestamp_start>',to: '<timestamp_end>'))&_a=(columns:!(winlog.record_id),filters:!(),index:'<index_pattern_id>',interval:auto,query:(language:lucene,query:'winlog.record_id:<raw_event_ids>'),sort:!(\\'@timestamp\\',desc))
    The variables: kibanaURL, timestamp_start, timestamp_end, index_pattern_id and raw_event_ids should be generated and added to the URL dynamically when the alert triggers.
    Here I have to admit that kibana_URL and index_pattern_id variables are not dynamic and in fact are hardcoded in the link for every alert type that is desidned to have this link.
    The explanation of the vars follows:
    kibana_URL – this one is obvious. It’s the hostname/IP and port of your Kibana instance (i.e. http://mykibana.local:5601);
    index_pattern_id – that’s quite easy. It is the ID of the index pattern that points to the index containing raw events. To get this ID just run a Kibana search across the index that stores your raw events and get this ID from the URL that you see in the address bar of the browser.
    To fill the link with all the dynamic data we should get:
    timestamp_start – this is the start time of the interval during which the raw events that had triggered the alert were detected (f.i. I have an alert that runs every 5 minutes and triggers if event A is found. So this is the starting time of that five minute interval). I use the following clause for this one: “Instant.ofEpochMilli(ctx.execution_time.getMillis()).minus(330, ChronoUnit.SECONDS)”. 330 in this example is the difference(in seconds) between “timestamp_end” and “timestamp_start”;
    timestamp_end – this is the end time of the interval mentioned above. I use “ctx.execution_time” for this one. So that it takes the time when the alert was triggered as the end time of the search;
    raw_event_ids – the winlog.record_id(s) of the events that triggered the alert (these I get from the raw events when running the “index” action in the watcher).
    That’s it.
    Here is the link example the way it is in the “action” – “index” section of the watcher:
    'raw_events':'https://elk-cluster.local/app/kibana#/discover?_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:\\'' + Instant.ofEpochMilli(ctx.execution_time.getMillis()).minus(330, ChronoUnit.SECONDS) + '\\',to:\\'' + ctx.execution_time + '\\'))&_a=(columns:!(winlog.record_id),filters:!(),index:\\'a9b95c40-35ed-11ea-b7b9-93b0d560ba52\\',interval:auto,query:(language:lucene,query:\\'winlog.record_id:' + ctx.payload.hits.hits[i]._source.winlog.record_id + '\\'),sort:!(\\'@timestamp\\',desc))'
    And here is the example of what this link looks like in one of the generated alerts:
    https:// elk-cluster.local /app/kibana#/discover?_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:'2020-05-16T21:22:00.393Z',to:'2020-05-16T21:27:30.393843Z'))&_a=(columns:!(winlog.record_id),filters:!(),index:'12ea28a0-32d5-11ea-b7b9-93b0d560ba52',interval:auto,query:(language:lucene,query:'winlog.record_id:1031033'),sort:!('@timestamp',desc))

Hope someone finds this usefull. Please feel free to post comments or ask questions.
Have a great day!
Oh, and here is the full JSON of the alert which can be viewed in Kibana:

  "_index": "watcher-alerts",
  "_type": "_doc",
  "_id": "CZJjH3IBakoKPIhabhC5",
  "_version": 1,
  "_score": null,
  "_source": {
    "computer_name": "ts22.local",
    "event_id": 1031033,
    "raw_events": "https://elk-cluster.local/app/kibana#/discover?_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:'2020-05-16T21:22:00.393Z',to:'2020-05-16T21:27:30.393843Z'))&_a=(columns:!(winlog.record_id),filters:!(),index:'12ea28a0-32d5-11ea-b7b9-93b0d560ba52',interval:auto,query:(language:lucene,query:'winlog.record_id:1031033'),sort:!('@timestamp',desc))",
    "confidence": "5",
    "event_name": "Execute a Remote Command",
    "alert_name": "Alert-Malicious Powershell",
    "timestamp": "2020-05-16T21:28:29.621731Z"
  "fields": {
    "timestamp": [
  "highlight": {
    "alert_name": [
      "@kibana-highlighted-field@ITsec@/kibana-highlighted-field@-@kibana-highlighted-field@W0011@/kibana-highlighted-field@-@kibana-highlighted-field@Malicious@/kibana-highlighted-field@ @kibana-highlighted-field@Powershell@/kibana-highlighted-field@"
  "sort": [

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.