feat(federation): seal federation peer client keys at rest (FED-M2-05)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/pr/ci Pipeline was successful

- Add packages/auth/src/seal.ts: shared AES-256-GCM seal/unseal using BETTER_AUTH_SECRET
- Export seal/unseal from @mosaicstack/auth index
- Refactor provider-credentials.service.ts to import seal/unseal from @mosaicstack/auth
- Add apps/gateway/src/federation/peer-key.util.ts: sealClientKey/unsealClientKey wrappers
- Add peer-key.spec.ts with 5 vitest tests (round-trip, non-determinism, at-rest, tamper, missing secret)
- Document key rotation deferred procedure in docs/federation/SETUP.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jarvis
2026-04-21 22:02:59 -05:00
parent bb24292cf7
commit 733f3b6611
6 changed files with 134 additions and 55 deletions

View File

@@ -117,3 +117,9 @@ docker compose -f docker-compose.federated.yml logs valkey-federated
```
If Valkey is running, verify your firewall allows 6380. On macOS, Docker Desktop may require binding to `host.docker.internal` instead of `localhost`.
## Key rotation (deferred)
Federation peer private keys (`federation_peers.client_key_pem`) are sealed at rest using AES-256-GCM with a key derived from `BETTER_AUTH_SECRET` via SHA-256. If `BETTER_AUTH_SECRET` is rotated, all sealed `client_key_pem` values in the database become unreadable and must be re-sealed with the new key before rotation completes.
The full key rotation procedure (decrypt all rows with old key, re-encrypt with new key, atomically swap the secret) is out of scope for M2. Operators must not rotate `BETTER_AUTH_SECRET` without a migration plan for all sealed federation peer keys.