config.hcl shipped `ui = false`, so there was no UI to reach even with working connectivity. That forces init and unseal through `docker compose exec`, which puts the unseal keys and root token into a server shell's history and scrollback -- the one place they should never be. Make it a substitution point driven by OPENBAO_UI, default on. This adds no exposure: the UI is served on the same listener, and anything that can reach :8200 can already do everything through the API. What it changes is where the unseal material is displayed -- the operator's browser instead of the host. Rendering config.hcl rather than copying it needed three things to be right: - Precedence. OPENBAO_UI passed to a run wins; otherwise the value .env already deploys applies; otherwise the default. Without that, `OPENBAO_UI=0 bash deploy.sh` against an existing node would report success and change nothing. Env-presence is captured before the ":=" default, so an explicit 0 is distinguishable from "not mentioned" and a re-run cannot silently re-enable the UI. A value passed this run is written back to .env. - Reload. A bind-mounted file's CONTENTS are not part of the compose config hash, so `up -d` leaves a changed config.hcl unloaded -- the same trap fixed in copyparty (76d2a09) and simplex (0f22735). Restart only on an actual change, and say loudly that a restart RE-SEALS the vault, because that is not a free action on a running one. - `cmp -s` stays inside an `if` condition; as `cmp -s A B && CONFIG_CHANGED=1` it would trip set -e whenever the files matched. Verified: default renders `ui = true` and seeds .env; an identical re-run reports no change; .env's 0 is honoured when nothing is passed; a passed 1 beats .env's 0 and is written through; a non-boolean value dies. Note for LAN-isolated hosts: the listener publishes on OPENBAO_BIND only, so a browser on another subnet still cannot reach it. The generated cert already carries DNS:localhost + IP:127.0.0.1 in its SANs, so `ssh -L 8200:<bind-addr>:8200` and https://localhost:8200 works against the existing cert without widening the publish. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
57 lines
2.6 KiB
HCL
57 lines
2.6 KiB
HCL
# OpenBao — hardened, same-LAN tape-encryption key store for Kanrisha.
|
|
#
|
|
# Native TLS on the listener (no reverse proxy in front), integrated raft
|
|
# storage (clean snapshot-based DR), and mlock enabled. This vault is the SOLE
|
|
# recovery path for encrypted tapes — losing the OpenBao data AND the unseal
|
|
# material loses every encrypted tape. Back it up (raft snapshots) and store the
|
|
# unseal keys/root token out of band (see the README + DR runbook).
|
|
|
|
storage "raft" {
|
|
path = "/openbao/data"
|
|
node_id = "openbao-1"
|
|
}
|
|
|
|
# TLS-terminating listener. tls.crt/tls.key are self-signed by deploy.sh on first
|
|
# run, or a CA-signed pair you drop in ./tls (e.g. issued by your Smallstep CA
|
|
# over ACME — see the README). The Kanrisha daemon trusts this via
|
|
# [encryption.openbao].ca_cert.
|
|
listener "tcp" {
|
|
address = "0.0.0.0:8200"
|
|
tls_cert_file = "/openbao/tls/tls.crt"
|
|
tls_key_file = "/openbao/tls/tls.key"
|
|
# Optional mTLS — require + verify a client cert from the tape host:
|
|
# tls_require_and_verify_client_cert = true
|
|
# tls_client_ca_file = "/openbao/tls/client-ca.crt"
|
|
}
|
|
|
|
# mlock keeps key material off swap — REQUIRED. Needs cap_add: [IPC_LOCK] +
|
|
# ulimits memlock unlimited (docker-compose.yml) and swap disabled on the host.
|
|
# Do NOT add `disable_mlock = true`.
|
|
|
|
# Single-node raft: advertising 127.0.0.1 is fine because a lone node is always
|
|
# ACTIVE and never redirects clients (they connect straight to the LAN address).
|
|
# For HA / multiple nodes, set BAO_API_ADDR + BAO_CLUSTER_ADDR to each node's
|
|
# reachable LAN address in the compose env instead.
|
|
api_addr = "https://127.0.0.1:8200"
|
|
cluster_addr = "https://127.0.0.1:8201"
|
|
# The built-in web UI. Substituted by deploy.sh from OPENBAO_UI. It adds NO new
|
|
# exposure: it is served on this same listener, and anything reachable on :8200
|
|
# can already do everything through the API. Turning it on is what lets an
|
|
# operator initialise/unseal and log in from a browser, so the unseal keys are
|
|
# shown in the browser instead of a server shell's scrollback.
|
|
ui = @UI@
|
|
|
|
# ── Auto-unseal (optional) — DEFAULT IS MANUAL UNSEAL ────────────────────────
|
|
# With no seal stanza OpenBao starts SEALED and needs `bao operator unseal` (x3)
|
|
# after every restart. To auto-unseal against a PKCS#11 HSM/token, uncomment and
|
|
# fill this in, mount the PKCS#11 module + device into the container, and set
|
|
# OPENBAO_HSM_PIN in .env:
|
|
#
|
|
# seal "pkcs11" {
|
|
# lib = "/usr/lib/softhsm/libsofthsm2.so"
|
|
# slot = "0"
|
|
# pin = "env://BAO_HSM_PIN"
|
|
# key_label = "kanrisha-unseal"
|
|
# mechanism = "0x1087" # CKM_AES_GCM
|
|
# }
|