CCR-2026-0064 (proposed): read-only window watch for the CCR-2026-0058 write role (net-kingdom NK-WP-0058-T06)
All checks were successful
CCR intake gate / gate (push) Successful in 1m14s
CI Smoke / host-smoke (push) Successful in 2s
CI Smoke / container-smoke (push) Successful in 4s

New request type auth-role-presence-watch (scripts/auth_role_watch_lane.py, registered in LANE_MODULES):
a Kubernetes-auth role for sso/nk-window-watch whose policy is generated from the CCR - read (mode flag)
or read and delete (mode close) on exactly one watched role path, plus token self-lifecycle. Validator
refuses any widening; apply writes policy and role and reads both back; tests with a fake bao.
Drafted by net-kingdom on the founder's instruction for platform-owner review. Mode flag; not approved.

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 943911@bnt-lap001
Assistant-Session: fc322940-1c8e-4bed-ab39-86cec99f23a0
This commit is contained in:
codex 2026-11-06 08:55:09 +01:00
parent 2e1ca67a0e
commit b1421317e7
5 changed files with 454 additions and 0 deletions

View file

@ -0,0 +1,96 @@
id: CCR-2026-0064
kind: credential-change-request
schema_version: 1
request_type: auth-role-presence-watch
title: 'nk-window-watch: flag the CCR-2026-0058 write role when it outlives its run (read-only)'
status: proposed
created: '2026-11-06'
updated: '2026-11-06'
requester:
agent: net-kingdom
reason: net-kingdom NK-WP-0058-T06 (contract row O5). On 2026-11-04/05 the window-scoped write role of
CCR-2026-0058 stayed open overnight; T11 confirmed no use. A watcher in sso
(net-kingdom bounded-executor/window_watch.py, rapp-bounded-executor manifests/window-watch.yaml) checks every
10 minutes whether the role exists while no bounded-executor run Job is active or recent, and flags it.
Drafted by net-kingdom on the founder's instruction (2026-11-06), for platform-owner review. Not approved.
review:
required: true
required_approvers:
- platform-owner
- net-kingdom-owner
comments: []
target:
domain: infotech
tenant: platform
workload: net-kingdom-bounded-executor-window-watch
rapp: rapp-bounded-executor
environment: production
purpose: Let only the ServiceAccount sso/nk-window-watch read whether the role
net-kingdom-bind-executor-svc-authelia-write exists; no other path, no list, no write, no value
openbao:
policy_name: net-kingdom-bounded-executor-window-watch
policy_file: openbao/policies/net-kingdom-bounded-executor-window-watch.hcl
watch:
mount: kubernetes
role: net-kingdom-bind-executor-svc-authelia-write
mode: flag
auth:
method: kubernetes
mount: kubernetes
role: net-kingdom-bounded-executor-window-watch
audience: openbao
ttl: 15m
token_max_ttl: 15m
token_explicit_max_ttl: 15m
token_no_default_policy: true
policies:
- net-kingdom-bounded-executor-window-watch
bound_claims:
service_account_names:
- nk-window-watch
service_account_namespaces:
- sso
bound_claims_confirmed: false
access_frontdoor:
type: platform-owner
catalog_id: bounded-executor-window-watch
readiness: pending-review
resolvable: false
lifecycle:
role_window: Standing. The watcher logs in once per run (every 10 minutes), reads one role path and revokes its
token at exit.
close_mode: Mode close would add delete on the same single path, so the watcher removes a stale write role
itself. It only ever reduces privilege, but it is an unattended write on an auth role, so it needs its own
founder and platform-owner decision and an amendment of this CCR.
deactivate: Delete the role, then the policy; remove the CronJob (rapp-bounded-executor).
rotate: Nothing to rotate; the login uses the projected ServiceAccount token.
compromised: Delete the role. The reachable information is whether one role exists and its parameters.
delivery:
surface: native-workload-login
namespace: sso
service_account: nk-window-watch
reader: The window watch CronJob (net-kingdom bounded-executor/window_watch.py in the pinned executor image,
deployed by rapp-bounded-executor make deploy-window-watch); it prints one value-free line per run
risk:
classification: low
notes:
- Reachable data is the parameters of one Kubernetes-auth role (bound ServiceAccount, policies, TTLs), no
secret value and no token.
- The role is separate from the CCR-2026-0058/0059/0061 roles; policies are never combined in one role.
- Node root, cluster admins able to mint tokens for sso/nk-window-watch and platform-admin remain inside this
boundary.
verification:
positive:
- Exact policy and role read back (credential-change.py applier-apply readback)
- The watch CronJob's next run reports ok (no write role outside a run), visible as a succeeded Job to
sso/nk-agent-status
negative:
- Reading any other auth role, KV path or sys path is refused
- Writing or deleting the watched role is refused in mode flag
- Wrong ServiceAccount, wrong namespace and wrong audience logins are denied
activation_conditions:
- Explicit platform-owner and net-kingdom-owner approval of this exact request.
- ServiceAccount sso/nk-window-watch exists (rapp-bounded-executor make deploy-window-watch), then
bound_claims_confirmed set to true by the platform-owner with its uid.
- Attended platform-admin (aal2) session or the delegated applier applies policy and role from a reviewed
commit; results recorded value-free.

View file

@ -0,0 +1,14 @@
# net-kingdom-bounded-executor-window-watch: CCR-2026-0064 (auth-role-presence-watch, mode flag).
# Platform-generated from the CCR by scripts/auth_role_watch_lane.py; do not edit by hand.
path "auth/kubernetes/role/net-kingdom-bind-executor-svc-authelia-write" {
capabilities = ["read"]
}
path "auth/token/lookup-self" {
capabilities = ["read"]
}
path "auth/token/revoke-self" {
capabilities = ["update"]
}

View file

@ -0,0 +1,201 @@
"""auth-role-presence-watch CCRs: a workload may watch whether one Kubernetes-auth role exists.
net-kingdom NK-WP-0058-T06 (contract row O5). Loaded by scripts/credential-change.py for request_type
auth-role-presence-watch. A watcher ServiceAccount logs in with its own Kubernetes-auth role and may read exactly one
other role's path, so it can see that a window-scoped role (CCR-2026-0058) outlived its run. Mode `flag` grants read;
mode `close` adds delete on that same path, which only ever reduces privilege. Nothing else: no KV path, no other
auth path, no list, no sys. Nothing here reads, prints or accepts a secret value.
"""
from __future__ import annotations
import importlib.util
import json
import re
import tempfile
from pathlib import Path
from typing import Any
REQUEST_TYPE = "auth-role-presence-watch"
ROLE_RE = re.compile(r"^[a-z0-9][a-z0-9-]*$")
NAME_RE = re.compile(r"^[a-z0-9][a-z0-9-]*$")
MODES = {"flag": ["read"], "close": ["read", "delete"]}
SELF_GRANTS = [("auth/token/lookup-self", "read"), ("auth/token/revoke-self", "update")]
DURATIONS = ("ttl", "token_max_ttl", "token_explicit_max_ttl")
def _load(name: str):
spec = importlib.util.spec_from_file_location(name, Path(__file__).resolve().parent / f"{name}.py")
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
_shared = _load("service_jwt_lane")
BaoError = _shared.BaoError
normalized = _shared.normalized
ttl_seconds = _shared.ttl_seconds
_run = _shared._run
_read_json = _shared._read_json
def watched_path(ccr: dict[str, Any]) -> str:
watch = ccr["openbao"]["watch"]
return f"auth/{watch['mount']}/role/{watch['role']}"
def generated_policy_hcl(ccr: dict[str, Any]) -> str:
openbao = ccr["openbao"]
caps = ", ".join(f'"{c}"' for c in MODES[openbao["watch"]["mode"]])
lines = [f"# {openbao['policy_name']}: {ccr['id']} ({REQUEST_TYPE}, mode {openbao['watch']['mode']}).",
"# Platform-generated from the CCR by scripts/auth_role_watch_lane.py; do not edit by hand.", "",
f'path "{watched_path(ccr)}" {{', f" capabilities = [{caps}]", "}"]
for path, capability in SELF_GRANTS:
lines += ["", f'path "{path}" {{', f' capabilities = ["{capability}"]', "}"]
return "\n".join(lines) + "\n"
def role_payload(ccr: dict[str, Any]) -> dict[str, Any]:
auth = ccr["openbao"]["auth"]
return {"bound_service_account_names": list(auth["bound_claims"]["service_account_names"]),
"bound_service_account_namespaces": list(auth["bound_claims"]["service_account_namespaces"]),
"token_policies": [ccr["openbao"]["policy_name"]], "audience": auth["audience"],
"token_ttl": auth["ttl"], "token_max_ttl": auth["token_max_ttl"],
"token_explicit_max_ttl": auth["token_explicit_max_ttl"], "token_no_default_policy": True}
def validate(ccr: dict[str, Any], repo_dir: Path) -> list[str]:
errors: list[str] = []
openbao = ccr.get("openbao")
if not isinstance(openbao, dict) or not isinstance(openbao.get("auth"), dict) \
or not isinstance(openbao.get("watch"), dict):
return ["openbao.auth and openbao.watch must be objects"]
auth, watch = openbao["auth"], openbao["watch"]
if (ccr.get("target") or {}).get("environment") != "production":
errors.append("target.environment must be production")
review = ccr.get("review") or {}
if review.get("required") is not True or not review.get("required_approvers"):
errors.append("review.required must be true with required_approvers")
if watch.get("mode") not in MODES:
errors.append(f"openbao.watch.mode must be one of {sorted(MODES)}")
if watch.get("mount") != "kubernetes" or not ROLE_RE.match(str(watch.get("role") or "")):
errors.append("openbao.watch must name one role on the kubernetes auth mount")
if not NAME_RE.match(str(openbao.get("policy_name") or "")):
errors.append("openbao.policy_name contains unsafe characters")
if openbao.get("policy_file") != f"openbao/policies/{openbao.get('policy_name')}.hcl":
errors.append("openbao.policy_file must be openbao/policies/<policy_name>.hcl")
if auth.get("method") != "kubernetes" or auth.get("mount") != "kubernetes":
errors.append("openbao.auth must be the kubernetes method on mount kubernetes")
if not ROLE_RE.match(str(auth.get("role") or "")) or auth.get("role") == watch.get("role"):
errors.append("openbao.auth.role must be safe and differ from the watched role")
if auth.get("audience") != "openbao":
errors.append("openbao.auth.audience must be openbao")
if any(ttl_seconds(auth.get(k)) is None or ttl_seconds(auth.get(k)) > 900 for k in DURATIONS):
errors.append("openbao.auth ttl, token_max_ttl and token_explicit_max_ttl must be at most 15m")
if auth.get("token_no_default_policy") is not True:
errors.append("openbao.auth.token_no_default_policy must be true")
if auth.get("policies") != [openbao.get("policy_name")]:
errors.append("openbao.auth.policies must be exactly [policy_name]")
claims = auth.get("bound_claims") or {}
names, namespaces = claims.get("service_account_names"), claims.get("service_account_namespaces")
if not (isinstance(names, list) and len(names) == 1 and isinstance(namespaces, list) and len(namespaces) == 1
and set(claims) == {"service_account_names", "service_account_namespaces"}):
errors.append("openbao.auth.bound_claims must name exactly one ServiceAccount in one namespace")
if not isinstance(auth.get("bound_claims_confirmed"), bool):
errors.append("openbao.auth.bound_claims_confirmed must be a boolean")
if errors:
return errors
policy = repo_dir / openbao["policy_file"]
if not policy.exists():
errors.append(f"openbao.policy_file does not exist: {openbao['policy_file']}")
elif normalized(policy.read_text(encoding="utf-8")) != normalized(generated_policy_hcl(ccr)):
errors.append("openbao.policy_file differs from the policy generated from the CCR")
return errors
def readiness_blockers(ccr: dict[str, Any], repo_dir: Path, allowed_statuses: set[str]) -> list[str]:
blockers: list[str] = []
if ccr.get("status") not in allowed_statuses:
blockers.append(
"applier requires approved, applied, verified, or active CCR status, "
f"got {ccr.get('status')}"
)
if (ccr.get("openbao") or {}).get("auth", {}).get("bound_claims_confirmed") is not True:
blockers.append("applier requires confirmed OpenBao auth binding")
blockers.extend(validate(ccr, repo_dir))
return blockers
def dry_run_payload(ccr: dict[str, Any], repo_dir: Path, warnings: list[str]) -> dict[str, Any]:
openbao = ccr["openbao"]
auth = openbao["auth"]
return {
"id": ccr["id"],
"title": ccr["title"],
"status": ccr["status"],
"environment": ccr["target"]["environment"],
"warnings": warnings,
"source_artifacts": {"policy_file": openbao["policy_file"]},
"mutations": [
{"kind": "policy_write", "openbao_path": f"sys/policies/acl/{openbao['policy_name']}",
"payload": {"source": openbao["policy_file"], "watched_path": watched_path(ccr),
"capabilities": MODES[openbao["watch"]["mode"]]}},
{"kind": "auth_role_write", "openbao_path": f"auth/{auth['mount']}/role/{auth['role']}",
"payload": role_payload(ccr), "precondition": "auth/kubernetes exists (never enabled here)"},
{"kind": "readback_compare", "openbao_path": "policy and role", "payload": {"prints": "booleans only"}},
],
"out_of_scope": [
"the watched role itself (CCR-2026-0058 window-open and window-close)",
"secret value reads or writes",
"token creation or login",
],
"required_evidence": [
"CCR id and approval reference",
"readback equality for policy and role",
"the watch CronJob's first run in mode " + openbao["watch"]["mode"],
],
}
def apply_details(ccr: dict[str, Any], actor: str) -> list[str]:
openbao = ccr["openbao"]
auth = openbao["auth"]
return [
f"Delegated metadata applier ran as {actor} using local bao CLI ambient authority.",
f"Policy write: sys/policies/acl/{openbao['policy_name']} ({openbao['watch']['mode']} on {watched_path(ccr)})",
f"Kubernetes auth role write: auth/{auth['mount']}/role/{auth['role']}",
"Readback matched source for policy and role.",
"No secret values were read, written, printed, or accepted in argv.",
]
def readback_mismatches(ccr: dict[str, Any], repo_dir: Path, bao_bin: str) -> list[str]:
openbao = ccr["openbao"]
auth = openbao["auth"]
mismatches: list[str] = []
live = _run(bao_bin, ["policy", "read", openbao["policy_name"]], repo_dir, quiet=True, capture=True)
if normalized(live) != normalized(generated_policy_hcl(ccr)):
mismatches.append("policy differs")
role = _read_json(bao_bin, ["read", f"auth/{auth['mount']}/role/{auth['role']}"], repo_dir).get("data", {})
for key, want in role_payload(ccr).items():
got = role.get(key)
same = ttl_seconds(got) == ttl_seconds(want) if key.startswith("token_") and key.endswith("ttl") else got == want
if not same:
mismatches.append(f"role {key} differs")
return mismatches
def run_apply(ccr: dict[str, Any], repo_dir: Path, bao_bin: str, quiet: bool = False) -> None:
openbao = ccr["openbao"]
auth = openbao["auth"]
mounts = _read_json(bao_bin, ["auth", "list"], repo_dir)
mounts = mounts.get("data", mounts)
if (mounts.get("kubernetes/") or {}).get("type") != "kubernetes":
raise BaoError("auth mount kubernetes/ is absent or not kubernetes; this lane never enables it")
_run(bao_bin, ["policy", "write", openbao["policy_name"], openbao["policy_file"]], repo_dir, quiet)
with tempfile.TemporaryDirectory() as tmp:
role_path = Path(tmp) / "role.json"
role_path.write_text(json.dumps(role_payload(ccr), sort_keys=True) + "\n")
_run(bao_bin, ["write", f"auth/{auth['mount']}/role/{auth['role']}", f"@{role_path}"], repo_dir, quiet)
mismatches = readback_mismatches(ccr, repo_dir, bao_bin)
if mismatches:
raise BaoError("readback mismatch: " + "; ".join(mismatches))

View file

@ -851,6 +851,7 @@ LANE_MODULES = {
"workload-kv-operator-matrix": "operator_matrix_lane",
"custody-generate-grant": "broker_grant_lane",
"broker-issuer-binding": "issuer_binding_lane",
"auth-role-presence-watch": "auth_role_watch_lane",
}

View file

@ -0,0 +1,142 @@
"""auth-role-presence-watch lane (CCR-2026-0064, net-kingdom NK-WP-0058-T06)."""
from __future__ import annotations
import copy
import importlib.util
import json
import os
import stat
import sys
import tempfile
import unittest
from pathlib import Path
import yaml
ROOT = Path(__file__).resolve().parents[1]
CCR_PATH = ROOT / "credential-change-requests/CCR-2026-0064-nk-bounded-executor-window-watch.yaml"
WATCHED = "auth/kubernetes/role/net-kingdom-bind-executor-svc-authelia-write"
def load(name: str, rel: str):
spec = importlib.util.spec_from_file_location(name, ROOT / rel)
module = importlib.util.module_from_spec(spec)
sys.modules[name] = module
spec.loader.exec_module(module)
return module
lane = load("auth_role_watch_lane", "scripts/auth_role_watch_lane.py")
cc = load("credential_change_cli_watch", "scripts/credential-change.py")
def ccr() -> dict:
return yaml.safe_load(CCR_PATH.read_text())
FAKE_BAO = r'''#!/usr/bin/env python3
import json, os, sys
path = os.environ["FAKE_BAO_STATE"]
state = json.load(open(path))
args = [a for a in sys.argv[1:] if a != "-format=json"]
state.setdefault("calls", []).append(args)
if args[:2] == ["auth", "list"]:
print(json.dumps({k: {"type": v} for k, v in state["mounts"].items()}))
elif args[:2] == ["policy", "write"]:
state["policies"][args[2]] = open(args[3]).read()
elif args[:2] == ["policy", "read"]:
if args[2] not in state["policies"]:
json.dump(state, open(path, "w")); sys.exit(2)
print(state["policies"][args[2]])
elif args[0] == "write":
role = json.load(open(args[2][1:]))
state["roles"][args[1]] = {k: (900 if v == "15m" else v) for k, v in role.items()}
elif args[0] == "read":
print(json.dumps({"data": state["roles"][args[1]]}))
json.dump(state, open(path, "w"))
'''
class AuthRoleWatchLaneTests(unittest.TestCase):
def test_ccr_validates_and_blocks_until_approved_and_bound(self):
_ccr, errors, _w = cc.validate_ccr(CCR_PATH)
self.assertEqual(errors, [])
blockers = cc.applier_readiness_blockers(_ccr)
self.assertIn("applier requires confirmed OpenBao auth binding", blockers)
ready = copy.deepcopy(_ccr)
ready["status"] = "approved"
ready["openbao"]["auth"]["bound_claims_confirmed"] = True
self.assertEqual(cc.applier_readiness_blockers(ready), [])
def test_flag_policy_is_one_read_and_self_lifecycle(self):
text = (ROOT / ccr()["openbao"]["policy_file"]).read_text()
paths = [line.split('"')[1] for line in text.splitlines() if line.startswith("path ")]
self.assertEqual(paths, [WATCHED, "auth/token/lookup-self", "auth/token/revoke-self"])
self.assertIn('path "%s" {\n capabilities = ["read"]\n}' % WATCHED, text)
self.assertNotIn("delete", text)
def test_close_mode_adds_only_delete_on_the_same_path(self):
c = ccr()
c["openbao"]["watch"]["mode"] = "close"
self.assertIn('path "%s" {\n capabilities = ["read", "delete"]\n}' % WATCHED, lane.generated_policy_hcl(c))
self.assertIn("openbao.policy_file differs from the policy generated from the CCR", lane.validate(c, ROOT))
def test_validator_rejects_widening(self):
cases = [
("unknown mode", lambda c: c["openbao"]["watch"].update(mode="admin")),
("other mount", lambda c: c["openbao"]["watch"].update(mount="netkingdom")),
("watch itself", lambda c: c["openbao"]["auth"].update(role=c["openbao"]["watch"]["role"])),
("long ttl", lambda c: c["openbao"]["auth"].update(ttl="1h")),
("default policy", lambda c: c["openbao"]["auth"].update(token_no_default_policy=False)),
("extra policy", lambda c: c["openbao"]["auth"]["policies"].append("platform-admin")),
("two accounts", lambda c: c["openbao"]["auth"]["bound_claims"]["service_account_names"].append("x")),
("extra claim", lambda c: c["openbao"]["auth"]["bound_claims"].update(other=["x"])),
("other audience", lambda c: c["openbao"]["auth"].update(audience="kubernetes")),
("staging", lambda c: c["target"].update(environment="staging")),
]
for label, mutate in cases:
with self.subTest(label):
c = ccr()
mutate(c)
self.assertNotEqual(lane.validate(c, ROOT), [], label)
def test_edited_policy_file_is_refused(self):
c = ccr()
with tempfile.TemporaryDirectory(dir=ROOT / "openbao/policies") as tmp:
edited = Path(tmp) / "p.hcl"
edited.write_text(lane.generated_policy_hcl(c) + 'path "platform/*" {\n capabilities = ["read"]\n}\n')
c["openbao"]["policy_name"] = "p"
c["openbao"]["policy_file"] = str(edited.relative_to(ROOT))
self.assertNotEqual(lane.validate(c, ROOT), [])
def _apply(self, mounts):
tmp = Path(tempfile.mkdtemp())
(tmp / "state.json").write_text(json.dumps({"mounts": mounts, "policies": {}, "roles": {}}))
bao = tmp / "bao"
bao.write_text(FAKE_BAO)
bao.chmod(bao.stat().st_mode | stat.S_IEXEC)
os.environ["FAKE_BAO_STATE"] = str(tmp / "state.json")
error = None
try:
lane.run_apply(ccr(), ROOT, str(bao), quiet=True)
except lane.BaoError as exc:
error = exc
return error, json.loads((tmp / "state.json").read_text())
def test_apply_writes_policy_and_role_and_reads_back(self):
error, state = self._apply({"kubernetes/": "kubernetes"})
self.assertIsNone(error)
role = state["roles"]["auth/kubernetes/role/net-kingdom-bounded-executor-window-watch"]
self.assertEqual(role["bound_service_account_names"], ["nk-window-watch"])
self.assertEqual(role["token_policies"], ["net-kingdom-bounded-executor-window-watch"])
self.assertEqual(set(state["policies"]), {"net-kingdom-bounded-executor-window-watch"})
self.assertNotIn(WATCHED, state["roles"]) # the watched role is never written here
def test_apply_refuses_without_the_kubernetes_mount(self):
error, state = self._apply({})
self.assertIsNotNone(error)
self.assertEqual(state["policies"], {})
if __name__ == "__main__":
unittest.main()