gabriel / musehub public
07-secrets-and-config.md markdown
47 lines 4.9 KB
Raw
sha256:7d5985ef251de9f0154f9b185a75cf36174bf73e0c34f5eca133e7bd20224bf4 Merge branch 'feat/opengraph-repo-cards' into dev Human 22 days ago

Section 7 — Secrets and Application Configuration

Companion to musehub-production-readiness-checklist.md.

Full secrets inventory (corrected, see docs/infrastructure.md)

Secret Purpose Where it lives today
DB_PASSWORD Postgres auth Hand-provisioned .env, per instance
WEBHOOK_SECRET_KEY Fernet key for webhook signing Hand-provisioned .env; also in SSM (/musehub/staging/)
RUNNER_TOKEN musehub-runner CI auth Hand-provisioned .env
BLOB_STORAGE_ACCESS_KEY_ID / _SECRET_ACCESS_KEY Cloudflare R2 API credentials Hand-provisioned .env
WORKER_INTERNAL_KEY Cloudflare Worker → MuseHub callback shared secret Hand-provisioned .env; also in SSM
PACK_WORKER_URL Public URL of the mpack-receiver Worker In SSM only (non-secret config, stored as SecureString anyway)

No OAuth client secrets, no payment provider keys, no email provider keys — none of those integrations exist (Section 0).

Checklist assessment

  • [x] Inventory all secrets. — done, above.
  • [x] Remove secrets from source control and repository history. — confirmed via grep, no secrets committed; .env is never tracked.
  • [ ] Store secrets in AWS Secrets Manager or SSM Parameter Store as appropriate. — partially drafted, not live. deploy/secrets.sh implements this correctly but only 3 of 7 required parameters actually exist in SSM, and the script would fail its own preflight check against the current live state. This is the actual work item for this section.
  • [ ] Encrypt secrets with KMS. — the 3 SSM params that do exist are SecureString (KMS-encrypted by default); the rest aren't in SSM at all yet.
  • [x] Use separate staging and production secrets. — confirmed: separate .env per instance, separate R2 buckets (musehub-staging/musehub-prod), separate SSM path prefixes (/musehub/<env>/).
  • [ ] Give workloads access only to the secrets they require. — the app reads its own .env wholesale; no per-secret access scoping exists (nor would it, for a single-process app on one instance) — likely N/A given the architecture, but flagging rather than assuming.
  • [x] Do not expose production secrets to pull-request workflows. — N/A, no GitHub Actions/PR workflows exist; MuseHub-native CI (Section 9) doesn't exist yet either, so there's nothing to expose secrets to yet.
  • [ ] Do not print secrets in logs. — not verified in this pass; would need a log-content review once Section 12's centralized logging exists (currently no logs are collected at all, so nothing to audit yet).
  • [ ] Configure secret rotation where supported. — not done.
  • [ ] Rotate credentials during the production launch. — not done; deferred to Section 18 (Cutover Plan).
  • [ ] Document emergency rotation procedures. — not done.
  • [x] Separate secrets from nonsecret configuration. — musehub/config.py's Settings class clearly separates secret fields (db_password, blob_storage_secret_access_key, etc.) from operational config (rate limits, quotas, timeouts) — this is already well-structured in code, even though the deployment-time delivery mechanism (hand-provisioned .env) isn't hardened yet.
  • [x] Validate required configuration at application startup. — pydantic_settings.BaseSettings does this by construction; missing required fields fail at import/startup, not at first use.
  • [x] Fail safely when critical configuration is missing. — same mechanism; also deploy/secrets.sh's own preflight check (die on missing DB_PASSWORD) is a fail-safe for the SSM path specifically, once that path is actually used.
  • [x] Remove default credentials and sample keys. — no default/sample secrets found in config.py (secret fields default to None, not placeholder values); the backup script's weak-password check (musehub, changeme123, etc.) in secrets.sh is a good sign of intent here even though that script isn't live yet.
  • [ ] Audit OAuth callback URLs and API allowlists for production. — N/A, no OAuth exists (Section 0).
  • [ ] Audit every external webhook secret. — WORKER_INTERNAL_KEY is the one webhook-adjacent secret (Cloudflare Worker callback); not independently audited in this pass — needs a closer look at how musehub/worker.py validates it.
  • [ ] Document ownership and rotation frequency for every production secret. — not done; blocked on Section 1's ownership-recording work generally.

The actual work item here

Wire deploy/secrets.sh in for real: populate the missing SSM parameters (DB_PASSWORD, BLOB_STORAGE_ACCESS_KEY_ID, BLOB_STORAGE_SECRET_ACCESS_KEY, RUNNER_TOKEN) for staging, run secrets.sh against staging to prove the pipeline actually works end-to-end, then decide (per Section 0's open item) whether production adopts this from its very first deploy rather than repeating staging's hand-provisioning. This is real infrastructure work, correctly deferred to the build phase per the doc-first workflow.

File History 1 commit
sha256:be1b2fdf6ab1fc652b3b35a945d0277a36fbf5d96e63692020d36cd7ebe03534 Merge 'docs/security-monitoring-verified' into 'dev' — prop… Human 2 days ago