Files
itpp-infrastructure/audit/phase-two/c4-credential-rotation-plan.md
T
root f5175f1ce0 Sync docs, audit artifacts, project notes, and VerdictTank proposal docs
- audit/phase-one + phase-two: security audit briefs, findings, credential-rotation plan, Docker-USER hardening scripts, rollback refs
- disaster-recovery/restore-test-log.md + backup-dr-audit-2026-08-10.md
- clients/ (modelortho SEO audit, ai-biz-dev competitive landscape), notes/ (tiktok strategy)
- projects/: front-desk-voice-agent, seo-visibility-checker product plan, hotnow-savannah HTML, resend-transactional-email, backup-dashboard-enhancements, code-review-graph, seo-ci-architecture
- proposals/verdicttank/: architecture v4.0, methodology, judge-pool review, consolidation reasoning, cross-check review
- docs/super-search/firecrawl-provider-strategy.md
- updates: CHANGELOG, model-chain, projects-master-readme, intelsight.io
- .gitignore: exclude nested standalone repos (seo-tool, venturebuilt)
2026-08-26 02:27:28 -04:00

8.9 KiB

C4 Credential Rotation Plan (Phase Two, WS1)

Status: APPROVED (D1). Phase 0 complete, Phase 1 in progress. Date: 2026-08-13 Owner: Sho'Nuff

0. What this plan covers (and what it does not)

  • The C4 permission subset is DONE. Logged as P2-C4-001 (app1-bu chmod 600 on 11 secret files + umask 077 root-cause fix). This plan does not re-open it.
  • This plan covers the second half of C4: inventory every plaintext credential, rotate them, and move them to Vaultwarden.
  • Source-hygiene follow-ups are included as Phase 6 (they are rotation-adjacent, not permission work).

1. The two decisions this plan needs from you (up front)

# Decision What it unlocks
D1 APPROVED 2026-08-13 ("A - Rotate, B - Rotate, C - Revoke"): rotate live AI keys (A+B), revoke dead (C) Phase 2 (in progress)
D2 Go/no-go: rotate the MSP-backdoor shared credential, plus approve the per-portal order Phase 3

Everything else in this plan runs under those two gates. Phases 4-6 are lower-risk hygiene and I will flag them individually before executing.

2. Evidence base (phase-one report, section 3.1 C4)

  1. Two unsanitized copies of key-inventory.md on Core (one inside Hermes's reference dir).
  2. Private scripts repo hardcodes the MSP-backdoor admin password reused across client onboardings (Git-A Finding 1). Single most consequential live credential.
  3. app1-bu /root/.hermes/.env (mode 644) holds ~20 plaintext secrets: root passwords for app1/app2/app3, Telegram bot token, Cloudflare/Netcup/SyncroMSP tokens, and eight AI-provider keys.
  4. rally.service, seemytrip.service, giftaroast.service hardcode JWT_SECRET, DEEPSEEK_API_KEY, ADMIN_AI_KEY, and Twilio credentials in world-readable unit files.
  5. app3 MySQL root password in /opt/backup-restore/snapshot.sh (mode 775) and /root/backup.sh.
  6. Public repo itpp-infrastructure re-leaks live admin passwords in a prior audit report (section 7, deferred per Germaine).

Recommended order from the report: app1-bu .env first, then key-inventory.md, then systemd units, then app3 snapshot.sh.

3. Safety rules (non-negotiable, apply to every phase)

  1. Fallback-first. Before any LiteLLM-adjacent or credential-affecting change, Hermes stays pinned to direct DeepSeek. This is already in force since C1 (P2-C1-001); re-confirm at start of each phase.
  2. Vaultwarden-before-changes. Retrieve a credential from Vaultwarden before touching the live system, never from a plaintext file, shell history, or a prior report.
  3. No autonomous key rotation. Every rotation happens only after the go/no-go above, in the order listed.
  4. Verify before done. Every rotation is followed by a live check (API call, login, health endpoint). No "should work" statements.
  5. Log + rollback. Each change is written to change-log.md at the moment it is made, with the rollback path stated before the change.
  6. Zero artifact style. No em dashes or en dashes in any plan or change-log entry. All credential values appear as [REDACTED].

4. Phase 0: Inventory (read-only, no changes)

Goal: a single authoritative list of every live plaintext credential, cross-referenced against Vaultwarden.

Steps:

  1. Re-run the secret-sprawl scan on the three hosts with the raw hit counts (6,296 Core / 5,504 app1-bu / 1,275 app2) and triage down to live, consequential secrets only.
  2. Categorize every secret:
    • (A) AI provider keys
    • (B) MSP-backdoor shared credential
    • (C) server root passwords (app1/app2/app3)
    • (D) service tokens (Telegram, Cloudflare, Netcup, SyncroMSP, Twilio)
    • (E) JWT secrets and DB passwords (systemd units, app3 snapshot/backup scripts)
    • (F) source-repo leaks (key-inventory.md copies, scripts repo, public repo section 7)
  3. Cross-reference each item against Vaultwarden: mark already vaulted, missing, or stale.
  4. Deliverable: an inventory table with a rotation priority, a current location, and a target Vaultwarden item for each credential.

Effort note: this is where the L-XL sizing sits. The raw scan counts are noise; the consequential list is far smaller.

4a. Phase 0 result (2026-08-13)

  • Inventory complete. The report's "eight keys" was an undercount: the live AI surface is ~19 upstream keys across three layers (config.yaml literals, .env plaintext, LiteLLM encrypted credentials), many duplicated.
  • GEMINI_API_KEY and GOOGLE_AI_STUDIO_KEY hold the same value under two names (one rotation, two lines to update).
  • Verdict: A (fallback chain, 7) = Rotate. B (operational LLM, 7) = Rotate. C (dead, 4) = Revoke.
  • Correction: PARALLEL_API_KEY is not dead. It is a live Super Search provider (Parallel.ai Search, fallback #11 in server.py), reclassified as a Phase 3 service token (Keep).
  • Vault gaps: DeepSeek, OpenAI, Google/Gemini, Groq, MiniMax have no Vaultwarden item; Cohere/Fireworks/Perplexity/Mistral have portal logins only.

5. Phase 1: AI provider keys (needs D1)

Sequence (fallback-first, rotate non-active providers before the active one):

  1. Confirm Hermes is pinned to direct DeepSeek and the direct endpoint is healthy (/v1/models + a test completion).
  2. From Phase 0 inventory, confirm the exact list of eight AI providers and which LiteLLM / env locations hold each key.
  3. Rotate the keys for all providers EXCEPT the one Hermes is actively pinned to (DeepSeek), one at a time:
    • Generate a new key at the provider portal.
    • Store the new key in Vaultwarden (target item from Phase 0).
    • Update LiteLLM config and/or env to reference the vault-backed value.
    • Verify the provider still resolves through the fallback chain (test call).
    • Write the change to change-log.md with rollback.
  4. Rotate the pinned provider (DeepSeek) LAST, immediately updating Core .env and LiteLLM before any subsequent API call can fail.
  5. Re-verify the full fallback chain end to end and switch Hermes back to its normal provider only after all eight keys are confirmed live.

Rollback: each step keeps the prior key in the change-log rollback note until the next step verifies green.

6. Phase 2: MSP-backdoor shared credential (needs D2)

Sequence (this is the highest-consequence single credential):

  1. Identify the exact shared admin credential and every client system / vendor portal currently using it (inventory from scripts repo + onboarding records).
  2. Produce a per-portal rotation order, ordered by blast radius (most-impacted or most-exposed first), and get your sign-off on the order.
  3. Vaultwarden-before-changes: confirm the replacement credential is generated and vaulted before touching any live system.
  4. Rotate one portal at a time: update the portal, verify login with the new credential, update any dependent automation/env, then move to the next.
  5. Remove the hardcoded password from the private scripts repo and replace it with a Vaultwarden lookup or a [REDACTED] placeholder.
  6. Log every portal change in change-log.md with rollback.

7. Phase 3: server root passwords and service tokens (lower risk)

  • Rotate app1/app2/app3 root passwords; store in Vaultwarden; update the one place that currently references them in plaintext (app1-bu .env).
  • Rotate service tokens: Telegram bot token, Cloudflare, Netcup, SyncroMSP, Twilio. Each token rotation re-issues at the vendor console, then updates the consuming service and any env/unit file.
  • Verify each service still functions after its token rotates (send a test, poll an endpoint, etc.).

8. Phase 4: JWT secrets and DB passwords

  • Move JWT_SECRET, DEEPSEEK_API_KEY, ADMIN_AI_KEY, and Twilio creds out of rally.service, seemytrip.service, giftaroast.service into vault-backed env or a chmod 600 env file, then reload the units.
  • Rotate the app3 MySQL root password in /opt/backup-restore/snapshot.sh and /root/backup.sh; store in Vaultwarden; update the scripts to source it from a 600-mode file.
  • Verify each service/backup still runs after the change.

9. Phase 5: source hygiene (flagged separately)

  • Redact or delete the two key-inventory.md copies on Core.
  • Confirm the scripts repo MSP password removal from Phase 2 is committed and pushed.
  • Public repo itpp-infrastructure re-leak (report section 7): deferred per your earlier instruction; restating it here so it is not silently dropped. Confirm whether to keep it deferred or fold it into this plan.

10. Verification gates (plan-wide)

  • Phase 0 inventory complete and cross-referenced against Vaultwarden
  • Fallback chain verified end to end after all AI key rotations
  • Every portal login verified after MSP-backdoor rotation
  • Every service/unit verified functional after its token/JWT/DB rotation
  • change-log.md has a dated entry with rollback for every single change
  • No plaintext credential remains in any world-readable location (re-run the scan)

11. Approval needed

  • D1: AI provider key rotation go/no-go (unlocks Phase 1)
  • D2: MSP-backdoor rotation go/no-go + per-portal order (unlocks Phase 2)
  • Phases 3-5: flag individually before execution (no blanket approval implied)