Files
nas-tools/SECURITY_EXECUTION_PLAN.md
Gan, Jimmy 3fd045aacb
Deploy Dashboard / deploy (push) Successful in 1m28s
feat: security hardening and HTTPS/SSO infrastructure configs
- Narrow trusted proxies, remove overly broad 10.0.0.0/8
- Fail closed on missing SSH known_hosts in terminal proxy
- Add Navidrome reverse proxy headers for Authelia SSO
- Add Gitea docker-compose definition
- Add Caddy configs for NAS and VPS edge proxies
- Add dnsmasq split-horizon DNS config
- Add security execution plan document
2026-02-28 22:25:39 +08:00

4.6 KiB

Security Execution Plan (Dual Caddy: VPS Public + NAS Internal)

Confirmed Architecture

  1. caddy-vps is public ingress only.
  2. nas-caddy is internal ingress only (LAN/Tailscale/internal service routing).
  3. server2 is for VLESS+REALITY and Tailscale exit-node use, not app ingress/CI.
  4. CI/CD is Gitea push-triggered deploy on NAS.

Public Host Responsibility Matrix

  1. auth.jimmygan.com -> VPS Caddy -> NAS Authelia (100.78.131.124:9092).
  2. nas.jimmygan.com -> VPS Caddy -> NAS dashboard (100.78.131.124:4000).
  3. music.jimmygan.com -> VPS Caddy -> NAS navidrome (100.78.131.124:4533).
  4. photos.jimmygan.com -> VPS Caddy -> NAS immich (100.78.131.124:2283).
  5. photos-app.jimmygan.com -> VPS Caddy -> NAS immich (100.78.131.124:2283).

All other service domains remain internal-only unless explicitly approved.

Security Objectives

  1. Keep your public access goals (nas/music/photos/photos-app) working.
  2. Enforce centralized auth + policy at public edge (caddy-vps + Authelia).
  3. Remove secret leakage risk and tighten trust boundaries.
  4. Preserve internal NAS workflows and current service availability.

Phase 0 - Pre-Change Safety

  1. Snapshot current configs:
    • VPS: /etc/caddy/Caddyfile
    • NAS: /volume1/docker/caddy/Caddyfile
    • NAS: /volume1/docker/authelia/config/configuration.yml
  2. Export backups for dashboard/gitea/immich/auth config + DB.
  3. Define maintenance window (expect auth/session resets).

Phase 1 - Secret Rotation and Hygiene

  1. Rotate exposed secrets immediately:
    • Authelia session.secret, storage encryption key, reset JWT secret.
    • LDAP bind password.
    • SMTP app password.
    • Gitea DB password and runner registration token.
    • Telegram bot token and any API tokens.
  2. Move secrets to non-git env/secret files.
  3. Keep .env and local assistant memory files untracked.
  4. Verify no plaintext secrets remain in tracked files.

Phase 2 - VPS Caddy as Single Public Auth Edge

  1. Update VPS Caddyfile to include all public hosts:
    • auth, nas, music, photos, photos-app.
  2. Ensure forward_auth is applied on nas/music/photos/photos-app.
  3. Keep auth.jimmygan.com without forward_auth (Authelia portal itself).
  4. Keep TLS + security headers on VPS Caddy.
  5. Reload Caddy and test all hostnames from public internet.

Phase 3 - Authelia Policy Enforcement

  1. Keep Authelia + LDAP as unified identity source.
  2. Enforce mandatory 2FA for public apps:
    • nas, music, photos, photos-app.
  3. Use group-based access rules where needed (family/media/admin groups).
  4. Keep documented break-glass admin recovery procedure.

Phase 4 - NAS Internal Plane Hardening

  1. Keep NAS Caddy for internal-only domains/routes.
  2. Remove overlap for public host policies from NAS Caddy (or clearly isolate).
  3. Reduce direct host port exposure where possible.
  4. Restrict NAS firewall/source ACL so public app ports are intended-path only.

Phase 5 - Dashboard Hardening

  1. Tighten trusted proxy logic in dashboard backend:
    • Only explicit proxy IPs/subnets.
    • No broad trust defaults.
  2. Harden /api/auth/proxy against header spoofing.
  3. Make SSH terminal fail-closed when known_hosts is missing.
  4. Move dashboard auth from localStorage tokens to secure httpOnly cookies.
  5. Add CSRF defenses for state-changing endpoints after cookie migration.

Phase 6 - Jellyfin/LLDAP Persistence Fix

  1. Persist network attachment in compose (current runtime docker network connect is not durable).
  2. Avoid exposing LDAP bind ports publicly if not required.
  3. Keep Jellyfin auth path consistent with Authelia/LDAP strategy.

Phase 7 - Validation Checklist

  1. Public access works for:
    • https://nas.jimmygan.com
    • https://music.jimmygan.com
    • https://photos.jimmygan.com
    • https://photos-app.jimmygan.com
  2. All above require Authelia login and 2FA.
  3. https://auth.jimmygan.com is reachable and stable.
  4. No app access from internet via raw NAS ports.
  5. Internal-only routes still work from LAN/Tailscale.
  6. Secret scan returns no tracked plaintext credentials.

Rollback Plan

  1. Restore previous VPS Caddyfile and reload Caddy.
  2. Restore previous NAS Caddyfile/Authelia config.
  3. Revert to prior container image tags if app auth breaks.
  4. Keep old+new secrets during transition window, then remove old.

New Conversation Handoff Prompt

Use this to resume execution in a new chat:

"Execute SECURITY_EXECUTION_PLAN.md phase-by-phase. Start with Phase 0 and Phase 1 only, show diffs before apply, and validate after each phase. Preserve dual-Caddy architecture: VPS public ingress, NAS internal ingress."