Rules¶
Rules are YAML files that define what to query, and under what condition an alert should fire.
Rule file format¶
id: "001"
name: Brute Force Detected
level: 65
size: ">5"
active: true
author:
- Your Name <[email protected]>
group: authentication
tags:
- authentication_failed
- bruteforce
description: "More than 5 failed login attempts in the last minute"
rule: |-
SELECT count(*) AS cnt
FROM auth_logs
WHERE
timestamp >= now() - INTERVAL 1 MINUTE
AND tenant = '{{ detector.tenant }}'
Fields¶
| Field | Required | Description |
|---|---|---|
id | yes | Unique rule identifier (string) |
name | yes | Human-readable name |
level | yes | Severity level (integer 0-100, higher = more severe, see Severity levels) |
size | yes | Condition to trigger the alert (see below) |
active | no | Enable or disable the rule (default: true) |
rule | yes | Query template (Jinja2, executed against the datasource) |
author | no | List of authors |
group | no | Rule group/category |
tags | no | List of tags for classification |
description | no | Description of what the rule detects |
data | no | Custom key/value data, available in the rule template |
sigma | no | Parse the rule field as a Sigma rule (default: false) |
Severity levels¶
level is an integer between 0 and 100. Anything outside that range makes the rule fail to load.
Webhooks translate the level into the severity vocabulary of their destination using these bands, where each band starts at the level below and ends where the next one begins:
| Band | Level |
|---|---|
informational | 0 |
low | 20 |
medium | 40 |
high | 60 |
critical | 80 |
The bands are configurable per webhook with the severity_map option, which takes the minimum rule level of each band. Bands left out keep their default:
webhooks:
my_hook:
type: opsgenie
api_key: '...'
severity_map: # optional, only the bands you want to move
high: 70
critical: 90
Each webhook page documents how it maps the bands to its destination.
Sigma rules use a textual level, which is converted on load:
| Sigma level | Clickdetect level |
|---|---|
informational | 10 |
low | 30 |
medium | 50 |
high | 75 |
critical | 90 |
size — condition format¶
The size field compares the number of rows returned by the query against a threshold.
| Operator | Example | Meaning |
|---|---|---|
> | ">0" | At least 1 result |
>= | ">=10" | 10 or more results |
< | "<5" | Fewer than 5 results |
<= | "<=100" | 100 or fewer results |
== | "==1" | Exactly 1 result |
Jinja2 templates¶
The rule query is rendered with Jinja2 before execution. The following variables are available:
| Variable | Type | Description |
|---|---|---|
detector.name | string | Detector name |
detector.tenant | string | Tenant identifier |
detector.data | dict | Custom data set in the detector's data field |
rule.id | string | Rule ID |
rule.name | string | Rule name |
rule.data | dict | Custom data set in the rule's data field |
startime | string | Unix timestamp (int as string) of the interval start |
endtime | string | Unix timestamp (int as string) of the interval end |
interval | string | Detector interval (e.g. "5m") |
rule_id | string | Shorthand for rule.id |
rule_level | int | Shorthand for rule.level |
rule_group | string | Shorthand for rule.group |
datasource | dict | Datasource configuration dict |
Custom Jinja2 filters¶
| Filter | Description |
|---|---|
\| to_list_like | Joins items as single-quoted strings: 'a', 'b', 'c' |
\| to_list | Joins items as comma-separated values: a, b, c |
\| tojson | Serializes to JSON (handles datetime, UUID, and dataclasses) |
Example with template variables¶
rule: |-
SELECT user, count(*) AS attempts
FROM auth_logs
WHERE
tenant = '{{ detector.tenant }}'
AND status = 'failed'
AND timestamp >= now() - INTERVAL 5 MINUTE
GROUP BY user
HAVING attempts > {{ rule.data.threshold | default(5) }}
data:
threshold: 10
Loading rules in a detector¶
Rules are referenced in the detector's rules list. Both direct paths and glob patterns are supported:
detectors:
my_detector:
rules:
- "rules/auth/brute_force.yml"
- "rules/network/*.yml"
- "rules/**/*.yml"
Webhook alert template variables¶
When a rule fires and a webhook is called, the following variables are available in the webhook template:
| Variable | Description |
|---|---|
rule | The Rule object (all fields accessible) |
data.len | Number of rows returned by the query |
data.value | List of result rows (each row is a dict) |
detector | The Detector object (name, tenant, data, etc.) |
datasource | The datasource configuration dict |
time.startime | Unix timestamp (float) of the interval start |
time.endtime | Unix timestamp (float) of the interval end |
Tips¶
For more precise query results, use the {{ startime }} and {{ endtime }} parameters. These allow you to filter data within a specific time range, making your queries more efficient and relevant