railiance-platform/docs/credential-lane-designs/tenant-engine-audit-core-sender-seed.md
codex bfa99d2e41
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
tenant-engine audit-core sender seed: founder approval recorded (MASON-WP-0007-T05)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 3775@bnt-lap001
Assistant-Session: cfacb6a5-ad5b-4f79-ac67-053e3b0d34a3
2026-10-03 08:35:24 +02:00

95 lines
4.7 KiB
Markdown

# tenant-engine audit-core sender: attended seed
Status: approved, not run. Approved by Bernd Worsch (founder) on 2026-10-03
in the custodian session ("APPROVE MASON-WP-0007-T05"), covering the
three-child sequence below at the reviewed commit e7eb9db. Not run yet. Owner: railiance-platform (OpenBao side) for
ops-mason MASON-WP-0007-T05 (plan row 7). Intake RPF-IN-0002. Prepared
2026-10-03 under CUST-WP-0075.
## What the founder approves
One attended sitting, run from a railiance-platform checkout at the reviewed
commit, with these three children in order. Each child prints nothing; read
warden's printed line, not its exit code (orientation §5).
```sh
cd ~/railiance-platform
export BAO_ADDR=http://127.0.0.1:18200 VAULT_ADDR=http://127.0.0.1:18200
# 1. policy + Kubernetes-auth role (commit 8c44256). Exit 3 = existing object differs.
warden access openbao-platform-admin-login --exec -- \
sh scripts/openbao-tenant-engine-audit-core-sender-eso-attended.sh
# 2. seed dry-run: KV metadata only, no value read or written.
warden access openbao-platform-admin-login --exec -- \
python3 scripts/tenant_engine_audit_core_sender_seed.py --dry-run \
--confirm 'SEED tenant-engine audit-core-sender' \
--receipt docs/evidence/tenant-engine-sender-seed-dry-run.json
# 3. seed: only if step 2's receipt says outcome dry_run_would_write (exit 0).
warden access openbao-platform-admin-login --exec -- \
python3 scripts/tenant_engine_audit_core_sender_seed.py \
--confirm 'SEED tenant-engine audit-core-sender' \
--receipt docs/evidence/tenant-engine-sender-seed.json
```
Each `warden access` is its own login. Receipts are created mode 0600, refused
if the file exists, and hold only paths, versions, booleans and an outcome
code. Commit them as evidence.
## What the seed does
`scripts/tenant_engine_audit_core_sender_seed.py` is the user-engine /
audit-core wrap-migrate technique (ops-mason
`plans/user-engine-openbao-runtime-custody.md` §6; audit-core runbook,
"wrap-migrated on 2026-08-14"): one platform-admin process reads the source and
writes the target, and the value travels only through process memory and the
`bao` child's stdin. Never argv, stdout, stderr, a file or the receipt.
1. Refuses unless `--confirm` is exact, HOME is a warden attended envelope, no
`BAO_TOKEN`/`VAULT_TOKEN` is set, and the identity has `platform-admin` and
not `root`.
2. Reads `platform/workloads/audit-core/senders` (KV v2, field `senders.json`)
and selects the one row named `tenant-engine`. Refuses if the row is
missing or duplicated, holds zero or more than one token (a rotation
overlap is in progress: finish it first), or is not write-only
(`may_write` true, `may_read` false).
3. If `platform/workloads/tenant-engine/audit-core-sender` exists: exit 0 when
it holds exactly `{token: <that token>}`, otherwise exit 3. Never overwrites.
4. Otherwise writes `{token}` with `cas=0`, reads it back (must be version 1 and
equal), and checks that the registry version did not move during the run.
The registry is never written. Exit codes: 0 ok (written or already
identical; dry-run: would write), 1 contained internal error, 2 precondition
refused before any write, 3 target exists and differs, 4 write failed,
5 verify failed, 6 dry-run found the target already present.
Tests: `tests/test_tenant_engine_audit_core_sender_seed.py` runs the helper as
a subprocess against a fake `bao` and asserts empty stdout/stderr, the token
never in `bao` argv or the receipt, CAS 0, idempotence, refusal of a differing
or deleted target, every precondition, and distinct write/verify codes.
## Operator check for MASON-WP-0007-T06 (read-only, not run)
Before the tenant-engine ClusterSecretStore goes live, the ESO controller must
be allowed to create ServiceAccount tokens in `tenant-engine`. Confirm the node
IP is `92.205.62.239` first (`kubectl get nodes -o wide`), then:
```sh
kubectl auth can-i create serviceaccounts --subresource=token \
-n tenant-engine --as=system:serviceaccount:external-secrets:external-secrets
```
`yes` is required. This is a SubjectAccessReview: it reads no object. A `no`
is a railiance-cluster RBAC matter, not a reason to widen the OpenBao role.
## Follow-ups outside the seed
- `openbao/policies/agent-high-risk-boundary.hcl` denies coding agents the
sender registry, but not the new
`platform/{data,metadata}/workloads/tenant-engine/audit-core-sender` paths.
Adding those deny lines is a separate reviewed policy change.
- Rotation stays overlap-first (plan §4): rotate in the registry, finish the
overlap so the sender holds one token, then re-seed. Because this helper
never overwrites, a rotated token needs a reviewed CAS-update variant. That
variant is not built.