Picks up 6 security fixes across 2.6.0/2.6.2, notably GHSA-xp3c-3jw3-4vcr
(LIST bypassing an explicit deny from a wildcard grant).
Checked the 2.6.x breaking changes against this deployment before upgrading:
- Identity-template hardening (+ * / , now rejected in template values):
no {{ }} templating in any policy, and every pki/ssh role has
*_template = false. Unaffected.
- Container default user changed root -> openbao (uid 100): the raft volume
at /openbao/file is already uid 100 and the config bind-mount is
world-readable :ro, so no chown fixup was needed. Both containers now run
as uid=100(openbao). Unaffected.
- Cloud KMS + pkcs11 seals become external plugins in 2.7.0: this uses the
transit seal, which stays built in. Unaffected.
- physical/file deprecated in 2.7.0: storage is raft. Unaffected.
- Pre-v2.5.0 corrupt identity groups purged on unseal: cluster was created
on 2.5.5, and the `family` group survived. Unaffected.
- Arch-specific tags (2.6.x-arm64) no longer published: compose uses the
plain multi-arch tag. Unaffected.
Upgrade order was unsealer first (recreate, manually unseal 1-of-1 shamir,
confirm the autounseal transit key is readable), then main, which
auto-unsealed via transit. Cluster IDs preserved on both.
Verified after: all 13 mounts, 4 auth methods and 14 policies intact; KV
read, PKI issue, SSH CA sign and transit encrypt all work through their
scoped tokens; backup token still 403s outside its scope; raft snapshots
succeed on 2.6.2; HTTPS via Traefik serves 2.6.2 with a trusted chain.
Note: sys/seal-status now reports `commit_date` instead of `build_date`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NFtVLA7VVqXL5G2S18c4Jk
renew-app-tokens.sh only walked ~/.config/openbao/*.token, so the three
root-owned tokens were never renewed and lapsed on 2026-07-29:
/etc/openbao-backup.token -> nightly raft snapshots failed (403)
/etc/openbao-unsealer-backup.token -> same, unsealer instance
/etc/openbao-cert-renew.token -> would have failed silently at <21d
Nightly backups had been failing for 24 days before this was noticed; the
last good snapshot was 2026-07-28. All three tokens have been re-issued as
periodic (30d) and the script now covers both sets.
The unsealer's token belongs to a separate instance with no published port,
so it renews via `docker compose exec` rather than curl -- renewing it
against main returns 403. Note `bao token renew` takes no -self flag; the
bare form is the renew-self call.
Service now runs as root to read /etc, and chowns the log back to lutz.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NFtVLA7VVqXL5G2S18c4Jk
Periodic scoped tokens (~/.config/openbao/*.token) expired because nothing
renewed them within their period. renew-app-tokens.sh renews all of them via
auth/token/renew-self; openbao-token-renew.timer runs it daily (Persistent=true).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
${DRY:+...} expanded on DRY=0 (non-empty). Gate the label on DRY=1 instead;
the apply logic was already correct.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Read-only access to secret/data/smtp/healthcheck, consumed by the ClaudeAdmin
healthcheck email notifier via a periodic token.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Generalize the .26 rollout into a reusable template:
- authorize the host principal on ssh/roles/host (allowlist, merged)
- sign the host certificate (ssh/sign/host)
- emit a self-contained installer (user-CA TrustedUserCAKeys + HostCertificate)
to artifacts/, additive and lockout-safe
- add @cert-authority for the host to the client's known_hosts
Needs no SSH access to the target (ssh-keyscan). README updated.
Also gitignore .claude/ (local harness settings).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reviewable governance scaffolding — NOTHING applied to live OpenBAO yet:
- policies/: materialize all existing policies as code (faithfully fetched
from live) + new `operator` (use engines, no admin) and `auditor`
(read-only governance visibility, no secret material)
- scripts/apply-policies.sh: idempotent policy-as-code apply, with a
read-only --dry-run that diffs files vs live (ignores comments)
- scripts/setup-identity.sh: identity-as-code — policy-bound groups
(g-admins/operators/auditors/personal) + a human entity/alias; DEFAULT
DRY-RUN, --apply to execute
- GOVERNANCE.md: the layered model, policy catalog, naming, apply order,
and cross-cutting controls (audit device, root offline, AppRole migration)
Dry-runs verified read-only: apply-policies shows operator/auditor as NEW,
all others unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two isolated personal-credential backup options to evaluate, both excluded
from the admin policy (root-only break-glass):
- Scenario A: personal/ KV v2 (versioned) + personal-{put,get,list}.sh
- Scenario B: transit-personal/ key personal-backup + secret-{encrypt,decrypt}.sh
Plus an AppRole example of how a system should consume a secret:
- demo-app role/policy (read-only secret/demo-app/*), short-lived tokens
- scripts/app-get-secret.sh: login (role_id+secret_id) -> token -> read
All tokens/credentials live under ~/.config/openbao (outside the repo).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Turn the ssh/ engine into an SSH CA for cert-based access:
- ssh/ roles: "user" (8h user certs, principal-restricted) and "host"
(long-lived host certs); mount max-lease-ttl raised for host certs
- scripts/ssh-login.sh: sign a fresh user cert via a scoped ssh/sign/user
token (API, no bao binary) and connect — no authorized_keys on targets
- ca/openbao-ssh-ca.pub: the SSH CA public key (for TrustedUserCAKeys and
client @cert-authority trust)
- README: usage, host onboarding, client trust
- gitignore generated per-host artifacts/
First host wired + verified end-to-end: 192.168.0.26 (pifour) — lutz cert
login and host-cert verification both confirmed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Store the gitea PAT in OpenBAO KV (secret/gitea/push) and fetch it via a
git credential helper instead of keeping it in ~/.git-credentials:
- scripts/git-credential-openbao.sh: helper that reads the cred from the
OpenBAO API using a scoped, read-only periodic token
- scripts/store-gitea-cred.sh: one-time hidden-input store of the PAT
- README: usage + rotation notes
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Build out the home-lab OpenBAO deployment beyond the basic node:
- docker-compose: add openbao-unsealer sidecar; main node now transit
auto-unseals against it (seal config kept in gitignored config/seal.hcl)
- policies/admin.hcl: non-root admin policy; per-engine rules for
ssh/pki/pki_int/totp/transit
- Internal two-tier CA (pki/ root + pki_int/ intermediate) issues the
openbao.famfi.home leaf Traefik serves; root CA published under ca/
- scripts/ + systemd/: daily cert renewal and Raft snapshot backups
(both instances), with scoped tokens stored outside the repo
- README: full runbook (auto-unseal, PKI, renewal, backups, DR/restore)
Secrets (init/unsealer keys, tokens, seal stanza) stay gitignored.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>