# Phase 4 deferred: mTLS + Infisical The PRD lists mTLS (Layer 2 admin API hardening) and Infisical (secret manager) as Phase 4 work. Both are deliberately deferred. Reasons + trigger criteria below. ## mTLS for `/internal/admin/*` **Why deferred:** no spoke currently exposes `/internal/admin/*`. Layer 2 is wire-ready (`AdminClient` with `X-Internal-Token`) but unused. Standing up a CA, distributing client certs, and adding mTLS verification on every spoke before any spoke actually has admin endpoints is premature engineering — we'd ship infrastructure for traffic that doesn't exist. **Threat model today:** spokes have no admin endpoints. There is no Layer 2 traffic to intercept. Tailscale already gates network access to panel-web; the panel cannot be reached from the public internet at all. **Trigger to revisit:** - Second spoke ships `/internal/admin/*` (i.e. we have 2+ spokes calling admin endpoints). - OR token rotation becomes a chore (manual env updates start drifting). - OR a regulatory requirement appears (KVKK audit, customer SOC2 ask, etc.). **When triggered, do:** 1. Generate a self-signed CA (long-lived) and per-spoke client certs (1-year, rotated by cron). 2. Add `caCert` / `clientCert` / `clientKey` options to `AdminClient` (already structured for it). 3. Spoke-side: configure their gateway (Traefik/Caddy/Nginx) to require client cert on `/internal/admin/*`. 4. Keep `X-Internal-Token` as defense-in-depth (mTLS authenticates client *machine*, token authenticates *application*). ## Infisical self-hosted **Why deferred:** no Infisical instance running in this Coolify. Adding it requires (a) deploying Infisical, (b) creating projects + service tokens, (c) installing the agent or SDK in panel-web + panel-worker, (d) migrating ~12 env vars. That's a weekend of work for marginal benefit at this scale — Coolify already encrypts env at rest and audits writes. **Trigger to revisit:** - Need to share secrets across multiple machines (right now everything's on `maestro`). - Need a secret-rotation cadence (e.g. quarterly rotation of `BETTER_AUTH_SECRET`). - Need versioned, time-windowed secrets (preview environments with their own credentials). - Need an audit trail of *who looked at* a secret (Coolify only audits writes). **When triggered, do:** 1. Deploy Infisical via Coolify (1 web + 1 db). 2. Create project `super-panel` with envs `production` and `staging`. 3. Install `@infisical/sdk` in both `apps/web` and `apps/worker`, swap `process.env.X` reads through the SDK with cache. 4. Remove the corresponding Coolify env vars (one at a time; verify on each). 5. Add CI gate: fail PRs that introduce raw `process.env.` access for known-sensitive keys. ## What we *do* have today (Phase 4 actually delivered) - Rate limit on `/sign-in/email` (5/min per IP+email, Redis-backed, fail-open). - Daily audit archive to MinIO (90-day retention). - Daily `pg_dump` of panel-postgres to MinIO (`panel-backups/`). - Restore drill script (`scripts/restore-drill.sh`) — monthly cadence target. - DR runbook (`docs/disaster-recovery.md`).