SentrySentry
Rules Engine

Rules Engine

Motor de regras determinístico WAF-style — fast path antes de heurísticas e IA

Rules Engine

O Sentry tem um motor de regras determinístico que roda antes das heurísticas e da IA — é o "fast path" do Pipeline::process. Inspirado nas Custom Rules / WAF da Cloudflare: cada regra é um match + action, avaliada em ordem de prioridade crescente, com short-circuit. Regras são a primeira linha de defesa (bloqueio instantâneo de scanners, Tor, VPN/proxy, países) e também a fonte de allowlists (IPs/ASNs confiáveis que bypassam todo o scoring).

Semântica de avaliação

O RuleSet mantém as regras ordenadas por priority (menor = avalia primeiro) e evaluate_with retorna o primeiro match. O que acontece depende da RuleAction:

ActionEfeito
AllowShort-circuit: bypass total de scoring e IA (allowlist).
Block / Challenge / RateLimitShort-circuit: executa a contenção e encerra o pipeline.
LogAnota o evento (RuleHit peso 0) e continua para heurísticas + IA.
TagIdem Log: anota e deixa fluir.

Ordem resumida:

Evento normalizado
  └─ Rules Engine (por prioridade; primeiro match vence)
       ├─ Allow                     → Allow + bypass de scoring/AI
       ├─ Block/Challenge/RateLimit → contenção imediata (short-circuit)
       ├─ Log/Tag                   → anota e continua
       └─ nenhum match              → heurísticas → reputation → routes
                                      → scorer → policy → decider

Um short-circuit de Block/Challenge/RateLimit gera um sinal RuleHit com peso fixo por verdict (Block 100, Challenge 50, RateLimit 30) e respeita a guard de never-ban ([real_ip] trusted_ips) e o flag cap_shadow — IPs em shadow-list são analisados mas nunca banidos. A verbosidade no console do evento short-circuitado é controlada por log_level na regra (silent suprime a linha; o evento continua sendo armazenado e despachado).

Tipos principais

Definidos em crates/sentry-core/src/rules.rs.

Rule — uma regra individual:

pub struct Rule {
    pub id: RuleId,
    pub name: String,
    pub priority: i32,
    pub enabled: bool,
    pub match_: RuleMatch,
    pub action: RuleAction,
    pub ttl: Option<Duration>,
    pub source: RuleSource,
    pub tags: Vec<String>,
    pub log_level: Option<RuleLogLevel>,
}
  • ttl expira regras dinâmicas (blocks temporários; o reaper do Cloudflare usa o mesmo formato sentry:<ts>:<ttl>).
  • log_level controla a verbosidade da linha no console (silent, info, warn, error).
  • O id de regras de config é um slug ASCII estável do nome (allow_internal_monitoring).

RuleAction — Allow | Block | Challenge | RateLimit | Log | Tag.

RuleSource — origem da regra:

VarianteOrigem
Config[[rules.custom]] no sentry.toml.
DbCriada via CLI/dashboard, persistida no Postgres.
CloudflareSyncEspelho de regras vivas do edge Cloudflare (reconcile no startup).
FeedGerada pelo importador de reputation feeds/datasets (feed:<name>).
AutoLearnedAuto-block com TTL derivado de incidentes confirmados.
DefaultPackPack default embutido.

RuleMatch — a condição (árvore combinável All/Any/Not). A referência completa das condições e da sintaxe textual está na página DSL de Match.

RuleSet — conjunto compilado e ordenado por prioridade, com replace_by_prefix para troca atômica de grupos de regras (usado no hot-reload de datasets).

SharedRuleSet — alias Arc<RwLock<RuleSet>> (definição): o daemon compartilha o mesmo handle com pipeline, edge inline e CLI; o hot-reload troca o conjunto interno com write() e a avaliação lê com read().

Fontes de regras

  1. Config (sentry.toml) — [[rules.custom]] compiladas por rules_from_config: uma expressão DSL inválida derruba só aquela regra (com o nome no erro), não o config inteiro.
  2. Postgres (tabela rules) — regras dinâmicas criadas via CLI (sentry rules add/allow/block) ou dashboard.
  3. Packs default — ver Default Rule Packs.
  4. Reputation feeds e datasets — regras sintéticas feed:<name> (prioridade 50) geradas por feed_rule (IP, quando a feed declara action) e dataset_rule (user_agent/path/ja3).
  5. Cloudflare sync — o reconcile do startup adota regras vivas do edge como espelho local (CloudflareSync).
  6. Auto-learned — escalada de reincidentes persistida no ip_state.

Hot-reload

  • sentry_rules_changed — task rules_hot_reload faz LISTEN no canal Postgres, recarrega o ruleset do banco e troca o Arc<RwLock<RuleSet>> sem restart. CLI/dashboard emitem o NOTIFY.
  • sentry_datasets_changed — task datasets_hot_reload reconstrói as regras com prefixo dataset: via replace_by_prefix (troca atômica, all-or-nothing) e atualiza os literais do prefilter.
  • O Postgres é a fonte da verdade: um nó que sobe depois carrega o ruleset do banco no startup.

Caches de performance (F5)

  • Cache de regex (REGEX_CACHE) e cache de IP-spec (IP_CACHE) de processo: padrões compilados 1× (o código antigo compilava regex por regra por evento — ~3,4 ms/evento). Patterns inválidos são cacheados como None para não re-parsear por evento.
  • Prefilter Aho-Corasick — as heurísticas só rodam a regex da família quando um literal aparece no texto (PREFILTER, um ArcSwap); datasets user_agent/path entram nesse gate via reload_dataset_lists, junto com SENSITIVE_PATH_RE e BAD_CRAWLER_RE.
  • Decode-once — o path URL-decodificado é computado 1× por avaliação (EvalCtx) e compartilhado por todas as condições path; regras nunca são burladas por encoding (%2e%2e%2f = ../, + = espaço — url_decode).

Empacotamento de config

Packs default são declarados assim:

[[rules.pack]]
name = "vpn_proxy"
mode = "shadow"          # shadow | enforce | off

[[rules.pack]]
name = "country_blocklist"
mode = "enforce"

[rules.pack.params]
countries = ["RU", "CN"]

Cada pack vira um par de chaves no mapa de modos e cada param é achatado como <pack>__<param> (ex.: country_blocklist__countries) antes de ir ao builder — wiring no daemon. Esse achatamento (F7.6) corrigiu o bug em que params de pack nunca chegavam ao builder. Só valores string e arrays de string são renderizados. Os params lidos hoje são country_blocklist__countries e host_allowlist__domains (pack_list_param).

CLI de gestão de regras

sentry rules list                                  # lista regras ativas
sentry rules show <id>
sentry rules add --name "block admin from RU" \
    --match 'country=RU AND path=/admin/*' --action block --priority 10
sentry rules allow <ip> [--ttl 24h] [--note "monitoring agent"]
sentry rules block <ip> [--ttl 24h] [--note "scan"]
sentry rules enable <id> | disable <id> | delete <id>
sentry rules packs                                 # estado dos packs default
sentry rules test --path /admin --method GET --ip 1.2.3.4 --ua "sqlmap/1.0"

sentry rules test avalia a expressão de match contra um evento hipotético — use para validar regras antes de promover para enforce. As ações allow/block por IP gravam no Postgres e emitem NOTIFY, então nós em execução recarregam sem restart.

Próximos passos

On this page