Secrets Management
Owner: Ops / Backend Lead Last Edited: April 2, 2026 Last Reviewed: April 2, 2026
1. Principles
- No secret ever lives in the repo.
.envfiles are gitignored..env.examplecontains only placeholders. - All secrets are managed in Infisical as the single source of truth.
- Infisical syncs secrets to deployment platforms (Render, Cloudflare Pages) via native integrations. Secrets are never manually edited in platform dashboards.
VITE_*frontend variables are public by nature — never put secrets there.- Break-glass access (emergency direct DB credentials, etc.) must be documented, audited, and rotated after use.
2. Infisical Organisation
Environments
| Environment | Status | Purpose | Syncs to |
|---|---|---|---|
prod | Active | Production secrets | Render (backend), Cloudflare Pages (frontend) |
preview | Deferred | QA / preview branch builds | Will sync to preview deployment platform when branch-based QA is needed |
dev | Deferred | Local development | Will use infisical run --env=dev CLI injection when local .env elimination is prioritized |
Folder Structure
/backend/ → Go backend secrets (synced to Render)
/frontend/ → Frontend secrets + config (synced to Cloudflare Pages)
/ops/ → Monitoring / alerting secrets (deferred — migrate when monitoring stack is productionised)
3. Secret Inventory
Backend (/backend/ → Render)
| Secret | Owner | Sensitive? | Rotation cadence |
|---|---|---|---|
DATABASE_URL | Backend Lead | Yes (embedded password) | 90 days or on compromise. Auto-rotation planned when DB migrated off Supabase |
REDIS_URL | Backend Lead | Yes (embedded password) | 90 days or on compromise |
CLERK_SECRET_KEY | Backend Lead | Yes | On staff change or compromise |
CLERK_ISSUER | Backend Lead | No | On Clerk tenant change |
CLERK_JWKS_URL | Backend Lead | No | On Clerk tenant change |
SENTRY_DSN | Backend Lead | No | — |
SENTRY_RELEASE | Backend Lead | No | — |
ALLOWED_ORIGINS | Backend Lead | No | — |
ENV | Backend Lead | No | — |
LOG_LEVEL | Backend Lead | No | — |
RATE_LIMIT_BURST | Backend Lead | No | — |
RATE_LIMIT_PER_SECOND | Backend Lead | No | — |
STRICT_CLERK_SCOPES | Backend Lead | No | — |
Frontend (/frontend/ → Cloudflare Pages)
| Secret | Owner | Sensitive? | Rotation cadence |
|---|---|---|---|
CLERK_SECRET_KEY | Backend Lead | Yes | On staff change or compromise. Used by Cloudflare Pages Function (/__clerk proxy) |
SENTRY_AUTH_TOKEN | Backend Lead | Yes | On compromise |
SENTRY_ORG | Backend Lead | No | — |
SENTRY_PROJECT_FRONTEND | Backend Lead | No | — |
VITE_API_BASE_URL | Backend Lead | No | — |
VITE_CLERK_PROXY_URL | Backend Lead | No | — |
VITE_CLERK_PUBLISHABLE_KEY | Backend Lead | No | — |
VITE_SENTRY_DSN | Backend Lead | No | — |
Note:
GIT_SHAis computed at build time by Cloudflare ($(git rev-parse --short HEAD)) and is not managed in Infisical.
Other Secrets (not yet in Infisical)
| Secret | Owner | Current location | Migration plan |
|---|---|---|---|
| Slack webhook URLs | Ops | go-backend/ops/.env (local only) | Move to Infisical /ops/ when monitoring stack is productionised |
GRAFANA_ADMIN_PASSWORD | Ops | go-backend/ops/.env (local only) | Move to Infisical /ops/ when monitoring stack is productionised |
METRICS_SCRAPE_TOKEN | Ops | Not currently set in prod | Add to Infisical /backend/ when Prometheus scraping is enabled |
READY_CHECK_TOKEN | Ops | Not currently set in prod | Add to Infisical /backend/ when LB health check auth is enabled |
| Cloudflare Tunnel token | Ops | Cloudflare dashboard | Consider moving to Infisical |
| GitHub Actions secrets | Backend Lead | GitHub repo/org secrets | Keep in GitHub — Infisical GitHub integration available if needed |
| Prism API keys (per-org) | Per-org admin | Database (api_keys table, hashed) | N/A — application-managed |
4. Rotation Playbooks
4.1 General Process (Infisical-managed secrets)
All secrets managed by Infisical follow this process:
- Rotate the credential in the upstream service (Supabase, Clerk, Sentry, Redis provider, etc.).
- Update the secret value in Infisical (prod environment, appropriate folder).
- Infisical automatically syncs the new value to Render / Cloudflare Pages.
- Redeploy the affected service to pick up the new value.
- Verify the service is healthy (
/readyfor backend, auth flow for frontend). - Infisical's version history serves as the rotation log.
4.2 Database credentials (DATABASE_URL)
- Rotate password in Supabase dashboard (or new DB provider when migrated).
- Update
DATABASE_URLin Infisical →/backend/→prod. - Infisical syncs to Render.
- Redeploy API on Render. Verify
/readyreturns 200. - Future: Auto-rotation will be configured when the database is migrated off Supabase to a provider that supports direct Postgres access.
4.3 Clerk (CLERK_SECRET_KEY)
- Generate a new secret key in Clerk dashboard → API Keys.
- Update
CLERK_SECRET_KEYin Infisical →/backend/→prodAND/frontend/→prod. - Infisical syncs to Render and Cloudflare Pages.
- Redeploy both services.
- Verify auth flows work end-to-end (login, JWT validation,
/__clerkproxy). - Revoke the old key in Clerk dashboard.
4.4 Redis credentials (REDIS_URL)
- Rotate password in managed Redis console.
- Update
REDIS_URLin Infisical →/backend/→prod. - Infisical syncs to Render.
- Redeploy API. Verify
/readyreturns 200.
4.5 Sentry auth token (SENTRY_AUTH_TOKEN)
- Generate a new auth token in Sentry → Settings → Auth Tokens.
- Update
SENTRY_AUTH_TOKENin Infisical →/frontend/→prod. - Infisical syncs to Cloudflare Pages.
- Next frontend build will use the new token for source map uploads.
4.6 Slack webhooks (local ops only — not yet in Infisical)
- Go to Slack workspace → Apps → Incoming Webhooks → Revoke old URL.
- Generate a new webhook URL.
- Update in
go-backend/ops/.env(or Infisical/ops/once migrated). - Restart Alertmanager:
cd go-backend/ops docker compose up -d alertmanager docker compose logs --tail=50 alertmanager - Trigger a test alert to confirm delivery.
4.7 Prism API keys (per-org, in-app)
- Revoke the key via admin API:
DELETE /api/v1/api-keys/{id}(requiresapi_keys:managescope). - Issue a new key via:
POST /api/v1/api-keyswith the required scopes and expiry. - Distribute the new key to the service that uses it.
- Confirm the old key returns 401.
5. Secret Scanning
GitHub secret scanning and push protection are configured for this repo (see .github/secret_scanning.yml). Push protection blocks commits containing known secret patterns before they land.
If a secret is detected in a scan alert:
- Treat it as compromised — rotate immediately using the playbook above.
- Remove it from git history using
git filter-repoor GitHub's "Remove secret" flow. - Audit access logs for the affected service for the window it was exposed.
- Record the incident.
6. Rotation Log
Rotation evidence is now tracked in Infisical's version history per secret. Each update records:
- Timestamp
- Who made the change
- Previous and new value (encrypted)
For auditing purposes, Infisical's audit log serves as the authoritative rotation record.
7. Future Work
- Dev environment: Set up Infisical
devenvironment with separate Supabase project (or local Postgres). Useinfisical run --env=devfor local development to eliminate.envfiles on disk. - Preview environment: Set up Infisical
previewenvironment for QA branch builds with isolated database. - DB auto-rotation: Configure Infisical native Postgres rotation when database is migrated off Supabase.
- Ops secrets: Migrate Slack webhooks, Grafana password, and metrics tokens to Infisical
/ops/when monitoring stack is productionised. - MAPBOX_TOKEN: Add to Infisical
/backend/when routing feature is enabled.
8. Related Docs
go-backend/.env.example— canonical env var reference with placeholder valuesdocs/ops/production-runbook.md— deploy and restart proceduresdocs/security/incident-response.md— what to do if a secret is confirmed compromiseddocs/ops/go-backend-runbook.md— Slack/Alertmanager restart steps