Rotate Atlas secrets
Rotate Atlas secrets
Section titled “Rotate Atlas secrets”Atlas reads every credential at process start. Rotation therefore reduces to:
update the secret in its source of truth, point the env var or mounted file
at the new value, and restart the affected service. The audit found live
credentials in /opt/atlas/.env on disk; this runbook is the canonical way
to change them without leaking the old value into a log or a git commit.
Pre-flight
Section titled “Pre-flight”.envis gitignored (/.env*in.gitignore). Never commit a real.env.- The repository checks out only
.env.example. If you ever need to copy a credential into the repo, copy into.env, never the example. make doctorshould be green before and after every rotation.
Database password (ATLAS_DB_DSN)
Section titled “Database password (ATLAS_DB_DSN)”- Rotate in PgBouncer / Postgres:
ALTER USER atlas WITH PASSWORD '<new>'; - Update
ATLAS_DB_DSNin.env(or in the orchestrator’s secret store). make ship-services— every Go service is restarted;pgxpoolreconnects.- Verify
/readyzreturnspostgres: ok.
DJED AI gateway virtual key (DJED_AI_API_KEY) — preferred path
Section titled “DJED AI gateway virtual key (DJED_AI_API_KEY) — preferred path”Atlas defaults to gateway mode: the planner talks to djed-litellm
through one OpenAI-compatible client and the gateway owns provider
routing, fallbacks, retries, cache, and per-cell virtual keys. Atlas’s
key is minted by the DJED provisioner; rotating it never touches an
upstream provider key.
- Mint a fresh cell virtual key:
Terminal window djed-provisioner ai mint --cell atlas# or, on the DJED host:/opt/djed/scripts/cell-provision.sh ai --cell atlas - Replace
DJED_AI_API_KEYin.envwith the new value. make ship-planner(andmake ship-servicesso the gateway picks up the new key for the/readyzAI dependency).- Verify
/readyzreturnsopenrouter: gateway mode (no recent failure)and the next/answer/streamrequest emits a real LLM answer instead of the baseline fallback. - Revoke the old virtual key:
Terminal window djed-provisioner ai revoke --cell atlas --key <old>
Mode check.
curl -fsS http://127.0.0.1:58104/api/atlas/planner/llm-statusincludes"mode": "gateway"whenDJED_AI_BASE_URLis set; legacy direct-OpenRouter mode reads"mode": "legacy".
OpenRouter API key (OPENROUTER_API_KEY) — legacy fallback
Section titled “OpenRouter API key (OPENROUTER_API_KEY) — legacy fallback”Used only when DJED_AI_BASE_URL is unset (the planner emits a
deprecation warning the first time it falls back). Prefer migrating to
the gateway mode above.
- Mint a new key at openrouter.ai.
- Replace the value in
.env(and Zitadel-managed secret if you push to it). make ship-plannerandmake ship-services(the gateway reads the key for clean-core readiness reporting).- Verify
/readyzreturnsopenrouter: legacy mode (no recent failure)and the next/answer/streamrequest emits a real LLM answer rather than the baseline fallback. - Revoke the old key.
BFF session secret (ATLAS_BFF_SESSION_SECRET)
Section titled “BFF session secret (ATLAS_BFF_SESSION_SECRET)”Rotating this signs everyone out — schedule accordingly.
- Generate a new value:
openssl rand -hex 32. - Replace
ATLAS_BFF_SESSION_SECRETin.env. make ship-services. Existingatlas_sessioncookies fail signature verification and clients fall back to the OIDC code flow.
BFF client secret (ATLAS_BFF_CLIENT_SECRET)
Section titled “BFF client secret (ATLAS_BFF_CLIENT_SECRET)”- Rotate in Zitadel for the Atlas web app application.
- Replace
ATLAS_BFF_CLIENT_SECRETin.env. make ship-services. Verify/api/auth/sessionfor an authenticated browser still returns 200.
Zitadel machine key (KEYSTONE_MACHINE_KEY_FILE)
Section titled “Zitadel machine key (KEYSTONE_MACHINE_KEY_FILE)”- Mint a new machine key in Zitadel for the
atlas-graphsyncservice user. - Replace the file at
/opt/djed/config/zitadel-keys/atlas-graphsync.key.jsonatomically (mvthe new file over the old). make ship-servicesforatlas-gateway,atlas-graphsync,atlas-resolver.- Verify
make ship-ontologysucceeds (still requires the ACL grant — see grant-ontology-acl).
Redis password (ATLAS_REDIS_URL)
Section titled “Redis password (ATLAS_REDIS_URL)”- Rotate in Redis (
CONFIG SET requirepass <new>thenCONFIG REWRITE). - Update
ATLAS_REDIS_URLin.env(the URL form already includes auth). make ship-servicesto restart the gateway. BFF sessions are stored in Redis db=6 and survive a Redis password rotation as long as the new URL reaches the same db.
Pre-commit guard
Section titled “Pre-commit guard”Add the following hook (or wire into your existing pre-commit framework) so
nothing under .env* (other than the example) can ever land in a commit:
#!/usr/bin/env bashif git diff --cached --name-only | grep -E '^\.env($|\.[^e])' > /dev/null; then echo "Refusing to commit .env files. Use .env.example for template values." exit 1fichmod +x .git/hooks/pre-commit to enable. CI should run the same regex
against the diff for completeness.