SentrySentry
Plugins

Challenge Providers

Edge actions provider-agnostic — o trait ChallengeProvider e os providers embutidos

Edge actions e ChallengeProvider

Edge actions (block / challenge / rate-limit em CDN/WAF) são provider-agnostic via trait ChallengeProvider, espelhando o padrão do LlmProvider. Isso permite trocar a Cloudflare por AWS WAF, Fastly, Bunny… sem mudar o ActionKind, as regras ou o filtro de verdict.

/// A provider that can apply an edge action (block / challenge / rate-limit).
#[async_trait]
pub trait ChallengeProvider: Send + Sync {
    fn name(&self) -> &'static str;
    async fn apply(&self, ip: IpAddr, verdict: Verdict, opts: &EdgeOptions) -> Result<()>;
}

O provider recebe um EdgeOptions (ttl + mode, onde mode é um EdgeMode: block | js_challenge | managed_challenge | rate_limit) e pode derivar o modo efetivo do verdict. Implementações devem ser idempotentes e manter cache de dedupe próprio — o daemon pode repetir decisões depois de um restart.

Filtro de verdict — ChallengeAction

A lógica de "qual veredito vira action" fica uma vez, no core: o tipo ChallengeAction embrulha o provider e seu applies_to aceita apenas Block, Challenge e RateLimit. Allow (benigno) e Quarantine (retido para análise LLM) são filtrados centralmente — o provider nunca precisa repetir a checagem. O provider só executa no edge.

Providers embutidos

Os providers conhecidos por daemon::build_challenge_action:

ProviderCrateEnforcementObservações
cloudflaresentry-action-cloudflareIP Access Rules + IP Lists (IPv6)API; TTL via notes
firewallsentry-action-firewallnftables / ipset / firewalldkernel; Linux-only; roda inline
opnsensesentry-action-opnsensealias table via REST alias_utildrop-only
pfsensesentry-action-opnsensetabela pfctldrop-only
nginxsentry-action-nginxincludes deny + geo map de JS challengemesmo host do daemon

Cloudflare

Aplica block/challenge/rate-limit via IP Access Rules (POST /zones/{zone}/firewall/access_rules/rules; o endpoint legado /firewall/rules foi descontinuado). A API não tem TTL por regra, então cada regra criada carrega em notes o stamp sentry:<created_unix>:<ttl_secs> — expiry recuperável entre restarts.

[[action]]
type = "challenge"
provider = "cloudflare"
[action.options]
mode = "managed_challenge"   # block | js_challenge | managed_challenge | rate_limit
ttl_secs = 86400
# max_failures = 3           # circuit breaker (default 3)
# ipv6_prefix = 64           # block/rate-limit IPv6 via IP List
# list_name = "sentry_blocks"
  • Env: SENTRY_CF_TOKEN + SENTRY_CF_ZONE obrigatórios (sem eles a action é pulada com warning); SENTRY_CF_ACCOUNT opcional (o account id é derivado do zone lookup quando ausente).
  • Reconcile no startup: verifica o token, readota regras vivas da edge no cache local (evita duplicar inserts) e deleta as expiradas.
  • Reaper: task de fundo (300 s) deleta regras cujo TTL no notes venceu.
  • Idempotência: duplicate-rule (CF 10009) é tratado como sucesso.
  • Circuit breaker: após max_failures inserts falhos consecutivos o provider se desativa até restart (falha de config não gera stream infinito de requests condenados).
  • IPv6 /64 (F2.14): IP Access Rules aceitam só endereço exato; com ipv6_prefix, vereditos Block/RateLimit para clientes IPv6 viram itens de prefixo em uma IP List account-level (sentry_blocks) + uma custom rule ip.src in $sentry_blocks (action block).

firewall

Bans de kernel (mesma crate descrita em Ações). Único provider que roda inline no hot path por default — contenção local, latência de fila zero.

[[action]]
type = "challenge"
provider = "firewall"
[action.options]
backend = "auto"     # auto | nftables | ipset | firewalld
ttl_secs = 86400

opnsense / pfsense

Bans em appliance — mesma crate, dois protocolos (detalhes em Ações). Plataformas drop-only: Challenge e RateLimit são logados como unenforced.

[[action]]
type = "challenge"
provider = "opnsense"   # ou "pfsense"
[action.options]
base_url = "https://192.0.2.10"   # obrigatório para opnsense
table = "sentry_blocks"

nginx

Geração de includes + reload (detalhes em Ações). Para o challenge JS, inclua o snippet gerado dentro do seu server {}:

include /etc/nginx/conf.d/sentry/sentry-challenge-if.conf;
[[action]]
type = "challenge"
provider = "nginx"
[action.options]
conf_dir = "/etc/nginx/conf.d/sentry"
reload_cmd = "nginx -s reload"
validate = true

Guarda never-ban

IPs em [real_ip] trusted_ips (e trusted_lists/whitelist, que entram no mesmo conjunto) nunca são banidos: o pipeline faz short-circuit para Allow e marca o IP como ReputationTier::Authorized — logo o filtro de verdict do ChallengeAction nem dispara. Os providers de containment local (firewall, opnsense/pfsense, nginx) recusam o IP de novo como guarda final, antes de qualquer comando ou chamada de API; o fast-path da edge inline também respeita o conjunto.

Alias de compatibilidade

type = "cloudflare" sem provider é equivalente à forma canonical type = "challenge" + provider = "cloudflare" e mantido por compatibilidade. Configs novas devem preferir a forma canonical.

Adicionar um novo provider de edge (AWS WAF, Fastly, Bunny…)

  1. Crie a crate sentry-action-<nome> implementando ChallengeProvider.
  2. Adicione-a a sentry-cli/Cargo.toml.
  3. Adicione um braço no match de daemon::build_challenge_action.

Sem mudar ActionKind, regras, ou filtro de verdict.

Sem provider: challenge PoW na edge inline

Em [deployment] mode = "inline" existe uma opção que não fala com nenhuma API: o challenge JavaScript interativo com proof-of-work embutido (JsChallenge, opt-in em [edge.challenge]). Um veredito Challenge vira um interstitial 503 com um puzzle SHA-256; a solução vira o cookie sentry_ch=<bucket>:<nonce>, válido pela graça de um bucket.

[edge.challenge]
enabled = true
# secret_env = "SENTRY_EDGE_CHALLENGE_SECRET"  # obrigatório quando enabled
# bucket_secs = 3600   # challenge e cookies rotam por bucket
# difficulty = 16      # bits zero iniciais (clamp 8..=28)
# template_path = "/etc/sentry/challenge.html"  # página custom (hot-read)
  • O segredo (SENTRY_EDGE_CHALLENGE_SECRET, 32+ bytes aleatórios) é obrigatório quando enabled = true — o startup falha sem ele.
  • Quem executa o veredito Challenge na edge é o challenge_backend (ChallengeBackend): sentry (default, PoW embutido) ou cloudflare (o veredito vira regra no CF; exige uma action com provider = "cloudflare").
  • O PoW nunca destrava um Block; bots verificados via rDNS ([bot_verification]) passam sem resolver; o cookie ganha Secure quando a própria edge termina TLS.

On this page