Loading

Run detection rules on demand

This guide walks through building a workflow that triggers a manual execution of one or more detection rules over a specific time range. Use it for gap-filling after a detection rule change, post-incident review, scheduled health checks, or any time you need to run rules outside their normal cadence.

The workflow is adapted from manually-run-rules.yaml in the elastic/workflows library.

If you're new to workflows, complete Build your first workflow first.

  • Permissions. All on Analytics > Workflows and on Security > Detection rules in the target space. Refer to Kibana privileges.
  • Rule IDs. The rule_id values of the detection rules you want to run. You can copy them from the Rules table in Elastic Security or from a saved-object export.
  • Time range. The lookback window for this manual run. The default in this workflow is the last 15 minutes, which matches the interval of most default rules.

The workflow runs on demand with a list of rule IDs:

  1. Manual trigger with a rule_ids array input.
  2. foreach step iterates the rule IDs.
  3. For each rule, a kibana.request step calls the detection engine's POST /api/detection_engine/rules/_bulk_action endpoint with the run action and a configurable time range.
  1. Declare the rule IDs and time window as inputs

    Inputs make the workflow reusable without editing YAML. Declare both the list of rule IDs and the lookback window in minutes:

    inputs:
      - name: rule_ids
        type: array
        description: Detection rule IDs to run.
        required: true
      - name: lookback_minutes
        type: number
        description: How many minutes back to run the rule.
        default: 15
    
    triggers:
      - type: manual
    		
  2. Loop over the rule IDs

    Use a foreach step to iterate. Inside the loop, foreach.item is the current rule ID:

    steps:
      - name: for_each_rule
        type: foreach
        foreach: "${{ inputs.rule_ids }}"
        steps:
          # Per-rule step goes here. Use foreach.item for the current rule ID.
    		

    Note the ${{ inputs.rule_ids }} form. Use ${{ ... }} whenever you're passing an array or object to a step parameter, so the value isn't stringified. Refer to Templating engine for the {{ }} vs. ${{ }} distinction.

  3. Trigger the rule run with kibana.request

    Call the detection engine's bulk action endpoint to run the rule over the lookback window. Build the start and end timestamps with Liquid date filters:

    - name: run_rule
      type: kibana.request
      with:
        method: POST
        path: /api/detection_engine/rules/_bulk_action
        body:
          action: run
          ids:
            - "{{ foreach.item }}"
          run:
            start_date: "{{ 'now' | date: '%s' | minus: inputs.lookback_minutes | times: 60 | date: '%Y-%m-%dT%H:%M:%S' }}.000Z"
            end_date: "{{ 'now' | date: '%Y-%m-%dT%H:%M:%S' }}.000Z"
    		

    The two Liquid expressions compute ISO timestamps: the start is now - lookback_minutes minutes, and the end is now. Adjust the expressions if you need a different window shape.

  • Run on a schedule. Replace the manual trigger with a scheduled trigger that fires every hour and passes a fixed rule list through consts.
  • Audit before you run. Chain a kibana.request GET /api/detection_engine/rules step first to fetch each rule's status and skip rules that are disabled or in error.
  • Summarize results. After the loop, post the number of rules run to Slack or index a summary document with elasticsearch.request for dashboarding.
  • Stop on first failure. Replace the per-iteration error handling with a strict on-failure: abort so the workflow fails fast if any one rule can't be triggered.