Files
config-public/server/app/openbao/docker-compose.yml
T
Lucas WintherandClaude Opus 5.5 665ac7d52f Render stack secrets from OpenBao in compose_stack
stack_secrets reads KV v2 on the target host and writes the stack's .env at
0600, failing loudly on a sealed vault, a bad token, a missing field or an
unsafe value. Adds an example OpenBao stack on app and moves webapp onto it;
metrics keeps a hand-placed .env.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 15:15:04 +02:00

56 lines
2.8 KiB
YAML

# OpenBao: the secret store every other stack with a credential reads from.
#
# Loopback only. It is published to 127.0.0.1 on the host, is not on proxy-net,
# and sets no VIRTUAL_HOST and no LETSENCRYPT_HOST, so nothing outside the host
# can reach it. That is the whole reason the compose_stack role does its vault
# read from the host rather than from the control node. See docs/secrets.md.
services:
openbao:
container_name: openbao
# Pinned, per server/README.md — and more firmly than most: a restart seals
# the vault and needs a manual unseal afterwards, so moving this tag is a
# deliberate maintenance window rather than a routine update.
image: docker.io/openbao/openbao:2.6.2
restart: unless-stopped
ports:
# The bind address matters more than the port. Without the 127.0.0.1 the
# secret store is on every interface the host has.
- "127.0.0.1:8200:8200"
# The image's default command is `server -dev`, which starts an in-memory
# vault with a known root token. Override it — but with the subcommand
# alone: the entrypoint script already appends `-config=/openbao/config`
# whenever the first argument is `server`, so passing that flag again here
# loads the directory twice and OpenBao tries to bind the listener twice,
# failing with "address already in use".
command: server
volumes:
- ./config:/openbao/config:ro
- ./data:/openbao/file
environment:
# The bao CLI defaults to https://127.0.0.1:8200, but this listener has
# TLS disabled (openbao.hcl sets tls_disable = true), so every
# `docker exec ... bao ...` would otherwise fail with a TLS handshake
# error. Set here so every exec'd command inherits it without needing
# its own -e BAO_ADDR. See docs/secrets.md.
BAO_ADDR: http://127.0.0.1:8200
# ./config is mounted read-only, but the entrypoint's chown of
# /openbao/config runs on every start whenever its uid does not match
# openbao's, which it never will here since the payload is synced as
# the deploy user — and that chown would fail against a read-only
# mount anyway. The config chown is echo-guarded, but the entrypoint's
# matching chowns of /openbao/logs and /openbao/file are not, and the
# script runs under `set -e` as uid 100: an un-runnable-as-non-root
# chown there would exit the container rather than just log noise. This
# stack survives today only because openbao.yml's stack_dirs hands
# data/ to 100:1000 before first start, so the stat short-circuits
# every chown — SKIP_CHOWN makes that not load-bearing.
SKIP_CHOWN: "true"
# mlock, so the unsealed keyring is never paged out to disk.
cap_add:
- IPC_LOCK
logging:
driver: "json-file"
options:
max-size: "1m"
max-file: "1"