Acaua is a collective SOC daemon consuming only Zeek log files, not a single-user tool needing local hardware like its siblings. Drop the Tauri desktop shell, installers and self-update entirely; the server and its web dashboard ship as a container, updated by pulling a new image tag. Link against the official prebuilt libduckdb instead of compiling it from source via the bundled feature, cutting image build time from 15+ minutes to about 3. Fix a real bug found along the way: as PID 1 in a container, the daemon ignored SIGTERM and was always killed after the stop timeout; it now shuts down gracefully. Also corrects the Pillar 1 beaconing score: the period estimate had a harmonic alias (a perfectly periodic 4h series resolved to 600s), and the old score formula flagged pure random traffic as suspicious (p95 = 0.839 on Poisson noise). The new formula was validated against 300 samples per scenario. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VAyr8d7HuAdUGB6aA5xmDD
7.6 KiB
Arquitetura
English · Português
O Acauã é um produto único em Rust: um daemon/CLI, um núcleo compartilhado e um dashboard web embutido. O runtime distribuído não tem Python nem banco externo. Este documento registra as decisões estruturais e as seis correções aplicadas ao blueprint original.
Stack
| Camada | Escolha | Motivo |
|---|---|---|
| Core, CLI e daemon | Rust 2021 (MSRV 1.88) | Toolchain única, segurança de memória, sem dependências externas de runtime |
| API HTTP | Axum + Tokio + Tower HTTP | Superfície assíncrona enxuta, fácil de embutir |
| Dashboard Web | HTML/CSS/JS vanilla | Sem etapa de build de frontend, assets embutidos no binário via rust-embed |
| Armazenamento analítico | DuckDB + Parquet | Armazenamento colunar embutido obrigatório, linkado à libduckdb.so oficial pré-compilada |
| Implantação | Docker / docker-compose | Daemon de SOC coletivo, usuário não-root sem privilégios, rootfs somente leitura |
| Validação científica | Python apenas em research/ |
astropy/scipy/networkx para fixtures, nunca distribuído |
O workspace possui dois crates: acaua-core e acaua-cli. Ambos utilizam version.workspace = true.
Componentes
Logs Zeek ──► acaua-core::zeek ──► eventos normalizados ──► storage
│
├──► pillar1 (beaconing)
├──► pillar2 (sessões persistentes)
├──► pillar3 (anomalias de protocolo)
└──► pillar4 (fusão) ──► alertas + evidência
│
acaua-cli (serve) ──► API axum ──► dashboard web embutido ──────────┘
zeek: parser delimitado e confinamento de caminhos. Nunca segue symlink fora da raiz do dataset.storage: motor DuckDB em memória sobre arquivos Parquet particionados por dia com TTL de sete dias.pillar1–pillar4: funções puras sobre eventos normalizados. Retornam scores e evidência, nunca apenas um float.fusion: combinação limitada em ordem fixa. Deve ser simétrica e reproduzível.doctor: checagens do ambiente local; reporta linkagem da DuckDB pré-compilada e status do Zeek em container.update: checa novas versões consultando a API de Releases do Gitea.
As seis correções
1. Rayleigh/Schuster, não Lomb–Scargle puro
Timestamps de eventos são um processo pontual unidimensional: não há valor y
para ajustar. O periodograma primário é, portanto, Rayleigh/Schuster:
P(T) = (2 / N) * [ (sum cos(2*pi*t_i / T))^2 + (sum sin(2*pi*t_i / T))^2 ]
Lomb–Scargle generalizado fica reservado para a extensão futura que avaliará um atributo real de resposta (como tamanho de payload ou duração) contra o tempo.
2. Proteger o caso de dispersão zero no MADM
Um beacon sintético ou sem jitter produz intervalos perfeitamente iguais. O
desvio absoluto mediano em relação à mediana (MADM) é então 0.0. Dividir por
0.0 ou tratá-lo como dado ausente é incorreto: dispersão zero é o resultado mais
suspeito possível. A implementação protege esse caso com atribuição explícita de
score (1.0) e sentinela documentado.
3. Substituir assimetria de Pearson por assimetria de Bowley
A assimetria amostral baseada no terceiro momento central é sensível a outliers individuais e pode divergir. A assimetria de Bowley utiliza quartis:
B = (Q3 + Q1 - 2*Q2) / (Q3 - Q1)
Ela é limitada em [-1.0, 1.0] por definição e resistente a outliers extremos.
Quando Q3 == Q1 (dados concentrados), a implementação atribui 0.0 com flag
sentinela.
4. Isolar o espaço de pesquisa Python
research/ tem seu próprio ambiente virtual e dependências. Ele é excluído do
workspace Cargo, ignorado em builds Docker e releases de CI, e testado apenas
quando scripts de validação de pesquisa forem invocados diretamente.
5. Modo degradado documentado para NetFlow/IPFIX
NetFlow v9 e IPFIX não carregam nomes de consulta DNS, SNI TLS, cadeias de certificados ou cabeçalhos HTTP. Qualquer análise que dependa de recursos de protocolo fica indisponível. O Acauã documenta isso como modo degradado e nunca alega paridade entre registros de fluxo e logs Zeek completos.
6. Fronteira única HTTP e RPC
O daemon expõe uma API Axum em loopback por padrão. A UI web embutida se comunica com o daemon exclusivamente por chamadas HTTP padrão.
API
A API HTTP é servida por acaua serve:
| Método | Caminho | Significado |
|---|---|---|
| GET | /api/health |
Liveness e versão |
| GET | /api/status |
Uptime, diretório de dados, sumário do dataset |
| GET | /api/alerts |
Alertas paginados com evidência |
| POST | /api/analyze |
Ingestão e análise de diretório de dataset |
| GET | /api/update |
Checagem de novas releases |
| GET | /logo.png |
Asset de marca embutido |
| GET | /* |
Fallback de UI embutida (rust-embed) |
serve escuta em 127.0.0.1:8787 por padrão. Expô-lo em uma rede externa exige
um proxy reverso com autenticação.
Armazenamento
DuckDB é uma dependência obrigatória linkada dinamicamente à libduckdb.so
oficial pré-compilada (versão 1.5.6 fixada com SHA-256 em scripts/fetch-libduckdb.sh).
Extensões Parquet, JSON e ICU já vêm compiladas estaticamente na biblioteca oficial.
O esquema consiste em arquivos Parquet particionados por dia sob o diretório de
dados configurado, com consultas DuckDB em memória e TTL de sete dias.
Atualizações
Atualizações do Acauã são distribuídas por imagens de container (docker compose pull && docker compose up -d).
O comando acaua update consulta a API de Releases do Gitea para ciberfauna/acaua e
notifica os operadores quando uma tag de versão mais nova estiver disponível. A
sobrescrita binária em disco (update --apply) foi removida: em um daemon de SOC
coletivo orquestrado via container, atualizações devem ser controladas por puxar
imagens novas em vez de processos que alteram o próprio executável.
Alternativas rejeitadas
- Serviço Python com FastAPI/ClickHouse: Rejeitado. Um runtime Python introduziria imagens pesadas e fronteiras de memória desnecessárias; o ClickHouse adicionaria um servidor externo e custo operacional para datasets que cabem perfeitamente em um armazenamento colunar embutido. O produto é 100% Rust.
- Aplicativo desktop (Tauri / AppImage / NSIS): Rejeitado. Diferente do Guará (forense em disco bruto local) e do Sabiá (hardware Wi-Fi em modo monitor), o Acauã não tem dependência de hardware local: é um daemon de SOC multiusuário consumindo logs do Zeek. Um wrapper desktop traria manutenção e superfície de segurança sem ganho operacional.
Implantação
- Docker Compose (Oficial): Imagem multi-arch (
git.lucasrguerra.dev.br/ciberfauna/acaua), rodando com usuário não-privilegiadoacaua(UID 10001), filesystem somente leitura e capabilities revogadas. - Compilação nativa:
scripts/fetch-libduckdb.sh ~/.cache/acaua/duckdbseguido decargo build --release -p acaua-cli.
Comportamento em falhas
Entradas malformadas são ignoradas com diagnóstico delimitado e contado. Um log
ausente não é fatal. Um banco corrompido é reportado pelo doctor e nunca
recriado silenciosamente sobre dados existentes.
Versionamento e compatibilidade
SemVer 2.0.0. O JSON de evidência carrega uma versão de esquema. Qualquer
alteração em uma pontuação ou no formato de evidência é breaking change para
versões minor 0.x e deve constar no changelog.