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 total

Trade-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 --verify deve sempre retornar Hash chain: VALID
  • Pra protecao contra reescrita: copiar hash_atual mais recente pra fora periodicamente (log file imutavel, S3 com object lock)

Recursos relacionados

By Borlot.com.br on 23/05/2026