--- id: RPF-WP-0067 type: workplan title: "NetKingdom owner answers: execution-attribution receipt emitter and service-identity metadata export" domain: financials repo: railiance-platform status: active flavor: implementation owner: claude created: "2026-10-28" updated: "2026-10-28" related: - NK-WP-0040 - NK-WP-0054 - AUDIT-WP-0014 state_hub_workstream_id: "b69630d9-5efb-511b-aa0d-346a372a113a" --- # RPF-WP-0067 — NetKingdom owner answers (NK-WP-0040-T02, NK-WP-0054-T04) Receiving workplan for two NetKingdom briefs (State Hub messages `521e3dba-59db-46a8-ae7a-fa8ae2a4c9a7` and `f5d366f5-853f-4d3c-9570-a3275d27df25`). Answers are from railiance-platform source only. No live, cluster or OpenBao action was taken; no Secret value was read. ## Answer the execution-attribution receipt emitter questions ```task id: RPF-WP-0067-T01 status: done priority: high state_hub_task_id: "38db40fd-e42b-5a9b-8b67-9da593acafd2" ``` Question source: net-kingdom `canon/standards/playbook-capability-contract_v0.2.md` §"Execution Attribution Receipt (proposed)"; audit-core admission requirements in audit-core `docs/cross-repo-evidence-admission.md` §"Execution-attribution receipts — AUDIT-WP-0014". Emission is not implemented here. 1. **Emitting component — not confirmable from this repository; none exists.** railiance-platform contains no Railiance playbook runner or executor and no `PlaybookCapability` declaration (search of `scripts/`, `tools/`, `lib/`, `helm/`, `argocd/`, `Makefile`: the only `playbook` hits are unrelated). The contract's reference declaration is `railiance-infra/capabilities/playbooks/railiance-infra.bootstrap-host.yaml` (S1 Ansible; contract v0.2 lines 375-385), and the contract itself says "a separate playbook runner" executes (line 261). railiance-platform is the S3 platform-services layer; the emitter must be named by the repository that owns the runner (railiance-infra for S1; S2/S4 owners for theirs). This repo should not be recorded as the emitter. 2. **Wire binding — what this repo can state.** The only audit-core sender binding in this repo is the existing event-sender pattern, which a future emitter should reuse rather than invent: - transport: HTTP `POST /v1/events` to in-cluster `http://audit-core.audit-core.svc.cluster.local:8080` (`scripts/native_factory_acceptance.py` line 48, `scripts/native_factory_probe/producer.py` lines 30-36, 127); - idempotency: `Idempotency-Key` header equal to the envelope `id`, with `correlation_id` carrying the run id (`producer.py` lines 33-34, 130, 174-176); - sender identity: a per-sender bearer from the audit-core sender registry at OpenBao `platform/workloads/audit-core/senders`, projected by ESO to a mounted credential file (`producer.py` line 31; `scripts/audit_core_synthetic_sender_lane.py` docstring); the envelope `source` must equal the sender name, tenant is declared; - signing: none at the message level. Authenticity is the bearer plus audit-core's own chaining; no detached or per-receipt signature exists in this repo. A playbook-runner sender identity does not exist in the registry; adding one is a CCR through this repo once the runner owner names the sender. 3. **When emitted — not confirmable.** No emitter exists, so no success/failure/ partial guarantee exists. Recommendation for the runner owner: emit on every terminal outcome (success, failure, partial/aborted) with a stable `run_id` as the idempotency key, and record absence of a receipt as an explicit gap. 4. **Fields a platform-side emitter could not populate truthfully today:** `initiator.iss`/`initiator.sub` and `delegation` (runs are started by an operator shell or ssh; no IAM Profile token is presented to a runner); `executing_workload` (Tenancy Posture `workload_identity` is still proposed); `artifact_digest` for Ansible runs (no packaged artifact; would need a computed tree digest); `decision_refs` (no machine link from CCR/approval records to a run); `time_interval.bound` (no established skew bound, so it must stay absent). `runtime_principal`, `tenant`, `environment`, `run_id`, `source_commit`, `target`, `action`, `time_interval.start/end/clock_source` are populatable by a runner that records them. Open: runner owner (railiance-infra and any S2/S4 runner) names the emitter; NetKingdom ships the receipt schema; audit-core implements AUDIT-WP-0014-T02. ## Provide value-safe OpenBao and PostgreSQL identity metadata ```task id: RPF-WP-0067-T02 status: done priority: high state_hub_task_id: "5b35310f-3aaa-5657-8983-d1279ffb55bd" ``` `scripts/service_identity_metadata_export.py` (tests: `tests/test_service_identity_metadata_export.py`, `make service-identity-metadata-tests`). Output schema `railiance-platform.service-identity-metadata.v1`. OpenBao: auth mounts, allowlisted role fields (bound claims/audiences/subject, service-account bindings, token policies, TTLs in seconds, token type/uses), policy rules and their SHA-256, and per-role `effective_rules` (exact paths merged, deny wins). PostgreSQL: `pg_roles` attributes, memberships and database owners. Role-ids, secret-ids, KV data, `pg_authid` and passwords are never read; secret-shaped output refuses the export and reports only a count. Proven from source for net-kingdom `tools/service-identity/declarations/openbao.yaml`: - `fluid-telegram-operators` grants: `openbao/auth/fluid-telegram-hall-of-helix-oidc-role.json` lines 12-20 and `openbao/policies/workload-kv-fluid-telegram-hall-of-helix-operator.hcl` lines 1-16 — read/create/update on four exact KV data entries under `platform/workloads/coulomb/fluid-telegram/hall-of-helix/`, no metadata, list or delete, 15-minute token, 30-minute explicit max. - `coding-agent` grants: `openbao/auth/coding-agent-jwt-role.json` lines 14-19 and `openbao/auth/coding-agent-approle.json` lines 5-11 attach `agent-high-risk-boundary` and `workload-kv-read-issue-core-runtime`; the boundary denies the same data path the second policy grants (`agent-high-risk-boundary.hcl` line 25 vs `workload-kv-read-issue-core-runtime.hcl` line 1), and deny wins. Effective: no KV data read; metadata read only where the boundary allows it; token self-lookup/revoke and `sys/capabilities-self`. - `coding-agent` `agent.mode`: not provable. The JWT role binds no agent-mode claim (`coding-agent-jwt-role.json` lines 8-13) and accepts `principal_type` `service` or `agent` (line 10). The mode is issued by KeyCape (KEY-WP-0043). ## Run the live export (founder) ```task id: RPF-WP-0067-T03 status: wait priority: medium blocking_reason: "Live read-only export needs the founder's OpenBao platform-admin login and cluster access." state_hub_task_id: "23ea4894-120a-556e-bf24-4b01cb2ddcfb" ``` ```bash cd ~/railiance-platform bridge up openbao-ui-railiance01 BAO_ADDR=http://127.0.0.1:18200 VAULT_ADDR=http://127.0.0.1:18200 \ warden access openbao-platform-admin-login --exec -- \ python3 scripts/service_identity_metadata_export.py \ --output ~/nk-wp-0054-t04-openbao-identity-metadata.json openbao SQL="$(python3 scripts/service_identity_metadata_export.py postgresql-sql)" P=$(ssh railiance01 kubectl -n databases get cluster net-kingdom-pg -o jsonpath='{.status.currentPrimary}') ssh railiance01 "kubectl -n databases exec $P -c postgres -- psql -U postgres -d postgres -AtX -c $(printf %q "$SQL")" \ | python3 scripts/service_identity_metadata_export.py \ --output ~/nk-wp-0054-t04-postgresql-identity-metadata.json postgresql --cluster net-kingdom-pg ``` Exit 0 writes the file; exit 3 means a secret-shaped value was found and nothing was written; exit 2 is a read failure. Return both JSON files to NetKingdom; they hold no secret values.