- Dev Center
- Documentation
- Deployment
- diagnos-api · Docker Compose
Deployment
diagnos-api · Docker Compose
One docker compose up for OpenBao and diagnos-api: what the bootstrap does, how the token is handed over, and the staging-only caveats.
On this page
English · Português (Brasil)
One docker compose up for OpenBao + diagnos-api, wired for local development and staging. For a production
Kubernetes deployment, see ../k8s/openbao (OpenBao itself) and ../k8s (the API) instead — this compose file
trades a few production concerns (a real KMS-backed seal by default, a multi-node raft cluster) for "one command,
nothing else to run."
Quickstart#
cp .env.example .env
# edit .env: DIAGNOS_API_TOKEN, then `diagnos status` for the two ids
Generate the mTLS material into certs/ with the openssl recipe in the
REST API guide; this compose stack expects certs/clients-ca.pem,
certs/server.pem (the recipe's tls.pem) and certs/server-key.pem (its tls-key.pem).
docker compose up
First run: openbao starts sealed and uninitialised, openbao-bootstrap initialises it, unseals it (only for
OPENBAO_SEAL=shamir — every other value auto-unseals on its own), enables KV v2, writes the diagnos-sdk policy
from openbao/policy.hcl, and mints the scoped token api reads. api only starts once that bootstrap exits 0.
What the bootstrap does#
openbao/bootstrap.sh runs once as the openbao-bootstrap service (entrypoint sh /bootstrap/bootstrap.sh on the
same openbao/openbao image — no extra image to build or trust) and is idempotent across restarts: it re-checks
status every time and skips whatever is already done, using only POSIX sh plus bao/grep/sed (no jq, not
present in that image).
- Waits for
openbao:8200to answer (any status — sealed counts). bao operator init -format=jsonif not yet initialised; writes the full output (recovery/unseal keys and the root token) to theopenbao-statevolume at0600and prints a loud warning to move them out.- Unseals with the saved keys — only meaningful for
OPENBAO_SEAL=shamir, since every KMS-backed seal unseals itself as soon as the process starts. - Enables KV v2 at
secret(idempotent — a secondenablefailing with "already in use" is the success path). - Writes policy
diagnos-sdkfromopenbao/policy.hclwith__WORKSPACE_ID__/__ACCOUNT_ID__substituted from.env. - Mints an orphan, renewable token scoped to that policy and writes it to
/state/openbao-token(0600) — skipped if a token already there still passesbao token lookup.
Warning
Staging only, read this. With OPENBAO_SEAL=shamir (the default), step 3 only works because step 2 kept the
unseal keys sitting in the openbao-state volume, unencrypted. That is a deliberate convenience for a disposable
environment — it means anyone with access to that Docker volume can unseal OpenBao and read every saved session,
no OpenBao credential required. Do not run this configuration anywhere that matters; set OPENBAO_SEAL to
aws/gcp/azure/transit instead (.env.example has the credentials each one needs) or unseal by hand and
keep the recovery keys off this machine entirely.
OPENBAO_TOKEN_FILE#
The api service never sees the OpenBao token as an environment value: openbao-bootstrap writes it to
/state/openbao-token (0600, owned by the API's uid 10001) and the SDK reads that path itself —
diagnos.Settings.from_env() honours OPENBAO_TOKEN_FILE whenever OPENBAO_TOKEN is unset. Nothing in this stack
ever puts the token in docker inspect output or a process environment.
Tearing down#
docker compose down # keeps openbao-data/openbao-state
docker compose down -v # destroys them — see the volumes' warnings in docker-compose.yml