
## Emenda 2026-10-21 — isolamento de rede e hardening de container (D5)

O "security in depth" acima era **da aplicação**. A camada de **runtime** (o que o container
pode fazer, e com quem ele pode falar) é tão decisiva quanto a aplicação: o `web` é o único
serviço exposto à internet, e um comprometimento dele não pode dar acesso aos dados.

- **Duas redes, e o contrato é medido:** `edge` (web, php-fpm, queue, mailpit, jaeger) tem
  saída para a internet — o `composer install` do deploy, o IndexNow e o export OTLP dependem
  dela; `data` (php-fpm, queue, postgres, valkey, storage) é `internal: true`, **sem rota
  padrão**: um dump, uma chave de sessão ou um objeto de mídia não vazam para fora. O `web`
  fica **só** na `edge` — ele não alcança o banco, o cache nem o storage.
- **Guard permanente:** `tools/network-check.sh` confere a topologia declarada **e** a matriz
  medida (o `web` não abre conexão com o Postgres; o app abre; os dados não têm rota padrão),
  rodado pelo `make check`. Uma rede que "parece" isolada no arquivo e não está isolada no
  container é exatamente o que o guard pega.
- **Hardening por container:** `no-new-privileges` em todos os serviços; `cap_drop: [ALL]` nos
  que rodam non-root e não precisam de capability; `pids_limit` e `ulimits.nofile`;
  `init: true` com `stop_grace_period` coerente com o timeout do worker.
- **Duas exceções medidas, e são exceções do binário, não do desenho:**
  - o **Caddy** tem capability de **arquivo** (`cap_net_bind_service=ep`): com
    `cap_drop: [ALL]` o exec é negado — o `web` mantém `cap_add: [NET_BIND_SERVICE]`;
  - o **Postgres** não tem `cap_drop`: o entrypoint da imagem faz `chown` no PGDATA como root
    e precisa de `CAP_CHOWN` (sem ela o container não sobe).
- **O segredo do cache fora do argv:** a senha do Valkey é renderizada num conf de runtime
  dentro do container (modo 600) — o `ps` do host não mostra a senha do cache, da sessão e da
  fila (que é a sessão do CMS).

Alternativas descartadas: manter uma rede só com firewall no host (o container não tem regra
própria e o host é o cPanel do cliente); três ou mais redes (mais topologia, mais chance de o
app perder a saída); `cap_drop: [ALL]` em todo mundo (quebra o Postgres e o Caddy, medido).
