feat(openbao): wizard + daily token rotation #56

Merged
michal merged 1 commits from feat/openbao-wizard into main 2026-04-20 16:22:51 +00:00
Owner

Summary

One-command setup for OpenBao-backed secret storage. `mcpctl create secretbackend bao --type openbao --wizard` takes your admin token once, provisions a narrow policy + token role, mints the first periodic token, stores it on mcpd, verifies end-to-end, and prints the migrate command. Admin token is never persisted.

The stored credential auto-rotates daily: mint new → verify → persist → revoke old. TTL 720h means a week of rotation failures still leaves plenty of runway. `describe secretbackend` surfaces token health + last rotation error so stale rotation is visible without tailing logs.

  • `@mcpctl/shared/vault` — new pure HTTP helpers + policy HCL builder
  • `tokenMeta` column on `SecretBackend` (empty-default, self-healing schema push)
  • `POST /api/v1/secretbackends/:id/rotate` gated by `rotate-secretbackend` op
  • Rotator loop: per-backend timers with ±10 min jitter, overdue-on-startup kick
  • `mcpctl rotate secretbackend ` convenience verb
  • Describe formatter renders Token health section (healthy / STALE / WARNING / ERROR)

Test plan

  • 15 vault-client unit tests (health, kv v2 mount, policy, role, mint, revoke, lookup-self, smoke round-trip)
  • 8 rotator unit tests (happy path + ordering, mint failure records error + keeps old token, non-renewable rejected, revoke failure tolerated, isOverdue, not-rotatable rejection)
  • 3 wizard flow tests (full scripted walk-through + migration hint, empty-admin rejection, sealed-vault rejection, admin token absent from stdout)
  • Full workspace suite: 1885/1885 (+32 new)
  • TypeScript clean across shared + mcpd + cli
  • Completions regenerated
  • End-to-end: deploy, run wizard against live bao.ad.itaz.eu, migrate the 9 secrets currently on default to bao, force-rotate, watch describe show new timestamps

🤖 Generated with Claude Code

## Summary One-command setup for OpenBao-backed secret storage. \`mcpctl create secretbackend bao --type openbao --wizard\` takes your admin token once, provisions a narrow policy + token role, mints the first periodic token, stores it on mcpd, verifies end-to-end, and prints the migrate command. **Admin token is never persisted.** The stored credential **auto-rotates daily**: mint new → verify → persist → revoke old. TTL 720h means a week of rotation failures still leaves plenty of runway. \`describe secretbackend\` surfaces token health + last rotation error so stale rotation is visible without tailing logs. - \`@mcpctl/shared/vault\` — new pure HTTP helpers + policy HCL builder - \`tokenMeta\` column on \`SecretBackend\` (empty-default, self-healing schema push) - \`POST /api/v1/secretbackends/:id/rotate\` gated by \`rotate-secretbackend\` op - Rotator loop: per-backend timers with ±10 min jitter, overdue-on-startup kick - \`mcpctl rotate secretbackend <name>\` convenience verb - Describe formatter renders Token health section (healthy / STALE / WARNING / ERROR) ## Test plan - [x] 15 vault-client unit tests (health, kv v2 mount, policy, role, mint, revoke, lookup-self, smoke round-trip) - [x] 8 rotator unit tests (happy path + ordering, mint failure records error + keeps old token, non-renewable rejected, revoke failure tolerated, isOverdue, not-rotatable rejection) - [x] 3 wizard flow tests (full scripted walk-through + migration hint, empty-admin rejection, sealed-vault rejection, **admin token absent from stdout**) - [x] Full workspace suite: **1885/1885** (+32 new) - [x] TypeScript clean across shared + mcpd + cli - [x] Completions regenerated - [ ] End-to-end: deploy, run wizard against live bao.ad.itaz.eu, migrate the 9 secrets currently on default to bao, force-rotate, watch describe show new timestamps 🤖 Generated with [Claude Code](https://claude.com/claude-code)
michal added 1 commit 2026-04-20 16:20:56 +00:00
feat(openbao): wizard-provisioning + daily token rotation
Some checks failed
CI/CD / typecheck (pull_request) Successful in 55s
CI/CD / test (pull_request) Successful in 1m4s
CI/CD / lint (pull_request) Successful in 2m2s
CI/CD / smoke (pull_request) Failing after 1m36s
CI/CD / build (pull_request) Successful in 4m13s
CI/CD / publish (pull_request) Has been skipped
dd4246878d
One-command setup replaces the 6-step manual flow — `mcpctl create
secretbackend bao --type openbao --wizard` takes the OpenBao admin token
once, provisions a narrow policy + token role, mints the first periodic
token, stores it on mcpd, verifies end-to-end, and prints the migration
command. The admin token is NEVER persisted.

The stored credential auto-rotates daily: mcpd mints a successor via the
token role (self-rotation capability is part of the policy it was issued
with), verifies the successor, writes it over the backing Secret, then
revokes the predecessor by accessor. TTL 720h means a week of rotation
failures still leaves 20+ days of runway.

Shared:
- New `@mcpctl/shared/vault` — pure HTTP wrappers (verifyHealth,
  ensureKvV2, writePolicy, ensureTokenRole, mintRoleToken, revokeAccessor,
  lookupSelf, testWriteReadDelete) and policy HCL builder.

mcpd:
- `tokenMeta Json @default("{}")` on SecretBackend. Self-healing schema
  migration — empty default lets `prisma db push` add the column cleanly.
- SecretBackendRotator.rotateOne: mint → verify → persist → revoke-old →
  update tokenMeta. Failures surface via `lastRotationError` on the row;
  the old token keeps working.
- SecretBackendRotatorLoop: on startup rotates overdue backends, schedules
  per-backend timers with ±10min jitter. Stops cleanly on shutdown.
- New `POST /api/v1/secretbackends/:id/rotate` (operation
  `rotate-secretbackend` — added to bootstrap-admin's auto-migrated ops
  alongside migrate-secrets, which was previously missing too).

CLI:
- `--wizard` on `create secretbackend` delegates to the interactive flow.
  All prompts can be pre-answered via flags (--url, --admin-token,
  --mount, --path-prefix, --policy-name, --token-role,
  --no-promote-default) for CI.
- `mcpctl rotate secretbackend <name>` — convenience verb; hits the new
  rotate endpoint.
- `describe secretbackend` renders a Token health section (healthy /
  STALE / WARNING / ERROR) with generated/renewal/expiry timestamps and
  last rotation error. Only shown when tokenMeta.rotatable is true — the
  existing k8s-auth + static-token backends don't surface it.

Tests: 15 vault-client unit tests (shared), 8 rotator unit tests (mcpd),
3 wizard flow tests (cli, including a regression test that the admin
token never appears in stdout). Full suite 1885/1885 (+32). Completions
regenerated for the new flags.

Out of scope (explicit): kubernetes-auth wizard, Vault Enterprise
namespaces in the wizard path, rotation for non-wizard static-token
backends. See plan file for details.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
michal merged commit ba4129a1e4 into main 2026-04-20 16:22:51 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: michal/mcpctl#56