MASON-IN-0004: record the policy-plus-AppRole escalation path in ops-mason-build

Finding from the inbound-library lane (ILIB-WP-0003): the build grant can
write a policy, bind it to an AppRole and mint a secret-id, yielding a
token outside its own denies. Options recorded for founder decision; the
policy is unchanged.

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 1170398@bnt-lap001
Assistant-Session: 622cd705-cb31-4322-ba08-dd42e44fa583
This commit is contained in:
tegwick 2026-10-05 16:23:05 +02:00
parent 4e3fc02f86
commit 7e86430913

View file

@ -71,3 +71,60 @@ notes: >-
fulfilled; the accepted conformance gaps and their 2026-12-21 review remain
declared and are not marked conformant by this intake closure.
```
## MASON-IN-0004 — Close the policy-plus-AppRole escalation path in ops-mason-build
```yaml
id: MASON-IN-0004
kind: intake
title: Close the policy-plus-AppRole escalation path in ops-mason-build
status: open
origin: review
origin_ref: inbound-library ILIB-WP-0003 (finding raised 2026-10-05 while preparing the first grant)
priority: high
owner: ops-mason
requested_by: founder
description: >-
policies/ops-mason-build.hcl says OpenBao, not convention, enforces "ops-mason
never reads a secret value". The explicit denies on platform/, operators/ and
secret/ data hold only for tokens that carry ops-mason-build. The same grant can
also do the following:
(1) create or update any ACL policy except its own (sys/policies/acl/*);
(2) create or update any AppRole role and read or write anything beneath it
(auth/approle/role/*), which includes reading role-id and minting secret-id;
(3) do the same for Kubernetes auth roles.
A grant holder could therefore write a policy granting read on platform/data/*,
bind it to a new AppRole, read that role's role-id, mint a secret-id and log in.
The resulting token does not carry ops-mason-build, so none of its denies
apply. Kubernetes roles allow the same path for anyone holding a
service-account JWT. This was confirmed by reading the policy text. It was
not exercised.
The builder legitimately needs to write policies and mint secret-ids to deliver
AppRole lanes, as it did for inbound-library-imap-approle on 2026-10-05. A
path-level deny on secret-id would therefore break every build. Parameter
constraints such as allowed_parameters with token_policies=workload-kv-read-*
narrow the role binding but not policy content, because a policy with a
conforming name can still grant platform/data/*.
options: >-
(a) Separation of duties: ops-mason drafts policy HCL in the plan, and the
founder applies the policy write in an attended operator session. The grant
loses sys/policies/acl/* create/update and keeps role binding and delivery,
restricted by allowed_parameters to the policy names the plan approved.
(b) Detective control: after every build, re-read the written policy and role
and compare them to the approved build_spec (policy text derived from kv_path
and capabilities). Alert from the OpenBao audit log on any sys/policies/acl
write or role secret-id mint by a claude-* display_name that has no matching
build-log record.
(c) Two grants: a read-only survey grant (survey, metadata, capabilities), and
a build grant minted only after plan approval and scoped by allowed_parameters
to that plan's exact policy and role names. Bao policies cannot template on
plan content, so this means minting a per-plan policy at grant time, itself an
operator act.
These can be combined, for example (b) now and (a) or (c) as the structural fix.
This is a decision for the founder. Do not widen or loosen ops-mason-build
while it is open.
notes: >-
A survey needs only (c)'s read-only grant. Today MASON-WP-0008 plan-survey runs
under the full build grant, so separating them also reduces what a survey
session can do.
```