Modelo de Seguranca
O que o Tatuzim protege
| Asset | Onde fica | Protecao |
|---|---|---|
| Identidade dos agentes (cert + key) | /var/lib/tatuzim-agent/identity/ |
Perm 0600 (key) + user dedicado |
| Estado autoritativo (agents, eventos, tokens) | db.enc no hub |
ChaCha20-Poly1305 + Argon2id |
| Conteudo de cargas (futuro modo selado) | Cofre + envelope encryption | X25519 ECDH per-destinatario |
| Audit log | Tabela eventos no vault |
Hash chain SHA256 |
| Tokens de enrollment | Tabela enrollment_tokens |
SHA256 do plaintext + single-use |
| Identidade do server (TLS cert) | step-ca | Pubkey pinada no agent |
| Chave de release minisign | /proj/.secrets/... |
0600 + debito tecnico (Cofre planejado) |
Modelo de ameaca
Ataques cobertos
| Ataque | Resposta do Tatuzim |
|---|---|
| MITM passivo no link Agent↔Server | mTLS strict — payload nao visivel |
| MITM ativo tentando inserir-se | Cert pinado da CA — atacante sem cert nao consegue handshake |
Atacante captura arquivo db.enc |
Argon2id KDF + ChaCha20-Poly1305 — sem passphrase, inutilizavel |
Atacante captura agent.key |
So compromete aquele 1 agent. Revoga via agentes.revoked_at |
| Token de enrollment vazado em log | Apenas SHA256 no DB; cleartext mostrado uma unica vez |
| Token replay | consumed_at marca como usado; reuse rejeitado |
| Enrollment em hostname errado | Token tem expected_hostname, validado antes de assinar |
| Adulteracao do audit log | Hash chain SHA256 detectavel via evento list --verify |
| Self-update com binario malicioso | Verificacao minisign com pubkey embutida no agent |
| Bruteforce do token (32 bytes) | 256 bits de entropia — infeasivel |
Ataques parcialmente cobertos
| Ataque | Limitacao | Mitigacao planejada |
|---|---|---|
| Comprometimento do hub (root) | Atacante usa step-ca intermediate online pra emitir certs | Root CA offline limita blast: voce gera novo intermediate + atualiza root pinada |
| Adulteracao da chain inteira | Atacante com vault inteiro pode regerar todos hashes | Witness externo (publicar hash atual em sistema imutavel) |
| Cert de uso vazado | Lifetime atual e ~24h | v0.4: identidade-de-uso de minutos, identidade-raiz raramente usada |
| Race em consume_token (2 enrolls simultaneos) | Stoolap nao tem SELECT FOR UPDATE |
Mitigado parcialmente por Mutex no AppState; futura transaction explicita |
Ataques nao cobertos (por design)
| Ataque | Por que nao |
|---|---|
| Atacante com root no agent | Tem acesso a agent.key que esta no disco. Solucao requer TPM/HSM — fora de escopo MVP |
| Atacante com root no hub e step-ca offline tambem | Game over total — voce perdeu a CA inteira |
| Comprometimento da chave minisign de release | Atacante pode assinar updates maliciosos. Mitigacao: mover pro Cofre quando existir |
| DoS no endpoint enroll | Sem rate limit no MVP. Workaround: rate limit no reverse proxy (Traefik) |
Camadas de defesa
┌────────────────────────────────────────────────────────────────┐
│ ATAQUE │
└────────────────────────────────────────────────────────────────┘
│
passa por todas as camadas pra ter sucesso
▼
┌────────────────────────────────────────────────────────────────┐
│ Camada 1: WireGuard (opcional) │
│ - Atacante nao consegue nem alcancar a porta │
└────────────────────────────────────────────────────────────────┘
▼
┌────────────────────────────────────────────────────────────────┐
│ Camada 2: TLS (sempre) │
│ - Trafego encriptado em transito │
└────────────────────────────────────────────────────────────────┘
▼
┌────────────────────────────────────────────────────────────────┐
│ Camada 3: mTLS strict (rotas /v1/certs/issue, manifest, events)│
│ - Cert do cliente deve ser assinado pela CA pinada │
│ - Self-signed ou Let's Encrypt e rejeitado │
└────────────────────────────────────────────────────────────────┘
▼
┌────────────────────────────────────────────────────────────────┐
│ Camada 4: Middleware de identidade │
│ - CN do client cert deve bater com agente registrado │
│ - Agente revogado → 401 │
└────────────────────────────────────────────────────────────────┘
▼
┌────────────────────────────────────────────────────────────────┐
│ Camada 5: Logica de negocio │
│ - CSR CN deve ser igual ao hostname do agent autenticado │
│ - Token deve estar nao-consumido, nao-expirado, hostname OK │
└────────────────────────────────────────────────────────────────┘
▼
┌────────────────────────────────────────────────────────────────┐
│ Camada 6: Encriptacao at-rest │
│ - Mesmo com acesso ao disco, sem passphrase = inutil │
└────────────────────────────────────────────────────────────────┘
▼
┌────────────────────────────────────────────────────────────────┐
│ Camada 7: Permissoes UNIX │
│ - User dedicado, 0600 nas chaves, 0750 no datadir │
└────────────────────────────────────────────────────────────────┘
▼
Sucesso = pwn totalTrade-offs assumidos
Encriptacao com passphrase env vs HSM
Escolha: passphrase em env var (compativel com systemd).
Trade-off: atacante com root no host le /proc/<pid>/environ e pega a passphrase. Aceito porque HSM/TPM e setup complexo e overkill pro MVP. Pra prod sensivel, considerar systemd-creds ou TPM.
CN do CSR no `/v1/certs/issue` so aceita hostname do agent
Escolha: cert emitido tem CN = hostname do agent que pediu.
Trade-off: agent nao consegue pedir cert pra traefik.dev.X.com (CN diferente). Isso e limitacao do MVP — modo CSR no Tatuzim e pra renovar a propria identidade ou pra certs cujo CN = hostname. Pra wildcards/aliases, futura sub-fase com mecanismo dedicado.
Single-writer no vault (flock)
Escolha: VaultLock flock exclusivo previne 2 processos abrirem o mesmo vault.
Trade-off: CLI offline nao funciona enquanto server roda. Workaround: parar server, mexer no CLI, reiniciar. Pra v0.2 planejada: API HTTP do server pra todas as operacoes admin.
Stoolap em vez de Postgres/SQLite
Escolha: SQL embedded em pure Rust, single-file.
Trade-off: menos maduro que SQLite. Vantagem: nao tem deps C (compatibilidade musl trivial), backup e cp do arquivo, sem processo extra.
Recomendacoes operacionais
Passphrase do vault
- Armazenar em password manager (Bitwarden) e envelope fisico
- Rotacionar a cada N meses (requer re-seal manual)
- Nunca commitar no Git nem em CI
Backup
db.enc+config.json(com salt e wrapped_dek) = vault completo- Sem a passphrase, esses 2 arquivos sao inuteis pra atacante
- Backup automatico via cron diaria recomendado
Permissoes
/var/lib/tatuzim/
├── config.json 0600 root:root (servidor)
├── db.enc 0600 root:root
└── vault.lock 0600 root:root
/var/lib/tatuzim-agent/ 0750 tatuzim:tatuzim
├── identity/
│ ├── agent.crt 0644
│ ├── agent.key 0600
│ └── ca.pem 0644
├── out/ 0750
├── state/ 0750
└── hooks/post-* 0750 (executavel)Auditoria
- Periodicamente:
tatuzim evento list --verifydeve sempre retornarHash chain: VALID - Pra protecao contra reescrita: copiar
hash_atualmais recente pra fora periodicamente (log file imutavel, S3 com object lock)