Files
acaua/docs/pt-BR/arquitetura.md
T
Lucas RayanandClaude Sonnet 5 8a80504c45
Release / Plan (reuse the published image?) (push) Successful in 3s
CI / Docker image (build and smoke test) (push) Skipped
CI / Format and clippy (push) Successful in 4m32s
CI / Dependency audit (push) Successful in 11s
CI / Tests (Linux) (push) Successful in 9m15s
Release / ci (push) Successful in 9m18s
Release / Build image (arm64) (push) Failing after 7m7s
Release / Build image (amd64) (push) Failing after 13m53s
Release / Publish tags (push) Skipped
Release / Gitea release (push) Skipped
refactor: distribute Acaua as a Docker image instead of a desktop app
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
2026-10-31 19:54:45 -03:00

163 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Arquitetura
[English](../architecture.md) · **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:
```text
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:
```text
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
1. **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.
2. **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-privilegiado `acaua` (UID 10001), filesystem somente leitura e capabilities revogadas.
- **Compilação nativa:** `scripts/fetch-libduckdb.sh ~/.cache/acaua/duckdb` seguido de `cargo 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.