MASON-WP-0005-T01: bind key-cape's confirmed claims for the operator lane

key-cape confirmed groups_claim=groups, bound group fluid-telegram-operators,
assurance aal2 and the three openbao-admin callbacks. The OIDC executor now
pins /assurance/level=aal2 (bound_claims_type=string) and accepts the exact
operator-tunnel UI callback; the retired public UI callback stays refused.
T01 now waits on the founder go for the LLDAP group and a scoped survey grant.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 327203@bnt-lap001
Assistant-Session: 55028ae3-4914-4bd1-8f5c-815f3527aef0
This commit is contained in:
tegwick 2026-10-08 23:41:34 +02:00
parent 24d05c6cde
commit 894761477f
4 changed files with 49 additions and 11 deletions

View file

@ -93,6 +93,11 @@ class OIDCKVSpec:
audit_log_path: Path | None = None
# KeyCape sets assurance.level=aal2 only after a verified privacyIDEA factor
# (key-cape reply 2026-10-08, as in CCR-2026-0034); every attended role pins it.
_REQUIRED_ASSURANCE = {"/assurance/level": "aal2"}
_UI_CALLBACK = "http://127.0.0.1:18200/ui/vault/auth/{mount}/oidc/callback"
_OPERATOR_MATRIX = (
("operator-app", ("read",)),
("operator-session", ("create", "read", "update")),
@ -138,6 +143,8 @@ def _validate_oidc_spec(spec: OIDCKVSpec) -> None:
for uri in spec.allowed_redirect_uris:
if not isinstance(uri, str):
raise BuildRefused("OIDC callback must be a URI")
if uri == _UI_CALLBACK.format(mount=spec.auth_mount):
continue
try:
u = urlsplit(uri)
valid = (u.scheme == "http" and u.hostname in {"localhost", "127.0.0.1"}
@ -146,7 +153,7 @@ def _validate_oidc_spec(spec: OIDCKVSpec) -> None:
except ValueError:
valid = False
if not valid:
raise BuildRefused("initial matrix engine accepts only reviewed loopback CLI callbacks on port 8250")
raise BuildRefused("matrix engine accepts only the reviewed loopback CLI callbacks on port 8250 and the operator-tunnel UI callback")
def oidc_role_document(spec: OIDCKVSpec) -> dict:
@ -154,7 +161,8 @@ def oidc_role_document(spec: OIDCKVSpec) -> dict:
return {
"role_type": "oidc", "user_claim": "sub", "groups_claim": "groups",
"oidc_scopes": ["openid", "profile", "email", "groups"],
"bound_claims": {"groups": spec.bound_group},
"bound_claims_type": "string",
"bound_claims": {"groups": [spec.bound_group], **_REQUIRED_ASSURANCE},
"allowed_redirect_uris": list(spec.allowed_redirect_uris),
"token_policies": [spec.policy_name], "token_no_default_policy": True,
"token_ttl": spec.token_ttl, "token_max_ttl": spec.token_max_ttl,