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

4.7 KiB

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).

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:

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.