Record founder approval of the MAS backup reader.
All checks were successful
CCR intake gate / gate (push) Successful in 3m13s
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

CCR-2026-0062 is approved with the live delivery account confirmed.
The OpenBao policy is not installed and no provider key was created.

Assistant: grok
Assistant-Session: 01a198fa-fd27-7e41-a0a2-57355c3e4efd
This commit is contained in:
codex 2026-11-02 02:37:01 +01:00
parent a274938232
commit 0fb2305def
4 changed files with 184 additions and 34 deletions

View file

@ -4,7 +4,7 @@
"schema_version": 1,
"request_type": "workload-kv-read",
"title": "MAS evidence archive node-delivery reader",
"status": "draft",
"status": "approved",
"created": "2026-11-02",
"updated": "2026-11-02",
"requester": {
@ -17,7 +17,22 @@
"platform-owner",
"mas-owner"
],
"comments": []
"comments": [
{
"at": "2026-11-02T01:35:00Z",
"reviewer": "User (platform-owner)",
"decision": "approved",
"comment": "Founder approved this reader on 2026-11-02. One read policy, ServiceAccount backup-primary-delivery in namespace mas, audience openbao.",
"source_ref": "founder-approval-2026-11-02"
},
{
"at": "2026-11-02T01:35:00Z",
"reviewer": "User (mas-owner)",
"decision": "approved",
"comment": "Founder approved MAS node delivery of this backup pair. The IAM application, pair custody, age escrow, and offsite publication stay separate.",
"source_ref": "founder-approval-2026-11-02"
}
]
},
"target": {
"domain": "communication",
@ -59,13 +74,13 @@
"mas"
]
},
"bound_claims_confirmed": false
"bound_claims_confirmed": true
}
},
"access_frontdoor": {
"type": "platform-owner",
"catalog_id": "mas-backup-primary-delivery",
"readiness": "pending-review",
"readiness": "approved-pending-apply",
"resolvable": false
},
"delivery": {

View file

@ -1,9 +1,10 @@
# MAS evidence publisher grant — 2026-11-02
Prepared for RPF-WP-0070. CCR-2026-0062 is a **draft**. Its Kubernetes binding
is unconfirmed and its delivery admission is false. This packet creates no
provider identity, OpenBao policy, role, or value, ServiceAccount, node file,
offsite upload, or timer.
Prepared for RPF-WP-0070. The founder approved CCR-2026-0062 on 2026-11-02
as platform-owner and mas-owner. The Kubernetes binding is confirmed against
ServiceAccount `backup-primary-delivery` in namespace `mas`, which exists with
automount disabled. Delivery admission is still false. No provider identity,
OpenBao policy, role, or value, node file, offsite upload, or timer exists yet.
The accepted shape is the email-connect ledger reader, CCR-2026-0037. The MAS
prefix is `platform-pg/application-archives/mas/` in bucket
@ -13,14 +14,14 @@ local. It is not an offsite object.
| Item | Prepared value | Live state |
| --- | --- | --- |
| Reader request | CCR-2026-0062 | draft, not approved |
| Reader request | CCR-2026-0062 | approved; not applied |
| KV path | platform/workloads/mas/backup-primary | no value written |
| Fields | AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY | absent |
| Policy | workload-kv-read-mas-backup-primary | source only |
| Policy | workload-kv-read-mas-backup-primary | source only; install is silent and attended |
| Role | mas-backup-primary-workload-kv-read | not created |
| ServiceAccount | backup-primary-delivery in namespace mas | source list only; automount false; no RoleBinding |
| ServiceAccount | backup-primary-delivery in namespace mas | live, automount false, uid c0e5867b-b4be-49b7-94db-6aae0a6e566e; no RoleBinding |
| Node file | /etc/mas-backup/primary.env, root:root 0600, directory 0700 | not created |
| Provider identity | proposed application mas-evidence-backup-primary | not created |
| Provider identity | proposed application mas-evidence-backup-primary | not created; this workstation has no Scaleway credential |
Do not reuse the email-connect publisher or its node file. Object-storage IAM
is not prefix-scoped inside a project, so a later admission needs its own IAM
@ -30,19 +31,23 @@ and is not created here.
## Still required before any offsite copy
1. Founder reviews as platform-owner and mas-owner, with the namespace,
ServiceAccount, and audience confirmed.
2. Create the separate IAM application and prove the prefix boundary, including
denial of sibling prefixes, retained delete, and IAM or bucket administration.
3. Apply the policy and role through the delegated metadata applier. Ops-mason
remains survey-only.
4. Provision the pair atomically with KV CAS=0 under an explicit platform
custody act. The single-field paste desk is unsuitable. Pair-custody and
slot-preparation lists stay closed to coulomb-social and email-connect until
that act.
5. Record positive reader proof and negative denials, then set delivery
admission. Export the admitted CCR and pin its SHA256 before creating the
node file.
1. Founder review is recorded: platform-owner and mas-owner, source
`founder-approval-2026-11-02`. The live account matches the binding.
2. Apply the policy and role with the attended platform-admin login:
`BAO_ADDR=http://127.0.0.1:18200 VAULT_ADDR=http://127.0.0.1:18200 warden access openbao-platform-admin-login --exec -- /home/worsch/railiance-platform/scripts/install-mas-backup-primary-reader.sh`
Sign in as platform-root. The helper is silent and writes only a receipt.
3. In the Scaleway console, create a new IAM application named
`mas-evidence-backup-primary`. Do not add a key to email-connect or to a
broad application. Then say that the application exists. This workstation
has no Scaleway credential, so it cannot create the application or its key.
4. Add three bucket-policy statements for that application, limited to
`platform-pg/application-archives/mas/`, with no object delete. Prove sibling
denial, retained-delete denial, and no IAM or bucket administration.
5. Provision the pair atomically with KV CAS=0 under the pair-writer policy
extended to this one path. The single-field paste desk is unsuitable.
6. Record positive reader proof and negative denials, then set delivery
admission. Export the admitted CCR and pin its SHA256 before creating
`/etc/mas-backup/primary.env`.
Age-identity escrow is a separate custody act. This grant does not move the
workstation private key, and the node must not hold it. TEM and SMTP

View file

@ -0,0 +1,128 @@
#!/bin/sh
# Install the MAS backup-primary reader policy and Kubernetes auth role.
# Silent: warden access rejects any child output. Receipts stay on absolute paths.
# This does not create a provider key, write a KV value, or create a node file.
set -eu
export BAO_ADDR="${BAO_ADDR:-http://127.0.0.1:18200}"
export VAULT_ADDR="${VAULT_ADDR:-http://127.0.0.1:18200}"
receipt_dir=/home/worsch/.local/state/railiance/receipts
umask 077
mkdir -p "$receipt_dir"
stage="$receipt_dir/mas-backup-primary-reader.stage"
: >"$stage"
python3 - "$stage" <<'PY'
import importlib.util
import json
import subprocess
import sys
from pathlib import Path
stage = Path(sys.argv[1])
root = Path("/home/worsch/railiance-platform")
spec = importlib.util.spec_from_file_location(
"credential_change", root / "scripts/credential-change.py"
)
cc = importlib.util.module_from_spec(spec)
spec.loader.exec_module(cc)
name = "CCR-2026-0062-mas-backup-primary.yaml"
safe_role_keys = (
"audience",
"bound_service_account_names",
"bound_service_account_namespaces",
"policies",
"token_explicit_max_ttl",
"token_max_ttl",
"token_no_default_policy",
"token_num_uses",
"token_policies",
"token_type",
"ttl",
)
def run(argv):
result = subprocess.run(argv, cwd=root, capture_output=True)
if result.returncode != 0:
stage.write_text(f"exit {result.returncode} step {argv[1]}\n", encoding="utf-8")
raise SystemExit(result.returncode or 1)
return result.stdout.decode()
ccr = json.loads((root / "credential-change-requests" / name).read_text(encoding="utf-8"))
if ccr.get("status") != "approved" or ccr["openbao"]["auth"].get("bound_claims_confirmed") is not True:
stage.write_text(f"{ccr.get('id')} not approved for apply\n", encoding="utf-8")
raise SystemExit(44)
blockers = cc.applier_readiness_blockers(ccr)
if blockers:
stage.write_text(ccr["id"] + " blocked\n", encoding="utf-8")
raise SystemExit(45)
openbao = ccr["openbao"]
auth = openbao["auth"]
policy_path = root / openbao["policy_file"]
run(["bao", "policy", "write", openbao["policy_name"], str(policy_path)])
installed = run(["bao", "policy", "read", openbao["policy_name"]])
if cc.normalized_policy_body(installed) != cc.normalized_policy_body(policy_path.read_text(encoding="utf-8")):
stage.write_text(openbao["policy_name"] + " readback differs\n", encoding="utf-8")
raise SystemExit(46)
payload = cc.auth_payload(ccr)
role_file = Path(f"/home/worsch/.local/state/railiance/receipts/{auth['role']}.payload.json")
role_file.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n", encoding="utf-8")
role_file.chmod(0o600)
run(["bao", "write", f"auth/{auth['mount']}/role/{auth['role']}", f"@{role_file}"])
raw = run(["bao", "read", "-format=json", f"auth/{auth['mount']}/role/{auth['role']}"])
data = json.loads(raw).get("data", {})
names = data.get("bound_service_account_names")
namespaces = data.get("bound_service_account_namespaces")
policies = data.get("token_policies") or data.get("policies")
audience = data.get("audience") or data.get("audiences")
problems = []
if names != payload["bound_service_account_names"]:
problems.append("names")
if namespaces != payload["bound_service_account_namespaces"]:
problems.append("namespaces")
if policies != payload["policies"].split(","):
problems.append("policies")
if audience not in (payload.get("audience"), [payload.get("audience")]):
problems.append("audience")
if data.get("token_no_default_policy") is not True:
problems.append("no_default")
if data.get("token_num_uses") != 4:
problems.append("uses")
if data.get("token_type") != "service":
problems.append("type")
if data.get("ttl") not in (300, "5m", "300s"):
problems.append("ttl")
if data.get("token_max_ttl") not in (300, "5m", "300s"):
problems.append("max_ttl")
if data.get("token_explicit_max_ttl") not in (300, "5m", "300s"):
problems.append("explicit_max_ttl")
if problems:
observed = {key: data.get(key) for key in safe_role_keys if key in data}
stage.write_text(
json.dumps({"role": auth["role"], "problems": problems, "observed": observed}, indent=2)
+ "\n",
encoding="utf-8",
)
raise SystemExit(47)
receipt = {
"status": "installed",
"id": ccr["id"],
"policy": openbao["policy_name"],
"role": auth["role"],
"policies": policies,
"bound_service_account_names": names,
"bound_service_account_namespaces": namespaces,
"ttl": data.get("ttl"),
"token_max_ttl": data.get("token_max_ttl"),
"token_explicit_max_ttl": data.get("token_explicit_max_ttl"),
"token_num_uses": data.get("token_num_uses"),
"token_no_default_policy": data.get("token_no_default_policy"),
"token_type": data.get("token_type"),
}
out = Path("/home/worsch/.local/state/railiance/receipts/mas-backup-primary-reader.json")
out.write_text(json.dumps(receipt, indent=2) + "\n", encoding="utf-8")
out.chmod(0o600)
PY
if [ -s "$stage" ]; then
exit 48
fi
exit 0

View file

@ -40,7 +40,7 @@ status: progress
priority: medium
needs_human: true
depends_on: [RPF-WP-0053-T05]
intervention_note: "Draft CCR-2026-0062 prepares the MAS prefix publisher. It is not approved or applied. Age-identity escrow is still required before offsite publication."
intervention_note: "Founder approved CCR-2026-0062. The delivery account exists. OpenBao policy/role install still needs the attended platform-admin login, and the IAM application is not created. Age-identity escrow remains separate."
state_hub_task_id: "4f6484fb-8303-5dd5-94cb-b2622e1322c8"
```
@ -61,12 +61,14 @@ The age identity is only on the operator workstation. It is not escrowed,
and nothing was published to `platform-pg/application-archives/mas/`.
The profile is accepted by `scripts/primary_application_archive.py`.
2026-11-02: the prefix publisher is prepared as draft `CCR-2026-0062`.
It names `platform/workloads/mas/backup-primary`, policy
`workload-kv-read-mas-backup-primary`, ServiceAccount
`backup-primary-delivery` in namespace `mas`, and delivery at
`/etc/mas-backup/primary.env`. Bindings are unconfirmed and delivery
admission is false. The IAM application, OpenBao value, live
ServiceAccount, and node file are not created. Pair-custody and
slot-preparation lists still name only coulomb-social and email-connect.
2026-11-02: the founder approved `CCR-2026-0062` as platform-owner and
mas-owner. ServiceAccount `backup-primary-delivery` now exists in
namespace `mas` with automount disabled and no RoleBinding. The binding
is confirmed. Delivery admission stays false. The OpenBao policy and
role are not installed: the local token is denied, so the install waits
for `warden access openbao-platform-admin-login --exec` running
`scripts/install-mas-backup-primary-reader.sh`. No Scaleway credential
is configured here, so IAM application `mas-evidence-backup-primary`
is not created. The KV pair and `/etc/mas-backup/primary.env` do not
exist. Pair-custody lists still name only coulomb-social and email-connect.
Design: `docs/credential-lane-designs/mas-evidence-backup-grant-2026-11-02.md`.