Configuration
rsigma engine daemon, rsigma engine eval, rsigma rule backtest, rsigma rule coverage, rsigma rule scorecard, rsigma rule visibility, and rsigma rule hygiene can be driven by a YAML config file in addition to CLI flags and environment variables. This page describes the schema, the discovery chain, and the precedence model that decides which value wins when more than one layer sets the same key.
The same machinery is exposed through the rsigma config group for scaffolding, validation, introspection, and reload.
Precedence
From highest to lowest:
- CLI flags on the command line (e.g.
--rules /tmp/r). - Environment variables: uniform
RSIGMA_<SECTION>__<KEY>(see Environment layer) plus the legacy clap-bound names listed in Environment Variables. - Project config:
./rsigma.yaml(or./rsigma.yml) in the current directory, then the nearest.rsigmarcfound by walking up from the current directory. - User config:
$XDG_CONFIG_HOME/rsigma/config.yaml(defaulting to~/.config/rsigma/config.yaml). - System config:
/etc/rsigma/config.yaml. - Compiled defaults baked into the binary.
Higher layers override lower ones per leaf, not whole sections; a project .rsigmarc that only sets eval.rules does not erase the rest of the user config. This matches the clig.dev guidance and is what most modern CLIs implement.
Use rsigma config show to see the resolved value for every key with the layer that supplied it.
Discovery
All layers that exist are loaded and merged. There is no first-match-wins fallback: a file at /etc/rsigma/config.yaml is always loaded if it exists, even when a project rsigma.yaml is also present.
Passing --config <PATH> replaces the discovery chain entirely: only that file is loaded (and a bad path is a hard error, so misspellings surface immediately).
The ~/.config/rsigma location is computed by honouring XDG_CONFIG_HOME explicitly rather than dirs::config_dir(), so on macOS the path stays under ~/.config/rsigma instead of ~/Library/Application Support/. The rsigma install workflow uses the same layout.
Format
A minimal example, with every supported top-level section:
# yaml-language-server: $schema=https://timescale.github.io/rsigma/rsigma.schema.json
version: 1
global:
log_format: text # text | json (maps to --log-format)
output_format: json # json | ndjson | table | csv | tsv (maps to --output-format)
color: auto # auto | always | never (maps to --color)
daemon:
rules: /etc/rsigma/rules
pipelines: [ecs_windows]
sources: [/etc/rsigma/sources]
# alert_pipeline: /etc/rsigma/alert-pipeline.yml # dedup (see the Alert Pipeline guide)
# risk: /etc/rsigma/risk.yml # risk-based alerting (see the Risk-Based Alerting guide)
api:
addr: "0.0.0.0:9090" # TCP host:port, or unix:///run/rsigma/api.sock (Unix; no TLS)
input:
source: stdin # stdin | http | nats://... | unix:///run/rsigma/ingest.sock (Unix)
format: auto
buffer_size: 10000
output:
sinks: [stdout] # stdout | file://... | nats://... | otlp://... | unix:///run/rsigma/out.sock (Unix)
drain_timeout: 5
# webhooks: [/etc/rsigma/webhooks/] # template-driven HTTP sinks
correlation:
action: alert
event_mode: none
max_events: 10
max_state_entries: 100000 # hard cap across all correlations and groups
# max_group_entries: 10000 # per-group window-state cap; unset = unbounded
state:
save_interval: 30
engine:
bloom_prefilter: false
match_detail: off
observe_fields: false
egress_policy: default
tap:
enabled: false # opt-in: enable GET /api/v1/tap (or pass --enable-tap)
buffer_events: 8192 # per-session buffer; a full buffer drops events (counted)
max_sessions: 2 # concurrent capture sessions (a session over the cap gets 409)
max_duration: 5m # largest accepted ?duration (a longer one gets 400)
tail:
enabled: false # opt-in: enable GET /api/v1/detections/stream (or --enable-tail)
buffer_events: 8192 # per-session buffer; a full buffer drops detections (counted)
max_sessions: 2 # concurrent tail sessions (a session over the cap gets 409)
schema:
observe: false # opt-in: count events per recognized schema (or --observe-schemas)
routing: false # opt-in: route each event to its schema's pipeline-set (or --schema-routing)
partition_rules: false # gated: compile platform-locked per-schema engines with only applicable rules (or --schema-partition-rules)
# config: /etc/rsigma/schema.yml # user schema signatures + routing bindings (--schema-config)
on_unknown: warn # warn | drop | passthrough | error, for events matching no schema
logsource_routing:
enabled: false # opt-in: conflict-based logsource pruning (or --logsource-routing)
# field_map: # event field names per dimension (default product/service/category)
# product: product
# custom: # extra dimensions: dimension name -> event field name
# tenant: org
# event_logsource: # static logsource when the field is absent (--event-logsource)
# product: windows
# custom: # extra dimensions: dimension name -> literal value
# tenant: acme
strict: false # reserved for a future strict subset-routing mode
eval:
rules: ./rules
pipelines: [sysmon]
input_format: auto
fail_on_detection: false
schema:
routing: false # opt-in: route each event to its schema's pipeline-set (or --schema-routing)
# config: ./schema.yml
on_unknown: warn
logsource_routing:
enabled: false # opt-in: conflict-based logsource pruning (or --logsource-routing)
# field_map:
# product: product
# event_logsource:
# product: windows
strict: false
backtest:
rules: ./rules
corpus: [./ci/corpus]
expectations: ./ci/expectations.yml
# unexpected: warn # fail | warn | ignore; unset lets the expectations-file default apply
input_format: auto
coverage:
# rules: [./rules]
# atomics: https://raw.githubusercontent.com/redcanaryco/atomic-red-team/master/atomics/Indexes/index.yaml
# baseline: https://raw.githubusercontent.com/SigmaHQ/sigma/master/other/sigma_attack_nav_coverage.json
# targets: ./threat-model-techniques.txt
fail_on_gaps: false
scorecard:
# backtest: ./backtest.json
# coverage: ./coverage.json
# metrics: http://localhost:9090/metrics
# triage: ./triage.json
fail_on: none
min_precision: 0.8
tune_max_precision: 0.5
retire_max_precision: 0.1
min_volume: 1
stale_window: 30
max_fp_ratio: 0.5
visibility:
# mapping: ./mapping.json
fail_on_blind_spots: false
hygiene:
# rules: [./rules]
# metrics: http://localhost:9090/metrics
# fields: ./fields.json
silent_threshold: 365d
stale_threshold: 365d
# noisy_threshold: 100000
# fail_on: [silent]
Run rsigma config init to scaffold a full, commented version. The full machine-readable schema is emitted by rsigma config schema.
Sections
| Section | Used by | Notes |
|---|---|---|
global |
every subcommand | global.log_format, global.output_format, and global.color. See Output Formats for the format/color semantics. |
daemon |
engine daemon |
Mirrors every non-secret daemon flag. |
daemon.api.tls |
engine daemon |
Inert unless the binary is built with the daemon-tls feature; otherwise config validate warns. |
daemon.api.auth |
engine daemon |
Bearer-token authentication with resource:action permissions (anonymous_permissions, roles, tokens). Absent = no authentication. Token secrets stay env-only via each token’s token_env. Mutually exclusive with --api-token-env. See HTTP API: Authentication. |
daemon.api.audit |
engine daemon |
Control-plane mutation audit trail (enabled, max_entries, max_age, max_body_bytes, sink). Requires --state-db; auto-enabled when a state database is configured. See HTTP API: Audit trail. |
daemon.nats |
engine daemon |
Non-secret NATS knobs (e.g. consumer_group). Secrets stay env-only. Inert unless built with daemon-nats. |
daemon.tap |
engine daemon |
Live event-tap limits (enabled, buffer_events, max_sessions, max_duration). Disabled by default; enable with enabled: true or --enable-tap. The rest are config-file-only. See HTTP API: Live event tap. |
daemon.tail |
engine daemon |
Live detection-tail limits (enabled, buffer_events, max_sessions). Disabled by default; enable with enabled: true or --enable-tail. The rest are config-file-only. See HTTP API: Live detection tail. |
daemon.dispositions |
engine daemon |
Triage feedback loop (enabled, source, window, numerator, min_sample). Disabled by default; enable with enabled: true, --enable-dispositions, or a configured source. See the Triage Feedback Loop guide. |
daemon.engine.cross_rule_ac |
engine daemon |
Inert unless built with daachorse-index. |
daemon.schema |
engine daemon |
Schema classification and routing (observe, routing, config, on_unknown). All opt-in. See Schema Routing. |
daemon.logsource_routing |
engine daemon |
Conflict-based logsource pruning (enabled, field_map, event_logsource, reserved strict). Opt-in. See Logsource-Aware Evaluation. |
eval |
engine eval |
Mirrors the eval flag surface. |
eval.schema |
engine eval |
Schema routing for one-shot eval (routing, config, on_unknown). observe has no effect here. |
eval.logsource_routing |
engine eval |
Conflict-based logsource pruning for one-shot eval (enabled, field_map, event_logsource, reserved strict). |
backtest |
rule backtest |
rules, corpus, expectations, unexpected, pipelines, and the syslog input knobs. unexpected has no compiled default so the expectations-file default can apply. |
coverage |
rule coverage |
rules, atomics, baseline, targets, fail_on_gaps. |
scorecard |
rule scorecard |
The two required reports (backtest, coverage), the verdict thresholds (min_precision, tune_max_precision, retire_max_precision, min_volume, stale_window, max_fp_ratio), the optional inputs (metrics, metrics_window, triage), fail_on, and report. |
visibility |
rule visibility |
mapping (logsource/field to ATT&CK data-source table path or URL; unset uses the bundled default) and fail_on_blind_spots. rules and observed are intentionally absent (they are invocation-specific CLI arguments). |
doc |
rule doc |
fail_on_missing (the CI gate). The ADS bar itself (enforced statuses and required sections) lives in .rsigma-lint.yml under an ads: block, not here. See Detection Strategy. |
hygiene |
rule hygiene |
rules, the optional sources (metrics, metrics_window, fields), the thresholds (silent_threshold, stale_threshold, noisy_threshold), and fail_on. See Rule Hygiene. |
mcp |
mcp serve |
mcp.http_addr (the --http bind address; unset means stdio), mcp.lint_config, mcp.rules_dir, and mcp.allow_sigma_cli (let convert_rules delegate non-native targets to an installed sigma-cli; off by default). The auth token is secret and stays flag/env-only. Inert unless built with the mcp feature. |
Secrets policy
The schema deliberately does not carry any secret-bearing daemon settings:
- NATS auth (
creds,token,user,password,nkey) - TLS key password
Supply these via environment variables (or --flag for ad-hoc use). Putting them in a checked-in YAML file would silently widen exposure, so the loader has no way to accept them.
Environment layer
Two parallel schemes are honoured:
Uniform
RSIGMA_<SECTION>__<KEY>(recommended). Nested keys use the__separator; single underscores stay inside a key. Values are parsed as YAML scalars so types coerce naturally (ints, bools, lists). Examples:Env var Equivalent config RSIGMA_DAEMON__API__ADDR=127.0.0.1:9090daemon.api.addrRSIGMA_DAEMON__INPUT__BUFFER_SIZE=20000daemon.input.buffer_sizeRSIGMA_GLOBAL__LOG_FORMAT=jsonglobal.log_formatRSIGMA_MCP__HTTP_ADDR=127.0.0.1:9100mcp.http_addrLegacy clap-bound names with a single underscore (
NATS_CREDS,RSIGMA_CONSUMER_GROUP,RSIGMA_TLS_KEY_PASSWORD). These continue to work at the flag layer and are listed in Environment Variables. Secrets are only readable this way.
The uniform scheme is detected by the __ separator, so it never collides with the legacy single-underscore names.
--dry-run and config show
config show folds default + file + env and reports the winning layer for each leaf. To preview what a real command will use, including its flag layer, the daemon, eval, backtest, coverage, scorecard, visibility, and hygiene commands support --dry-run:
rsigma engine daemon --dry-run
# prints the effective daemon section as YAML, then exits 0
In config show output the layer is one of default, file, or env. In a command’s --dry-run view, flag-supplied values appear on top of all three.
Format versioning
Every config carries version: 1 at the top level. The loader currently accepts any value (the field is informational), but future migrations will gate on it; treat it as required when authoring new files.
See also
rsigma config initto scaffold a template.rsigma config validatefor layered loading with diagnostics.- Environment Variables for the legacy single-underscore names and the precedence with CLI flags.
- Exit codes for the
CONFIG_ERROR(3) contract used by every config command.