Record the passing hub-writer receipts.
Member and non-member verification both passed. The verifier accepts s. tokens and calls sys/capabilities with a token that is allowed to. Assistant: grok Assistant-Session: 01a13b2d-5f6d-7a32-b2c9-384625c55ca6
This commit is contained in:
parent
05882b189f
commit
97d1fed949
7 changed files with 116 additions and 45 deletions
|
|
@ -2,17 +2,15 @@
|
|||
# Custodian Brief — ops-mason
|
||||
|
||||
**Domain:** infotech
|
||||
**Last synced:** 2026-10-14 17:37 UTC
|
||||
**Last synced:** 2026-10-14 17:49 UTC
|
||||
**State Hub:** http://127.0.0.1:8000 *(adjust if running on a remote machine)*
|
||||
|
||||
## Active Workstreams
|
||||
|
||||
### Name a dedicated caller for the reuse-surface hub writer token
|
||||
Progress: 2/4 done | workplan_id: `08e52353-b6e5-5742-b7b4-080d51a0cf57`
|
||||
Progress: 3/4 done | workplan_id: `08e52353-b6e5-5742-b7b4-080d51a0cf57`
|
||||
|
||||
**Open tasks:**
|
||||
- ! Apply the role without a KV write `7c32e273`
|
||||
*(wait: After T02. Founder applies proposed CCR-2026-0044 through the delegated applier. No bao kv put. Do not attach the policy to the admin entity.)*
|
||||
- ! Record the sanitized receipt `9e12db29`
|
||||
*(wait: After T03. Founder runs scripts/verify-reuse-surface-hub-writer.py member and non-member. A live receipt does not exist yet.)*
|
||||
|
||||
|
|
|
|||
16
docs/evidence/2026-10-14-reuse-surface-hub-writer-member.txt
Normal file
16
docs/evidence/2026-10-14-reuse-surface-hub-writer-member.txt
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
mode=member
|
||||
at=2026-10-14T20:05:45Z
|
||||
addr=http://127.0.0.1:18200
|
||||
role=reuse-surface-hub-writer-workload-kv-read
|
||||
policy=workload-kv-read-reuse-surface-runtime
|
||||
login=ok
|
||||
entity_id=c204099b-cb94-363f-e207-5ff4d4aa6e94
|
||||
policies=workload-kv-read-reuse-surface-runtime
|
||||
identity_policies=
|
||||
platform/data/workloads/reuse/reuse-surface/runtime-secrets: read
|
||||
platform/metadata/workloads/reuse/reuse-surface/runtime-secrets: read
|
||||
platform/data/workloads/reuse/reuse-surface: deny
|
||||
platform/metadata/workloads/reuse/reuse-surface: deny
|
||||
platform/data/workloads/issue-core/issue-core/issue-core-runtime: deny
|
||||
revoked=yes
|
||||
result=pass
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
mode=non-member
|
||||
at=2026-10-14T20:10:49Z
|
||||
addr=http://127.0.0.1:18200
|
||||
role=reuse-surface-hub-writer-workload-kv-read
|
||||
policy=workload-kv-read-reuse-surface-runtime
|
||||
login=refused
|
||||
entity_id=
|
||||
policies=
|
||||
identity_policies=
|
||||
platform/data/workloads/reuse/reuse-surface/runtime-secrets: not-run
|
||||
platform/metadata/workloads/reuse/reuse-surface/runtime-secrets: not-run
|
||||
platform/data/workloads/reuse/reuse-surface: not-run
|
||||
platform/metadata/workloads/reuse/reuse-surface: not-run
|
||||
platform/data/workloads/issue-core/issue-core/issue-core-runtime: not-run
|
||||
revoked=n/a
|
||||
result=pass
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Plan: `plans/reuse-surface-hub-writer.md`. Filed request:
|
||||
`railiance-platform/credential-change-requests/CCR-2026-0044-reuse-surface-hub-writer-caller.yaml`
|
||||
(proposed). Source copy:
|
||||
(applied 2026-10-14). Source copy:
|
||||
`builds/reuse-surface-hub-writer/credential-change-requests/CCR-DRAFT-REUSE-SURFACE-HUB-WRITER.yaml`.
|
||||
|
||||
Run this only after CCR-2026-0044 is approved and applied. LLDAP group
|
||||
|
|
@ -15,9 +15,11 @@ shape go through
|
|||
identity-provisioner `POST /v1/groups/ensure`; see
|
||||
`docs/directory-group-binding.md`.
|
||||
|
||||
The script leaves `~/.vault-token` in place and uses it only to call
|
||||
`sys/capabilities`. The lane token is not printed and is revoked before the
|
||||
script exits. A passing receipt is the sanitized verification record.
|
||||
The script leaves `~/.vault-token` in place. It calls `sys/capabilities` with
|
||||
the first local token that is allowed to: `BAO_TOKEN` or `VAULT_TOKEN`, then
|
||||
`~/.local/openbao/platform-admin.token`, then `~/.vault-token`. The lane token
|
||||
is not printed and is revoked before the script exits. A passing receipt is
|
||||
the sanitized verification record.
|
||||
|
||||
```bash
|
||||
export BAO_ADDR=http://127.0.0.1:18200
|
||||
|
|
|
|||
|
|
@ -140,7 +140,9 @@ key-cape confirms the group:
|
|||
1. Copy the policy file over
|
||||
`railiance-platform/openbao/policies/workload-kv-read-reuse-surface-runtime.hcl`
|
||||
and apply the CCR with the delegated applier. Do not run `bao kv put`.
|
||||
2. Keep an operator token in `~/.vault-token` for the capability query.
|
||||
2. The capability query uses the first local token allowed to call
|
||||
`sys/capabilities`: `BAO_TOKEN` or `VAULT_TOKEN`, then
|
||||
`~/.local/openbao/platform-admin.token`, then `~/.vault-token`.
|
||||
In a private window, as the group member:
|
||||
|
||||
```bash
|
||||
|
|
@ -165,7 +167,11 @@ Do not export the field. Revoke the lane token when the command returns.
|
|||
|
||||
## 6. Result
|
||||
|
||||
Applied 2026-10-14T17:47:43Z. No live member receipt yet.
|
||||
Applied 2026-10-14T17:47:43Z. Both attended receipts passed on 2026-10-14.
|
||||
Member at 20:05:45Z is entity `c204099b-cb94-363f-e207-5ff4d4aa6e94` with
|
||||
only `workload-kv-read-reuse-surface-runtime`. Non-member at 20:10:49Z was
|
||||
refused. Copies are in `docs/evidence/2026-10-14-reuse-surface-hub-writer-member.txt`
|
||||
and `docs/evidence/2026-10-14-reuse-surface-hub-writer-non-member.txt`.
|
||||
|
||||
2026-10-14: railiance-platform filed this bundle as proposed CCR-2026-0044
|
||||
(`88b4aed`, message `14e23602`). The live policy file stays as it was until
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@
|
|||
|
||||
Logs in on auth/netkingdom role reuse-surface-hub-writer-workload-kv-read with
|
||||
``bao login -token-only``, so the operator's token helper is left alone. The
|
||||
lane token stays in memory. Capability queries run as the operator token
|
||||
already present in the environment or token helper, because the workload
|
||||
policy has no sys/capabilities-self grant. The receipt records policies,
|
||||
entity id, path capabilities, and pass/fail. It does not record the token or
|
||||
any KV value.
|
||||
lane token stays in memory. Capability queries use the first local token that
|
||||
may call ``sys/capabilities`` (``BAO_TOKEN`` or ``VAULT_TOKEN``, then
|
||||
``~/.local/openbao/platform-admin.token``, then ``~/.vault-token``), because
|
||||
the workload policy has no sys/capabilities-self grant. The receipt records
|
||||
policies, entity id, path capabilities, and pass/fail. It does not record the
|
||||
token or any KV value.
|
||||
|
||||
Sign in with a private browser window. A reused platform-admin session is the
|
||||
wrong principal for ``member``.
|
||||
|
|
@ -43,7 +44,8 @@ from ops_mason.reuse_surface_hub_writer import (
|
|||
)
|
||||
|
||||
BAO_ADDR = os.environ.get("BAO_ADDR", "http://127.0.0.1:18200")
|
||||
TOKEN_RE = re.compile(r"\b(?:hvs|hvb|hvr)\.[A-Za-z0-9_-]{8,}\b")
|
||||
# This OpenBao issues s. service tokens. hvs/hvb/hvr are the newer Vault shapes.
|
||||
TOKEN_RE = re.compile(r"\b(?:hvs|hvb|hvr|s)\.[A-Za-z0-9_-]{8,}\b")
|
||||
PATHS = [DATA, METADATA, PARENT_DATA, PARENT_METADATA, SIBLING]
|
||||
|
||||
|
||||
|
|
@ -58,14 +60,45 @@ def receipts_dir() -> Path:
|
|||
return path
|
||||
|
||||
|
||||
def operator_token() -> str:
|
||||
def token_candidates() -> list[tuple[str, str]]:
|
||||
found: list[tuple[str, str]] = []
|
||||
for name in ("BAO_TOKEN", "VAULT_TOKEN"):
|
||||
value = os.environ.get(name, "").strip()
|
||||
if value:
|
||||
return value
|
||||
helper = Path(os.environ.get("HOME", str(Path.home()))) / ".vault-token"
|
||||
if helper.is_file():
|
||||
return helper.read_text(encoding="utf-8").strip()
|
||||
found.append((name, value))
|
||||
home = Path(os.environ.get("HOME", str(Path.home())))
|
||||
for label, path in (
|
||||
("~/.local/openbao/platform-admin.token", home / ".local/openbao/platform-admin.token"),
|
||||
("~/.vault-token", home / ".vault-token"),
|
||||
):
|
||||
if path.is_file():
|
||||
value = path.read_text(encoding="utf-8").strip()
|
||||
if value:
|
||||
found.append((label, value))
|
||||
return found
|
||||
|
||||
|
||||
def write_capabilities(caller: str, subject: str, paths: list[str]) -> subprocess.CompletedProcess[str]:
|
||||
body = json.dumps({"token": subject, "paths": paths})
|
||||
tmp = tempfile.NamedTemporaryFile("w", prefix="rs-caps-", delete=False)
|
||||
try:
|
||||
os.fchmod(tmp.fileno(), stat.S_IRUSR | stat.S_IWUSR)
|
||||
tmp.write(body)
|
||||
tmp.close()
|
||||
return run_bao(["write", "-format=json", "sys/capabilities", f"@{tmp.name}"], caller)
|
||||
finally:
|
||||
try:
|
||||
os.remove(tmp.name)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
def operator_token() -> str:
|
||||
"""Return a token allowed to call sys/capabilities, or an empty string."""
|
||||
for _label, token in token_candidates():
|
||||
probe = write_capabilities(token, token, ["auth/token/lookup-self"])
|
||||
if probe.returncode == 0:
|
||||
return token
|
||||
return ""
|
||||
|
||||
|
||||
|
|
@ -90,8 +123,8 @@ def login() -> str:
|
|||
token="",
|
||||
)
|
||||
token = (proc.stdout or "").strip()
|
||||
if proc.returncode != 0 or not token or TOKEN_RE.fullmatch(token) is None:
|
||||
sys.stderr.write(redact(proc.stderr or "login refused\n"))
|
||||
if proc.returncode != 0 or TOKEN_RE.fullmatch(token) is None:
|
||||
sys.stderr.write(redact(proc.stderr or "login output was not a token\n"))
|
||||
return ""
|
||||
return token
|
||||
|
||||
|
|
@ -107,21 +140,10 @@ def lookup(token: str) -> dict:
|
|||
def capabilities(operator: str, lane: str) -> dict[str, list[str]]:
|
||||
if not operator:
|
||||
raise RuntimeError(
|
||||
"no operator token for sys/capabilities "
|
||||
"(BAO_TOKEN, VAULT_TOKEN, or ~/.vault-token)"
|
||||
"no token can call sys/capabilities "
|
||||
"(BAO_TOKEN, VAULT_TOKEN, ~/.local/openbao/platform-admin.token, or ~/.vault-token)"
|
||||
)
|
||||
body = json.dumps({"token": lane, "paths": PATHS})
|
||||
tmp = tempfile.NamedTemporaryFile("w", prefix="rs-caps-", delete=False)
|
||||
try:
|
||||
os.fchmod(tmp.fileno(), stat.S_IRUSR | stat.S_IWUSR)
|
||||
tmp.write(body)
|
||||
tmp.close()
|
||||
proc = run_bao(["write", "-format=json", "sys/capabilities", f"@{tmp.name}"], operator)
|
||||
finally:
|
||||
try:
|
||||
os.remove(tmp.name)
|
||||
except OSError:
|
||||
pass
|
||||
proc = write_capabilities(operator, lane, PATHS)
|
||||
if proc.returncode != 0:
|
||||
raise RuntimeError(redact(proc.stderr or "sys/capabilities failed"))
|
||||
payload = json.loads(proc.stdout)
|
||||
|
|
@ -151,11 +173,17 @@ def main(argv: list[str]) -> int:
|
|||
if mode not in {"member", "non-member"}:
|
||||
sys.stderr.write("usage: verify-reuse-surface-hub-writer.py member|non-member\n")
|
||||
return 2
|
||||
operator = operator_token()
|
||||
if not operator:
|
||||
sys.stderr.write(
|
||||
"no token can call sys/capabilities. Checked BAO_TOKEN, VAULT_TOKEN, "
|
||||
"~/.local/openbao/platform-admin.token, and ~/.vault-token.\n"
|
||||
)
|
||||
return 1
|
||||
sys.stderr.write(
|
||||
f"Sign in as the {mode} identity in a private browser window.\n"
|
||||
"A platform-admin session is the wrong principal for member.\n"
|
||||
)
|
||||
operator = operator_token()
|
||||
now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
lane = login()
|
||||
report: dict = {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ type: workplan
|
|||
title: "Name a dedicated caller for the reuse-surface hub writer token"
|
||||
domain: infotech
|
||||
repo: ops-mason
|
||||
status: active
|
||||
status: finished
|
||||
flavor: planning
|
||||
owner: codex
|
||||
topic_slug: custodian
|
||||
|
|
@ -117,15 +117,20 @@ Done 2026-10-14.
|
|||
|
||||
```task
|
||||
id: MASON-WP-0011-T04
|
||||
status: wait
|
||||
status: done
|
||||
depends_on: [MASON-WP-0011-T03]
|
||||
blocked_on: human
|
||||
blocking_reason: "After T03. Founder runs scripts/verify-reuse-surface-hub-writer.py member and non-member. A live receipt does not exist yet."
|
||||
priority: high
|
||||
state_hub_task_id: "9e12db29-532d-5d90-8519-227799018ab0"
|
||||
```
|
||||
|
||||
Both modes must pass. Copy the mode-0600 receipts into `docs/evidence/`
|
||||
with no token and no field value, reply to message `08b254af`, and tell
|
||||
ops-warden the role name for `auth_method`. Hub registration itself stays
|
||||
Both modes passed on 2026-10-14. Member receipt at 20:05:45Z: login ok,
|
||||
entity `c204099b-cb94-363f-e207-5ff4d4aa6e94`, policy
|
||||
`workload-kv-read-reuse-surface-runtime` only, exact paths read, parent and
|
||||
sibling paths deny, token revoked. Non-member receipt at 20:10:49Z:
|
||||
login refused. Copies with no token are
|
||||
`docs/evidence/2026-10-14-reuse-surface-hub-writer-member.txt` and
|
||||
`docs/evidence/2026-10-14-reuse-surface-hub-writer-non-member.txt`.
|
||||
Replied to message `08b254af`. ops-warden can name role
|
||||
`reuse-surface-hub-writer-workload-kv-read` on
|
||||
`auth_method` for `reuse-surface-hub-write-token`. Hub registration stays
|
||||
with the-custodian.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue