fix(openbao): sanity-audit fixes — 4 blockers + hardening

A multi-agent sanity audit of the freshly-merged deployment found four
end-to-end blockers (and several smaller issues); all fixed here.

HIGH (were blocking):
- deploy.sh never called install_docker(), so `docker compose pull` hit
  command-not-found on any host without Docker. Now called before the
  compose steps.
- The container's server process runs as the image's own (often non-root)
  user but the mounted config/TLS were root-owned 0640/0600 and the raft
  volume root-owned -> vault crash-looped, never binding :8200. deploy.sh
  now detects the image UID after pull and aligns ownership of config.hcl,
  ./tls and the data volume (a no-op when the image runs as root);
  config.hcl is installed 0644 (holds no secrets).
- Docs told operators to set the daemon key `openbao_ca_cert`, but the
  Kanrisha daemon's key is `ca_cert` (config.go, mapstructure:"ca_cert").
  The wrong key is fatal on strict unmarshal / leaves TLS unverified.
  Renamed in all 5 places (config.hcl, gen-tls.sh, deploy.sh x2, README).
- DR backup used `docker compose cp openbao:… -`, which emits a TAR stream,
  so the age-encrypted snapshot was tar-wrapped and would not restore.
  Switched to `docker compose exec -T openbao cat` for the raw bytes, wrote
  the snapshot to a scratch path (not the live raft dir), and documented the
  matching restore.

MEDIUM:
- Swap detection used `swapon --show` (absent on BusyBox) and `\s` (GNU-only)
  -> silently no-op on Alpine, leaving swap on. Now uses /proc/swaps and
  [[:space:]] so mlock hardening actually holds on musl.
- A Docker-published port bypasses the host INPUT firewall, so the source
  rule was illusory. deploy.sh now narrows OPENBAO_BIND to OPENBAO_ADDR when
  it is an IP, the compose/README/.env comments state the reality, and a new
  Exposure section + an init-immediately warning were added.
- Fixed broken ../kanrisha/ and deployments/kanrisha/ links (separate repo).

LOW:
- OPENBAO_TLS_SANS is now honored (folded into the SAN list from the env).
- .gitignore excludes *.snap / *.snap.age.
- Bootstrap note clarifies bootstrap.sh needs the `bao` CLI (run it from the
  Kanrisha host/workstation, not this Docker-only vault host).
- README multi-OS count corrected (eight stacks) + automations.sh header
  lists openbao.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-08 19:11:37 -05:00
parent 2efc9dbffb
commit 0812f345a8
9 changed files with 216 additions and 112 deletions
+3 -3
View File
@@ -110,7 +110,7 @@ deployments/<name>/ # one folder per stack
| [`squid`](deployments/squid/) | SSL-bump caching forward proxy — static-content cache + TLS interception via a local CA. **The exception: a forward proxy, not a Caddy/LE site.** | — |
| [`copyparty`](deployments/copyparty/) | Portable file server — web UI/WebDAV behind Caddy, plus direct **SFTP** + **FTPS**. Ships a security-notices-aware updater. | — |
| [`simplex`](deployments/simplex/) | SimpleX SMP + XFTP relay with Tor hidden services + encrypted backups. | globals/age-pubkey.txt |
| [`openbao`](deployments/openbao/) | Hardened tape-encryption key store for [Kanrisha](deployments/kanrisha/). **Exception: native TLS on the LAN, no Caddy/LE.** raft storage, mlock, self-signed or Smallstep-ACME cert, manual/HSM unseal. | globals/age-pubkey.txt (backups) |
| [`openbao`](deployments/openbao/) | Hardened tape-encryption key store for **Kanrisha** (the LTO tape-archive system — separate repo/host). **Exception: native TLS on the LAN, no Caddy/LE.** raft storage, mlock, self-signed or Smallstep-ACME cert, manual/HSM unseal. | globals/age-pubkey.txt (backups) |
## Conventions
@@ -145,8 +145,8 @@ instance user-data, and the host configures itself on first boot.
## Multi-OS notes
The host-provisioning scripts (`setup-host`, `harden-ssh`, `harden-jumphost`,
`sshuser`) and the six Docker stacks (pocket-id, beszel, headscale, webfinger,
squid, copyparty) run on Alpine, Debian, and Alma. Distro differences live in
`sshuser`) and the eight Docker stacks (pocket-id, beszel, headscale, webfinger,
squid, copyparty, simplex, openbao) run on Alpine, Debian, and Alma. Distro differences live in
[`scripts/oslib.sh`](scripts/oslib.sh) — package manager (`apk`/`apt`/`dnf`),
init system (OpenRC/systemd), sshd service name, the per-distro `sftp-server`
path, hostname, boot hooks, and the sshguard log source/backend.
+2 -2
View File
@@ -14,8 +14,8 @@
# It opens a Gum wizard (auto-installed) that lets you:
# • Mode: deploy on THIS host, or build deploy.sh artifacts locally.
# • Pick any deployment (pocket-id, beszel, headscale, webfinger, squid,
# copyparty, simplex) or any generic script (harden-ssh, harden-jumphost,
# sshuser, auto-update).
# copyparty, simplex, openbao) or any generic script (setup-host, harden-ssh,
# harden-jumphost, sshuser, auto-update).
# Shared defaults come from globals/ (see globals/README.md).
#
# Non-interactive: set SKIP_PROMPTS=1 plus the needed vars and pipe the menu
+12 -7
View File
@@ -8,16 +8,21 @@
# [encryption.openbao].address at (https://${OPENBAO_ADDR}:8200).
OPENBAO_ADDR=10.0.0.10
# Interface the published API port binds to on the host. Default is all
# interfaces; set the LAN IP to avoid listening anywhere else.
# Interface the published API port binds to on the host. Leave blank/all and
# deploy.sh narrows it to OPENBAO_ADDR when that is an IP; set it explicitly to
# pin a specific LAN IP. (A published port bypasses the host INPUT firewall — see
# the README — so this bind is the main interface restriction.)
OPENBAO_BIND=0.0.0.0
# ─── TLS ────────────────────────────────────────────────────────────────────
# Comma-separated SANs for the self-signed cert deploy.sh generates. Include
# EVERY name/IP the tape host might use (deploy.sh appends OPENBAO_ADDR + the
# loopback for you). To use a CA-signed cert instead (e.g. Smallstep over ACME),
# drop tls.crt + tls.key into ./tls and these are ignored — see the README.
OPENBAO_TLS_SANS=DNS:localhost,IP:127.0.0.1
# EXTRA SANs for the self-signed cert, beyond OPENBAO_ADDR + loopback (which
# deploy.sh always includes). This is read from the ENVIRONMENT at deploy time,
# so to add names export it before running deploy.sh, e.g.
# OPENBAO_TLS_SANS=DNS:vault.lan,IP:10.0.0.11 bash deploy.sh
# (deploy.sh records the final SAN list back into this .env for reference.) To
# use a CA-signed cert instead (e.g. Smallstep over ACME), drop tls.crt + tls.key
# into ./tls and this is ignored — see the README.
OPENBAO_TLS_SANS=
OPENBAO_TLS_DAYS=825
# ─── Image tag ──────────────────────────────────────────────────────────────
+4 -1
View File
@@ -1,3 +1,6 @@
# Never commit generated TLS material (the listener key) or a populated .env.
# Never commit generated TLS material (the listener key), a populated .env, or
# raft snapshot backups (they contain vault data).
/tls/
.env
*.snap
*.snap.age
+56 -20
View File
@@ -1,9 +1,10 @@
# openbao
Hardened [OpenBao](https://openbao.org) — the tape-encryption key store for
[Kanrisha](../kanrisha/). Deliberately **separate from the tape host**: a
compromise of the tape node must not reach the vault, and OpenBao's
mlock/TLS/unseal lifecycle is cleaner on its own box.
**Kanrisha** (the LTO tape-archive system; separate repo, separate host).
Deliberately **separate from the tape host**: a compromise of the tape node must
not reach the vault, and OpenBao's mlock/TLS/unseal lifecycle is cleaner on its
own box.
Unlike the other stacks here there is **no Caddy / Let's Encrypt** — a secrets
store terminates TLS itself and is reached over the **LAN**, not the public
@@ -24,8 +25,8 @@ internet.
| Variable | Notes |
|----------|-------|
| `OPENBAO_ADDR` | IP/DNS the Kanrisha tape host uses to reach this vault (goes in the cert SAN; you point the daemon at `https://$OPENBAO_ADDR:8200`). |
| `OPENBAO_BIND` | Host interface the API binds to. Default all; set the LAN IP to narrow it. |
| `OPENBAO_TLS_SANS` | Extra SANs for the self-signed cert (deploy.sh adds `OPENBAO_ADDR` + loopback). |
| `OPENBAO_BIND` | Host interface the API publishes on. Left at the default, deploy.sh narrows it to `OPENBAO_ADDR` when that is an IP (a published port bypasses the INPUT firewall, so this bind is the real restriction — see [Exposure](#exposure)). |
| `OPENBAO_TLS_SANS` | **Extra** SANs beyond `OPENBAO_ADDR` + loopback (which deploy.sh always adds). Read from the environment at deploy time — `export` it before running deploy.sh. |
| `OPENBAO_TAG` | OpenBao image tag (pin it). |
| `OPENBAO_HSM_PIN` | Only for PKCS#11 auto-unseal. Leave blank for manual unseal. |
@@ -40,8 +41,11 @@ OPENBAO_ADDR=10.0.0.10 SKIP_PROMPTS=1 bash deployments/openbao/deploy.sh
```
`deploy.sh` installs Docker, generates a self-signed TLS cert (if none present),
seeds `.env`, disables swap (for mlock), firewalls `8200/tcp`, and brings the
stack up. OpenBao starts **sealed** — initialise + unseal once:
seeds `.env`, disables swap (for mlock), narrows the API bind to the LAN IP,
opens `8200/tcp`, aligns file/volume ownership to the container's UID, and brings
the stack up. OpenBao starts **sealed** — initialise + unseal once (do this
immediately; an uninitialised vault reachable on the LAN can be init'd by anyone
who connects):
```bash
docker compose exec -e BAO_ADDR=https://127.0.0.1:8200 openbao \
@@ -57,7 +61,7 @@ your backup recipient (`globals/age-pubkey.txt`), never on this host.
- **Self-signed (default):** `deploy.sh` runs [`gen-tls.sh`](gen-tls.sh) to
create `./tls/tls.{crt,key}` with `OPENBAO_ADDR` in the SAN. Hand `tls.crt` to
the Kanrisha daemon as `[encryption.openbao].openbao_ca_cert`.
the Kanrisha daemon as `[encryption.openbao].ca_cert`.
- **Smallstep CA over ACME (option):** issue a cert from your `step-ca` and drop
it in `./tls` instead — `gen-tls.sh` then no-ops. e.g. with the `step` client:
@@ -67,7 +71,7 @@ your backup recipient (`globals/age-pubkey.txt`), never on this host.
# renew on a timer: step ca renew --daemon ./tls/tls.crt ./tls/tls.key
```
Give the Kanrisha daemon your Smallstep **root** as `openbao_ca_cert` (then it
Give the Kanrisha daemon your Smallstep **root** as `ca_cert` (then it
trusts the vault without `-tls-skip-verify`).
## Auto-unseal (optional)
@@ -79,10 +83,13 @@ device into the `openbao` service, and set `OPENBAO_HSM_PIN` in `.env`.
## Bootstrap for Kanrisha
Once unsealed, enable KV v2 + AppRole and seed the domain key with the Kanrisha
bootstrap script (from the Kanrisha repo, `deploy/openbao/bootstrap.sh`):
bootstrap script (from the Kanrisha repo, `deploy/openbao/bootstrap.sh`). It calls
the `bao` CLI directly, so run it **from a host that has `bao`** (the Kanrisha
host or your workstation) pointed at this vault — this vault host only ships
Docker. Copy `tls.crt` to that host first and pass it as `BAO_CACERT`:
```bash
BAO_ADDR=https://$OPENBAO_ADDR:8200 BAO_CACERT=./tls/tls.crt \
BAO_ADDR=https://$OPENBAO_ADDR:8200 BAO_CACERT=/path/to/openbao-ca.crt \
BAO_TOKEN=<root> bash bootstrap.sh
```
@@ -91,19 +98,48 @@ It enables the `kanrisha-tape` KV-v2 mount (with **effectively-unlimited**
policy, seeds the domain key, and prints the `[encryption.openbao]` block for the
Kanrisha config. Point the daemon at `address = "https://$OPENBAO_ADDR:8200"`.
## Exposure
This is a secrets store on the LAN, not a public service. Two things to know:
- **A Docker-published port is DNAT'd and bypasses the host `INPUT` firewall.** A
source-restricting rule on `INPUT` does **not** gate `:8200`. The real interface
restriction is the publish bind: `deploy.sh` defaults `OPENBAO_BIND` to
`OPENBAO_ADDR` when that is an IP, so the API listens only on that LAN IP. To
restrict by *source host*, use a `FORWARD`/`DOCKER-USER` rule or network
segmentation, not `INPUT`.
- **mTLS (optional):** to require the tape host to present a client cert, enable
the `tls_require_and_verify_client_cert` stanza in [`config.hcl`](config.hcl)
and issue the tape host a client cert from the same CA.
And **initialise the vault immediately** after `deploy.sh` — an uninitialised
vault reachable on the LAN can be `bao operator init`'d by anyone who connects,
handing them the root token and unseal keys.
## Backup / DR
The vault is the sole recovery path for encrypted tapes — back it up:
```bash
# Consistent raft snapshot (safe while running):
docker compose exec -e BAO_ADDR=https://127.0.0.1:8200 openbao \
bao operator raft snapshot save -tls-skip-verify /openbao/data/snapshot.snap
# then copy it off-box, age-encrypted:
docker compose cp openbao:/openbao/data/snapshot.snap - | \
age -r "$(cat ../../globals/age-pubkey.txt)" > openbao-$(date +%F).snap.age
# Consistent raft snapshot (safe while running); write it to a scratch path, NOT
# into the live raft dir:
docker compose exec openbao \
bao operator raft snapshot save -address=https://127.0.0.1:8200 -tls-skip-verify /tmp/openbao.snap
# then stream the RAW file off-box, age-encrypted. Use `exec -T ... cat`, not
# `compose cp openbao:… -` (which emits a TAR wrapper that won't restore):
docker compose exec -T openbao cat /tmp/openbao.snap | \
age -r "$(cat /path/to/globals/age-pubkey.txt)" > "openbao-$(date +%F).snap.age"
```
Restore: `bao operator raft snapshot restore`. Snapshots do **not** contain the
unseal keys — you still need those (and the root token) to unseal a restored
vault, which is why they are stored separately.
Restore (into a fresh, unsealed vault): decrypt, copy the raw `.snap` in, and
apply it:
```bash
age -d -i ~/.age/key.txt openbao-DATE.snap.age > openbao.snap
docker compose cp openbao.snap openbao:/tmp/openbao.snap
docker compose exec openbao \
bao operator raft snapshot restore -address=https://127.0.0.1:8200 -tls-skip-verify /tmp/openbao.snap
```
Snapshots do **not** contain the unseal keys or root token — you still need
those to unseal a restored vault, which is why they are stored separately.
+1 -1
View File
@@ -14,7 +14,7 @@ storage "raft" {
# 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].openbao_ca_cert.
# [encryption.openbao].ca_cert.
listener "tcp" {
address = "0.0.0.0:8200"
tls_cert_file = "/openbao/tls/tls.crt"
+129 -75
View File
@@ -102,13 +102,18 @@ open_bao_port() {
disable_swap() {
[[ "$DISABLE_SWAP" == "1" ]] || { warn "DISABLE_SWAP=0 -- mlock will be best-effort."; return; }
if swapon --show 2>/dev/null | grep -q .; then
# Detect active swap via /proc/swaps (a header line + one line per device) so
# this works on musl/BusyBox too, where `swapon --show` does not exist.
if [[ -r /proc/swaps ]] && [[ "$(wc -l < /proc/swaps)" -gt 1 ]]; then
log "Disabling swap (mlock keeps key material off disk)..."
swapoff -a || warn "swapoff failed -- disable swap manually."
else
log "No active swap."
fi
# Persist: comment any swap lines in fstab so it stays off across reboots.
if [[ -f /etc/fstab ]] && grep -qE '^[^#].*\sswap\s' /etc/fstab; then
sed -i.bak -E 's|^([^#].*\sswap\s.*)$|# \1 # disabled for OpenBao mlock|' /etc/fstab
# [[:space:]] (not \s) so the match works under musl/BusyBox grep/sed.
if [[ -f /etc/fstab ]] && grep -qE '^[^#].*[[:space:]]swap[[:space:]]' /etc/fstab; then
sed -i.bak -E 's|^([^#].*[[:space:]]swap[[:space:]].*)$|# \1 # disabled for OpenBao mlock|' /etc/fstab
log "Commented swap entries in /etc/fstab (backup: /etc/fstab.bak)."
fi
}
@@ -147,13 +152,27 @@ prompt() {
prompt OPENBAO_ADDR "LAN address the Kanrisha tape host reaches this vault at (IP or DNS)"
[[ -n "$OPENBAO_ADDR" ]] || die "OPENBAO_ADDR is required."
# Build the cert SAN list: loopback + whatever OPENBAO_ADDR is (IP vs DNS).
# Build the cert SAN list: loopback + whatever OPENBAO_ADDR is (IP vs DNS) +
# any extra SANs the operator exported in OPENBAO_TLS_SANS.
ADDR_IS_IP=0
if [[ "$OPENBAO_ADDR" =~ ^[0-9.]+$ || "$OPENBAO_ADDR" == *:* ]]; then
ADDR_SAN="IP:${OPENBAO_ADDR}"
ADDR_IS_IP=1
else
ADDR_SAN="DNS:${OPENBAO_ADDR}"
fi
SANS="DNS:localhost,IP:127.0.0.1,${ADDR_SAN}"
[[ -n "${OPENBAO_TLS_SANS:-}" ]] && SANS="${SANS},${OPENBAO_TLS_SANS}"
# A Docker-published port bypasses the host INPUT firewall, so the interface bind
# is the real restriction. If the operator left OPENBAO_BIND at the all-interfaces
# default and OPENBAO_ADDR is an IP, narrow the publish to just that LAN IP.
if [[ "$OPENBAO_BIND" == "0.0.0.0" && "$ADDR_IS_IP" == "1" ]]; then
OPENBAO_BIND="$OPENBAO_ADDR"
log "Binding the API to ${OPENBAO_BIND} only (set OPENBAO_BIND to override)."
elif [[ "$OPENBAO_BIND" == "0.0.0.0" ]]; then
warn "OPENBAO_BIND=0.0.0.0 and OPENBAO_ADDR is a DNS name -- API publishes on ALL interfaces. Set OPENBAO_BIND to a LAN IP to narrow it."
fi
# ----------------------------------------------------------------------------
# Lay down the stack
@@ -161,7 +180,9 @@ SANS="DNS:localhost,IP:127.0.0.1,${ADDR_SAN}"
log "Setting up $STACK_DIR..."
install -d -m 0750 "$STACK_DIR"
install -m 0640 "$SCRIPT_DIR/docker-compose.yml" "$STACK_DIR/docker-compose.yml"
install -m 0640 "$SCRIPT_DIR/config.hcl" "$STACK_DIR/config.hcl"
# config.hcl holds no secrets and is read by the in-container server process
# (which may be a non-root user) over a read-only mount -- keep it world-readable.
install -m 0644 "$SCRIPT_DIR/config.hcl" "$STACK_DIR/config.hcl"
install -m 0750 "$SCRIPT_DIR/gen-tls.sh" "$STACK_DIR/gen-tls.sh"
ENV_FILE="$STACK_DIR/.env"
@@ -196,9 +217,29 @@ if [[ "$FORCE" != "1" ]]; then
[[ "${ans,,}" == "y" || "${ans,,}" == "yes" ]] || { warn "Aborted."; exit 0; }
fi
install_docker
cd "$STACK_DIR"
log "Pulling image..."
docker compose pull
# The OpenBao server process runs as the image's own user -- root in some image
# variants, a non-root service user in others -- and reads its config + TLS over
# read-only bind mounts and writes the raft data volume. So those must be owned by
# that UID. Detect it from the pulled image and align ownership; all of this is a
# harmless no-op when the image runs as root.
BAO_UID=$(docker compose run --rm --no-deps --entrypoint id openbao -u 2>/dev/null | tr -dc '0-9' || true)
BAO_UID=${BAO_UID:-0}
log "OpenBao container runs as UID ${BAO_UID}; aligning file/volume ownership."
chown -R "${BAO_UID}:${BAO_UID}" "$STACK_DIR/config.hcl" "$STACK_DIR/tls"
# tls.key stays private to that UID; config.hcl + tls.crt are non-secret.
chmod 0600 "$STACK_DIR/tls/tls.key" 2>/dev/null || true
# Raft data volume is created root-owned on first mount; make it writable by the
# server UID (a one-shot root container chowns the mounted volume in-place).
docker compose run --rm --no-deps --user 0:0 --entrypoint chown openbao \
-R "${BAO_UID}:${BAO_UID}" /openbao/data 2>/dev/null || \
warn "Could not pre-chown the raft data volume; if OpenBao fails to write storage, chown the openbao-data volume to UID ${BAO_UID}."
log "Starting OpenBao..."
docker compose up -d --remove-orphans
@@ -215,7 +256,11 @@ DEPLOYED (OpenBao starts SEALED -- finish setup below)
Address: https://${OPENBAO_ADDR}:8200
Stack dir: ${STACK_DIR}
TLS: ${STACK_DIR}/tls/tls.crt (give this to the Kanrisha daemon as
[encryption.openbao].openbao_ca_cert)
[encryption.openbao].ca_cert)
>> Initialise NOW: an uninitialised vault reachable on the LAN can be init'd by
anyone who connects, capturing the root token + unseal keys. Do step 1 before
walking away.
1. Initialise + unseal (ONCE). Store the unseal keys + root token OUT OF BAND:
docker compose exec -e BAO_ADDR=https://127.0.0.1:8200 openbao \\
@@ -223,18 +268,22 @@ TLS: ${STACK_DIR}/tls/tls.crt (give this to the Kanrisha daemon as
docker compose exec -e BAO_ADDR=https://127.0.0.1:8200 openbao \\
bao operator unseal -tls-skip-verify <key> # x3, three different keys
2. Bootstrap for Kanrisha (from the Kanrisha repo's deploy/openbao/bootstrap.sh):
BAO_ADDR=https://${OPENBAO_ADDR}:8200 BAO_CACERT=${STACK_DIR}/tls/tls.crt \\
2. Bootstrap for Kanrisha. Run the Kanrisha repo's deploy/openbao/bootstrap.sh
from a host that HAS the 'bao' CLI (the Kanrisha host or your workstation --
this vault host only ships Docker), pointed at this vault. Copy tls.crt there
first as the BAO_CACERT:
BAO_ADDR=https://${OPENBAO_ADDR}:8200 BAO_CACERT=/path/to/openbao-ca.crt \\
BAO_TOKEN=<root> bash bootstrap.sh
Then point the Kanrisha daemon at:
[encryption.openbao]
address = "https://${OPENBAO_ADDR}:8200"
openbao_ca_cert = "/etc/kanrisha/openbao-ca.crt" # = tls.crt above
ca_cert = "/etc/kanrisha/openbao-ca.crt" # = tls.crt above
3. Back it up (this vault is the sole recovery path for encrypted tapes):
docker compose exec -e BAO_ADDR=https://127.0.0.1:8200 openbao \\
bao operator raft snapshot save -tls-skip-verify /openbao/data/snap.snap
...copy it off-box, age-encrypted. See the README for the full DR flow.
docker compose exec openbao \\
bao operator raft snapshot save -address=https://127.0.0.1:8200 -tls-skip-verify /tmp/openbao.snap
docker compose exec -T openbao cat /tmp/openbao.snap > ${STACK_DIR}/openbao.snap
...then age-encrypt + copy it off-box. See the README for the full DR flow.
Manage:
docker compose logs -f
@@ -250,66 +299,71 @@ EOF
# __ARCHIVE_BELOW__ is the embedded tar.gz payload (base64), added by build.sh.
exit 0
__ARCHIVE_BELOW__
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
pZZaaqmlllpqqaWWWmr5/5N/AAPPvDEAUAAA
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
Oym9JwC6CAgptd9aab0Tha4Q6paSMpeYkMkVlXfH2hmyLkOxXcbr0NmC+q152GrZ1xLk3EmFUuuI
fugh2vaSJULz3g/fDOhPf6L3jzZQDmYjmSNuB2364Zu9F4b04AUJph4fn0xHdOHsHTx/XNGS/If1
RV4qhAkwF+CnARcllttIEECww1s9PjvtioEVqa0eV5Vpyd7wC0xnDknqEPqeFARY9tptlRtHikHO
w0H/f8lJ1D1blPIhKXwBUMP3WeblXozzzvxlfqeGWR7GCge5G5AAbE2/BycdHo/sd0tyzmafiNgR
zUUnFKRtJuvl9R8AOo4nRzY7wSgcXT1gMj8DpB5FxcSL1dHX71kfWaf8BVARPe/3txYtH+zvb63c
am0L76X1ksGGVEpvKJ7K6lD70Vximekh2Q3VrJP7+HAfgsezXnK9pb6rMkPYToA9/bElfykJhp8y
r3vquXPp0bvQ93936GraEzQG8q568GIkjf+qNT5b/x08X+M/xomDwcHzgwb/fYkGKJVmK/YarAmC
cCR5DBOXTEWlyvizkK9UyLBlJrkpIiWiQBStuAaxrvxpyXhloC1HwXOU5UAuBr7gdzoVwJOBjAs5
RtnyHoNAOJoSF3I0DU0Km6XZ0rxiFtVdVwW4MHBpKhdhxKDmqTL+L/bHlSEboDv8Aj4noCTiKw9d
49NHk8vT6atR7d7MUl6Rr+N1Vf9Ok9ZOWSpyaSoSMe8yty6eMFJA1syvw82llvuFV0hhNkuBhT9V
KS2RBMZ2fun9Yddt1TuPKpzKgjstLwkYyVb3AkYXp+ZuANKSQM5XL9vRmeJLEtdAvrc9aJ+teaz1
z7ze1xK7PvZqu+ATcj2OX2q/kBoZhqqHLAr9sIjYGvjyDkI1sp1M+Yx17K0Ilzoj2rrA8LmrCmWV
2grE1u+lM7XpRGhYb9A21q1uT9RvNrjdVv2l+5GtP29agJSJ/92K/LQ2Mf6/q8uRoKMqwdzW4l2o
8CoFEzeE/R1FaZpd83uYzv0i9BcbWmKqsSVA1l37+shc6wrWhfTx5Denl+eT1+PJFWu7ISDvazmt
NWkp14/ZTrVchslFn67VnF/wwN0l7OWqhU0KJ4nZdlp09Mm0bmCyyooIY/b1Ufj1Vm4NfB7y64Iy
XyQ5vc1pw9Ipp1xxnqschq3cLl2xupt69VZeXSa+Jr9eJ9TrbHp3K5Mu82jO+HlV81anSpz57yYB
X4KPvLtZu4qKIa3tFPAIGeCmxp/ybTK4xJv/Yr3HgS74fagIJsvTYOnz/QYrb11jzOjlkVyM2+TB
RwviL8rrPsx1Www3Y7pPwyouDfNtGb7c8tnbMh+/JWMyT7kHN+WKqylM98qytDa1a3OfbKtCDYM9
L+/TSDpuQ4IoW+1VbbJkhFLW2DlMliX21lZh+6hJaZrWtKY1rWlNa1rTmta0pjWtaU1rWtOa1rSm
Na1pTWta05rWtKY1rWlNa1rTmvZf1v4G3yMW1ABQAAA=
+8 -2
View File
@@ -26,8 +26,14 @@ services:
ulimits:
memlock: -1
ports:
# Native-TLS API. Bind to the LAN IP (OPENBAO_BIND) to avoid exposing it on
# every interface; firewall it to the tape host (deploy.sh does this).
# Native-TLS API. Publish on the LAN IP only (OPENBAO_BIND) so it is not
# exposed on unrelated interfaces. NOTE: a Docker-published port is DNAT'd
# and bypasses the host INPUT firewall, so a source restriction there does
# NOT gate it — narrow access with OPENBAO_BIND + the optional mTLS
# (tls_require_and_verify_client_cert) stanza in config.hcl, and initialise
# the vault immediately (an uninitialised vault can be init'd by anyone who
# can reach it). deploy.sh defaults OPENBAO_BIND to OPENBAO_ADDR when it is
# an IP.
- "${OPENBAO_BIND:-0.0.0.0}:8200:8200"
volumes:
- ./config.hcl:/openbao/config/config.hcl:ro
+1 -1
View File
@@ -36,4 +36,4 @@ chmod 644 "$DIR/tls.crt"
echo "[gen-tls] Generated self-signed OpenBao cert in $DIR"
echo "[gen-tls] SANs: ${SANS} validity: ${DAYS}d"
echo "[gen-tls] Give $DIR/tls.crt to the Kanrisha daemon as"
echo "[gen-tls] [encryption.openbao].openbao_ca_cert (so it trusts this listener)."
echo "[gen-tls] [encryption.openbao].ca_cert (so it trusts this listener)."