elastic / elastic/docs-content
[Security][DE/Workflows][9.6 & Serverless] Create rule exceptions from a workflow
- Dominant language
- No language data
- Stars
- 47
- Forks
- 261
- Avg merge
- 3d 12h
- Merged PRs (30d)
- 116
Description
### Description
For 9.6 we are adding a named Workflow action step under the existing `security.*` namespace: `security.createRuleException`. Until now, adding an exception to a detection rule from a workflow was only reachable through the generic `kibana.request` step calling the rule-exceptions API directly, which requires API knowledge and offers no discoverability or schema validation in the Workflows editor.
This new step exposes an explicit input schema (validated at save time, discoverable in the Workflows editor) and native exception-creation semantics, with optional idempotency via `item_id`, so detection engineers can automate suppression workflows without hand-writing exceptions-API requests.
`security.createRuleException` adds an exception item to a detection rule's own default exception list (creating that list automatically if the rule doesn't have one yet), so the exception only affects that one rule.
This step is **GA** in 9.6. It lives in the `StepCategory.KibanaSecurity` category (the same category as the `security.*` alert/attack triage steps and the `security.enableRule`/`disableRule` rule-management steps) and is automatically authenticated using the permissions/API key of the identity executing the workflow (same model as the existing `kibana.*` and `cases.*` steps). It is implemented as a custom step on top of the rule-exceptions API via the `callKibanaApi` platform utility.
The step optionally accepts an `item_id` to make repeated runs idempotent: when an item with that `item_id` already exists on the rule's default list, the step skips creation (or updates it, with `overwrite: true`) instead of creating a duplicate. The output's `outcome` reports what happened (`created`, `skipped`, or `overwritten`).
---
## Docs work
### 1. Add this step to the Security action steps page
On `explore-analyze/workflows/steps/security.md`, add an **Exceptions** group (parallel to the Alerts, Attacks, and Rules groups) with jump links — or, if the companion `security.createExceptionListItem` step already added this group, add this step as a subsection within it. Follow the same layout as the other groups: purpose sentence, a parameter table (`Parameter | Location | Type | Required | Description`), and a YAML example.
Reuse the page's existing conventions (`applies_to` frontmatter, the `:::{include} ../_snippets/schema-location-legend.md :::` legend, the Related section). This step is GA in 9.6: use `stack: ga 9.6+` / `serverless: ga`, consistent with the rest of the page.
#### Conventions to document
- **All parameters live under `with`.**
- **Entries use a flat, verb-based `operator` shape**, not the raw exceptions-API discriminated union. Each entry combines a `field` with an `operator`: `is`, `is_not`, `matches`, and `does_not_match` take a single `value` (the match operators support `*` and `?` wildcards); `is_one_of` and `is_not_one_of` take a `values` array; `exists` and `does_not_exist` take no operand; `is_in_list` and `is_not_in_list` reference a value list via `list.id` and `list.type`.
- **A value-list entry cannot be mixed with other entry types in the same item.** If any entry in `entries` uses `is_in_list`/`is_not_in_list`, every entry in that item must.
- **`entries` is a logical AND.** All entries of an item must match for the exception to apply; author separate items for alternative (OR) conditions.
- **Nested conditions are not supported.** Fields mapped as `nested` in the source indices (mostly Endpoint objects) can't be targeted from this step; use the Security UI or API for those.
- **`expire_time` (optional, ISO 8601) makes the exception temporary.**
- **Optional idempotency via `item_id`.** When provided and an item with that `item_id` already exists on the rule's default list, the step skips creation and returns the existing item, or updates it when `overwrite: true` (existing comments are preserved). `overwrite: true` requires `item_id`; providing `overwrite` without `item_id` fails validation. **If `item_id` is omitted, the API assigns a new random one on every run** — the step has nothing to match against, so it always creates a fresh item. Re-running the same workflow (a retry, a scheduled trigger, a loop) without `item_id` produces a new duplicate exception item each time instead of reusing the previous one. Provide `item_id` whenever the workflow might run more than once for what is logically the same exception.
- **A conflicting `item_id` on a different list fails loudly.** `item_id` is not scoped to a particular list. If an item with that `item_id` already exists on a list *other than* this rule's own default list, the step fails rather than silently creating a duplicate or touching the wrong item. Worth an explicit callout, since this is a step-level design choice, not an API-enforced rule.
- **Output summary.** The step returns `{ id, item_id, list_id, namespace_type, name, created_at, created_by, expire_time?, outcome }`. `outcome` is one of `created`, `skipped`, `overwritten`.
#### Reference (schema as implemented)
**`security.createRuleException`** — Add an exception item to a detection rule's own default exception list.
| Parameter | Location | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `rule_id` | `with` | `string` (rule UUID) | Required | The rule's `id` (UUID), not `rule_id`, e.g. `kibana.alert.rule.uuid` on an alert. The rule's own default exception list is created automatically if it doesn't have one yet. |
| `item_id` | `with` | `string` | Optional | Stable identifier for idempotency; see conventions above. |
| `overwrite` | `with` | `boolean` | Optional (default `false`) | Update the existing item instead of skipping when `item_id` already exists. Requires `item_id`. |
| `name` | `with` | `string` | Required | Exception item name. |
| `description` | `with` | `string` | Required | Exception item description. |
| `entries` | `with` | `array` | Required (at least 1) | The item's match conditions; see conventions above. |
| `os_types` | `with` | `string[]` | Optional | OS types the exception applies to. |
| `tags` | `with` | `string[]` | Optional | Tags for the item. |
| `expire_time` | `with` | `string` (ISO 8601) | Optional | Makes the exception temporary. |
| `comments` | `with` | `string[]` | Optional | Comments attached to the item. |
```yaml
# Exclude a host from a rule
- name: add_exception_to_rule
type: security.createRuleException
with:
rule_id: '{{ variables.rule_id }}'
name: 'Exclude maintenance host'
description: 'Host is under maintenance'
entries:
- field: host.name
operator: is
value: '{{ variables.host_name }}'
```
```yaml
# Temporary exception created from an alert
- name: add_exception_from_alert
type: security.createRuleException
with:
rule_id: '{{ event.kibana.alert.rule.uuid }}'
name: 'Auto exception for {{ event.host.name }}'
description: 'Created by workflow'
expire_time: '{{ variables.expiration }}'
comments:
- 'Excluded during the patching window'
entries:
- field: host.name
operator: is
value: '{{ event.host.name }}'
- field: user.name
operator: is_one_of
values:
- svc-patching
- svc-backup
```
```yaml
# Idempotent: re-running this workflow updates the same item instead of duplicating it
- name: add_or_update_exception
type: security.createRuleException
with:
rule_id: '{{ variables.rule_id }}'
item_id: 'maintenance-window-{{ variables.host_name }}'
overwrite: true
name: 'Exclude maintenance host'
description: 'Host is under maintenance'
entries:
- field: host.name
operator: is
value: '{{ variables.host_name }}'
```
Without `item_id`, running this same workflow again would create a second, separate exception item for the same host rather than updating the first. `item_id` and `overwrite: true` together make re-runs safe.
#### Output reference
| Field | Type | Description |
| --- | --- | --- |
| `id` | `string` | Saved-object `id` of the created (or existing) item. |
| `item_id` | `string` | The item's `item_id`. |
| `list_id` | `string` | The list the item is on (the rule's default list). |
| `namespace_type` | `string` | Always `single` for a rule's own default list. |
| `name` | `string` | The item's name. |
| `created_at` | `string` | Creation timestamp. |
| `created_by` | `string` | Creator. |
| `expire_time` | `string` | Present only if set on the item. |
| `outcome` | `string` | `created`, `skipped`, or `overwritten`. |
### 2. Update the Action steps overview page
On [`explore-analyze/workflows/steps/action-steps.md`](https://github.com/elastic/docs-content/blob/main/explore-analyze/workflows/steps/action-steps.md), add (or extend, if the companion ticket got there first) a bullet on the Security category's "Use … to:" list:
- Add an exception to a detection rule (`security.createRuleException`).
### 3. Update the step-type index
On [`reference/step-types.md`](https://github.com/elastic/docs-content/blob/main/explore-analyze/workflows/reference/step-types.md) (A–Z index), add a `security.createRuleException` row to the **Security** category. One-line summary: add an exception item to a rule's own default exception list, with optional idempotency via `item_id`. Applies from 9.6.0 and in serverless.
### (Optional) Rule-ops / exceptions use-case guide
If there is a detection-rule-operations or exceptions-management use-case guide, add a short mention of `security.createRuleException` as the native option instead of a generic `kibana.request` call. Skip if no such guide exists.
---
## Timeline & environment
- **Stack release:** 9.6.0
- **Serverless:** active by default (no feature flag)
- GA in 9.6. Tag everything `stack: ga 9.6+` / `serverless: ga`.
### Which deployment methods does this change impact?
Elastic On-Prem and Cloud (all)
### What Elastic Stack release is this request related to?
9.6
## Resources
- **Implementation PR:** [kibana#277802 — [Security Solution] Add exception creation workflow steps](https://github.com/elastic/kibana/pull/277802) (implements both this step and its companion, `security.createExceptionListItem`)
- **Companion ticket:** `security.createExceptionListItem` — add an exception item to an existing exception list (filed separately, same PR, same target page)
- **Sibling epic:** [security-team#18163 — [Radar] - Exception creation workflow step](https://github.com/elastic/security-team/issues/18163)
- **Existing reference to mirror:** [Enable/disable detection rules from a workflow](https://github.com/elastic/docs-content/issues/7352) (same target page, same layout pattern) and [Cases action steps](https://www.elastic.co/docs/explore-analyze/workflows/steps/cases)
- **Target page (shared with triage, rule-management, and the companion exception step):** `explore-analyze/workflows/steps/security.md`
### Implementation notes for the drafter (source of truth: PR #277802)
- Step ID `security.createRuleException`; category `StepCategory.KibanaSecurity`.
- Calls `POST /api/detection_engine/rules/{id}/exceptions` (the rule-exceptions API), which creates the rule's default exception list automatically if it doesn't have one yet.
- Goes through the `callKibanaApi` platform utility.
- Editor icon: `filter_exclude`.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.