fix: route OpenBao recovery ceremonies safely

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a0290b-3241-74c3-b868-6049545af836
This commit is contained in:
tegwick 2026-08-22 20:54:45 +02:00
parent fff76ef089
commit e3b9b1620c
10 changed files with 131 additions and 4 deletions

View file

@ -185,6 +185,16 @@ def _founder_for_entry(entry: RouteEntry, need: str, domain: Optional[str]) -> F
"desk_hint": f"warden desk --from-plan (act=oidc_login) or: {expanded.fetch_command}",
},
)
if entry.lane == "ceremony":
return FounderAct(
kind="approve",
summary=f"Attended owner ceremony approval required for {entry.id}",
details={
"lane_id": entry.id,
"wiki_ref": entry.wiki_ref,
"desk_hint": "warden desk --act approve --lane " + entry.id,
},
)
if _APPROVAL_SIGNS.search(need):
return FounderAct(
kind="approve",
@ -293,8 +303,9 @@ def build_plan(
domain=domain,
)
# Login lanes always need a human identity act
if entry.lane == "login":
# Login and ceremony lanes always need a human act. A ceremony is a pure
# owner pointer: it must never fall through to secret paste-once mechanics.
if entry.lane in ("login", "ceremony"):
act = _founder_for_entry(entry, need, domain)
return AccessPlan(
need=need,
@ -308,7 +319,11 @@ def build_plan(
founder_act=act,
catalog=freshness,
candidates=candidates,
reasons=["login lane requires interactive founder/operator identity act"],
reasons=[
"login lane requires interactive founder/operator identity act"
if entry.lane == "login"
else "ceremony lane requires attended owner approval"
],
actor=actor,
domain=domain,
)

View file

@ -69,7 +69,7 @@ _REQUIRED_FIELDS = (
"workload_ref",
)
_VALID_STATUS = ("active", "draft")
_VALID_LANES = ("secret", "login")
_VALID_LANES = ("secret", "login", "ceremony")
_VALID_ROTATION_METHODS = ("rotate", "re-establish")
# Default review cadence for a catalog pointer — "is this still the right owner

View file

@ -174,6 +174,8 @@ class RouteEntry:
# "login" — interactive auth bootstrap (OIDC/MFA). No secret-read gate (you have
# no identity yet), no caller-auth precheck (the point is to get one),
# run interactively as the caller; warden never captures the token.
# "ceremony" — attended owner operation such as Shamir seal/unseal. It is a
# pointer plus approval boundary, never an executable access lane.
lane: str = "secret"
# Owner-native exec front door (WP-0019). When `exec_owner` is set, that subsystem
# (e.g. secrets-engine) provides the PRIMARY way to run a secret-backed command; the