From 3bd3a2e87bb28d3baae10f79ce25c1db19295f3e Mon Sep 17 00:00:00 2001 From: codex Date: Tue, 15 Sep 2026 23:13:13 +0200 Subject: [PATCH] Record verified production Clock custody and authority acceptance Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a09cbb-87c6-7900-a145-4ce53ba9f1a6 --- ...028-railiance-clock-authority-signing.yaml | 17 ++++++-- .../railiance-clock-host-delivery.md | 20 +++++++++ ...26-09-15-railiance-clock-host-custody.json | 15 +++++++ ...2026-09-15-railiance-clock-production.json | 42 +++++++++++++++++++ scripts/credential-change.py | 16 ++++--- 5 files changed, 102 insertions(+), 8 deletions(-) create mode 100644 docs/evidence/2026-09-15-railiance-clock-host-custody.json create mode 100644 docs/evidence/2026-09-15-railiance-clock-production.json diff --git a/credential-change-requests/CCR-2026-0028-railiance-clock-authority-signing.yaml b/credential-change-requests/CCR-2026-0028-railiance-clock-authority-signing.yaml index bfe98ab..59eaa80 100644 --- a/credential-change-requests/CCR-2026-0028-railiance-clock-authority-signing.yaml +++ b/credential-change-requests/CCR-2026-0028-railiance-clock-authority-signing.yaml @@ -3,7 +3,7 @@ kind: credential-change-request schema_version: 1 request_type: attended-host-key-delivery title: Railiance Clock authority signing key custody and host delivery -status: approved +status: verified created: '2026-09-15' updated: '2026-09-15' requester: @@ -53,7 +53,7 @@ openbao: access_frontdoor: type: attended-host-file catalog_id: openbao-platform-admin-login - readiness: approved-pending-apply + readiness: ready resolvable: false delivery: surface: attended-host-file @@ -93,7 +93,18 @@ verification: host key verification is required. - Fresh public key, artifact SHA256, readiness and signed sample acceptance are recorded. - evidence: [] + evidence: + - kind: attended_host_custody + result: passed + receipt: docs/evidence/2026-09-15-railiance-clock-host-custody.json + details: OpenBao KV version 1 and matching public-key fingerprint on private host + file; contained login, child operation and self-revocation succeeded. + - kind: production_authority_acceptance + result: passed + receipt: docs/evidence/2026-09-15-railiance-clock-production.json + details: Active/enabled private authority; pinned wheel; bounded host health; + three signed workstation samples cross-checked through SSH, wrong key id refused. + No standing workload read grant. lifecycle: deactivate: Stop authority and withdraw consumer trust. Retain custody and host key until owner retention decision. diff --git a/docs/credential-lane-designs/railiance-clock-host-delivery.md b/docs/credential-lane-designs/railiance-clock-host-delivery.md index ef3cdf9..48f759d 100644 --- a/docs/credential-lane-designs/railiance-clock-host-delivery.md +++ b/docs/credential-lane-designs/railiance-clock-host-delivery.md @@ -34,3 +34,23 @@ Rotation is a separate explicit operation: stop the authority, CAS against the known current custody version, replace the host key atomically, and distribute new public key/epoch trust before resuming clients. This initial-admission helper deliberately does not implement rotation or overwrite keys. + +## Accepted production deployment + +Version 1 custody and native workstation samples passed on 2026-09-15. See +`docs/evidence/2026-09-15-railiance-clock-host-custody.json` and +`docs/evidence/2026-09-15-railiance-clock-production.json`. +Use the documented private OpenBao endpoint `http://127.0.0.1:18200` for the +attended envelope: the configured public hostname presented an untrusted +certificate during deployment. TLS verification was not disabled. + +Authority endpoint on Railiance01: `http://127.0.0.1:8787/v1/time-samples`; +readiness: `http://127.0.0.1:8787/readyz`. Workstations use an authenticated SSH +loopback connection and separately admitted public key/epoch. Trust files last +at most 15 minutes and do not survive a workstation boot. Optional integrations +are not globally enabled by this deployment; operational trust refresh remains +in RCLK-WP-0005-T06 and consumer adoption in RCLK-WP-0004. + +The health export sandbox allows read-only adjtimex, which ProtectClock would +block even with modes=0. Empty bounding/ambient capability sets deny clock writes. +The authority keeps ProtectClock enabled. diff --git a/docs/evidence/2026-09-15-railiance-clock-host-custody.json b/docs/evidence/2026-09-15-railiance-clock-host-custody.json new file mode 100644 index 0000000..7e22ef5 --- /dev/null +++ b/docs/evidence/2026-09-15-railiance-clock-host-custody.json @@ -0,0 +1,15 @@ +{ + "schema": "platform.railiance-clock-host-custody.v1", + "status": "delivered_pending_authority_acceptance", + "stage": "complete", + "ccr": "CCR-2026-0028", + "kv_version": 1, + "kid": "railiance01-clock-20260915-v1", + "public_key_pem": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE6dgMrD13yE5PKBxDSl7ledal2vwd\nDmPZEjdYW8UK48Abto6dfuJfjCHeC+Jl3w1D5VZLfbbzD114ymKTszE80A==\n-----END PUBLIC KEY-----\n", + "public_key_sha256": "bd583446b5ed61d086806b2a0c5aaf33a875b751e45599e75335d1f415be609a", + "host": { + "public_key_sha256": "bd583446b5ed61d086806b2a0c5aaf33a875b751e45599e75335d1f415be609a", + "owner": "railiance-clock", + "mode": "0600" + } +} diff --git a/docs/evidence/2026-09-15-railiance-clock-production.json b/docs/evidence/2026-09-15-railiance-clock-production.json new file mode 100644 index 0000000..2dcd562 --- /dev/null +++ b/docs/evidence/2026-09-15-railiance-clock-production.json @@ -0,0 +1,42 @@ +{ + "scope": "production authority acceptance", + "host": "railiance01", + "client": "Linux/WSL via SSH loopback", + "os_clocks_changed": false, + "samples": [ + { + "width_ms": 101.667802, + "railiance_minus_local_midpoint_ms": 253.602519, + "independent_host_cross_check": true + }, + { + "width_ms": 108.062875, + "railiance_minus_local_midpoint_ms": 325.159405, + "independent_host_cross_check": true + }, + { + "width_ms": 160.436282, + "railiance_minus_local_midpoint_ms": 371.73663, + "independent_host_cross_check": true + } + ], + "wrong_kid_refused": true, + "epoch": "b1164ccb-a4c2-4cc8-adf8-1d5597de697b", + "kid": "railiance01-clock-20260915-v1", + "public_key_sha256": "bd583446b5ed61d086806b2a0c5aaf33a875b751e45599e75335d1f415be609a", + "trust_lifetime_seconds": 900, + "wheel_sha256": "89d1419f038eff485a27a4206a19101ce7ca2976092971bbc796a77188fc93ad", + "listener": "127.0.0.1:8787", + "service_active": true, + "service_enabled": true, + "authority_clock_write_capabilities": [], + "health_clock_write_capabilities": [], + "readiness": "usable", + "key_custody": "CCR-2026-0028 version 1", + "final_ansible_convergence": { + "ok": 29, + "changed": 0, + "failed": 0, + "unreachable": 0 + } +} diff --git a/scripts/credential-change.py b/scripts/credential-change.py index b3fc654..9c28c9a 100755 --- a/scripts/credential-change.py +++ b/scripts/credential-change.py @@ -493,7 +493,7 @@ def render_summary(ccr: dict[str, Any], warnings: list[str]) -> str: f" {openbao['kv_path']}", f" {fields}", "Policy:", - f" {openbao['policy_name']}", + f" {openbao.get('policy_name', 'none (attended host delivery)')}", "Auth binding:", ] if auth.get("method") == "token": @@ -664,6 +664,8 @@ def auth_payload(ccr: dict[str, Any]) -> dict[str, Any]: def render_plan(ccr: dict[str, Any]) -> str: + if ccr.get("request_type") == "attended-host-key-delivery": + return "Use docs/credential-lane-designs/railiance-clock-host-delivery.md through the attended owner procedure. No workload policy or auth role is created." openbao = ccr["openbao"] auth = openbao["auth"] payload = auth_payload(ccr) @@ -693,6 +695,8 @@ def render_plan(ccr: dict[str, Any]) -> str: def render_operator_commands(ccr: dict[str, Any]) -> str: + if ccr.get("request_type") == "attended-host-key-delivery": + return "Use docs/credential-lane-designs/railiance-clock-host-delivery.md through the attended owner procedure. No workload policy or auth role is created." openbao = ccr["openbao"] auth = openbao["auth"] auth_path = f"auth/{auth['mount']}/role/{auth['role']}" @@ -898,7 +902,7 @@ def applier_dry_run_payload(ccr: dict[str, Any], warnings: list[str]) -> dict[st { "kind": "policy_write", "openbao_path": f"sys/policies/acl/{openbao['policy_name']}", - "policy_name": openbao["policy_name"], + "policy_name": openbao.get("policy_name"), "source": openbao["policy_file"], "body": generated_policy_hcl(ccr).rstrip(), }, @@ -998,6 +1002,8 @@ def render_applier_apply_plan(ccr: dict[str, Any], warnings: list[str]) -> str: def runbook_readiness_blockers(ccr: dict[str, Any]) -> list[str]: + if ccr.get("request_type") == "attended-host-key-delivery": + return ["use the attended owner procedure in docs/credential-lane-designs/railiance-clock-host-delivery.md"] blockers: list[str] = [] status = ccr.get("status") if status not in RUNBOOK_ALLOWED_STATUSES: @@ -1281,7 +1287,7 @@ def lifecycle_payload(ccr: dict[str, Any], action: str) -> dict[str, Any]: "openbao": { "secret_path": openbao["kv_path"], "fields": openbao["fields"], - "policy_name": openbao["policy_name"], + "policy_name": openbao.get("policy_name"), "auth_role_path": auth_role_path, "disable_commands": disable_commands, }, @@ -1627,7 +1633,7 @@ def status_payload(ccr: dict[str, Any], warnings: list[str]) -> dict[str, Any]: "mount": openbao["mount"], "kv_path": openbao["kv_path"], "fields": openbao["fields"], - "policy_name": openbao["policy_name"], + "policy_name": openbao.get("policy_name"), "auth_mount": auth.get("mount"), "auth_method": auth.get("method"), "auth_role": auth.get("role"), @@ -1783,7 +1789,7 @@ def decision_template_context(ccr: dict[str, Any]) -> dict[str, str]: return { "id": ccr["id"], "kv_path": openbao["kv_path"], - "policy_name": openbao["policy_name"], + "policy_name": openbao.get("policy_name"), "auth_role_path": f"auth/{auth['mount']}/role/{auth['role']}", "decision_link": state_hub.get("decision_api_url") or state_hub.get("decision_dashboard_url")