railiance-clock/docs/implementation-review-2026-09-15.md
tegwick 9892c81ed6 Implement authenticated Railiance application clock
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a09cbb-87c6-7900-a145-4ce53ba9f1a6
2026-09-15 22:16:23 +02:00

91 lines
5.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Online Clock implementation and consumer review — 2026-09-15
The operator requested time infrastructure and relevant consumer integration in
the SECRETS-WP-0010 session. This document specifies the concrete implementation
for review and deployment. No expiry field, human approval or OS clock is changed.
## Implemented profile
The existing ES256/JWS profile is implemented with PyJWT/cryptography, closed
schemas, exact key/authority/environment/epoch/policy/nonce binding, bounded HTTP
bodies, disabled redirects/proxies and a fresh online exchange for every read.
The client uses Linux CLOCK_MONOTONIC and CLOCK_BOOTTIME; elapsed bounds include
the extrema of both observations and configured drift/resolution allowances.
Suspend disagreement beyond policy tolerance refuses; smaller disagreement is
included in uncertainty. A boot-bound local trust admission expires by BOOTTIME,
including across process restart. New processes cannot reset that deadline.
The private authority is proposed as a host systemd service for the initial pilot:
it needs a root-owned host-health export, existing SSH transport and no cluster
capacity. This avoids a privileged pod or host DBus mount and uses the existing
S1 owner, not a new execution rail. It listens only on 127.0.0.1:8787, has no
capabilities and cannot change the host clock. The health exporter is separately
sandboxed, has no capabilities, and reads adjtimex with modes=0.
A fresh random epoch is generated for every authority process. Clients pin the
admitted epoch and refuse a restart until a new owner admission. Persistent
client rollback state is required, privately owned and flock-serialized; missing,
corrupted or older state refuses. Admission recreates that state only through an
explicit reviewed recovery; the runtime never repairs it automatically.
## UTC and timer assumptions requiring native acceptance
The proposed initial model trusts the existing Linux discipline and the explicitly
admitted ntp.ubuntu.com source. It requires TIME_OK, no UNSYNC or pending leap,
timesyncd synchronization and a nonignored normal-leap source observation.
Kernel maxerror/esterror plus a 10ms measurement margin and collection/sample
aging supply a conservative bound **conditional on the discipline's accounting
and trusted upstream**. This is not independent-source consensus or proof against
a compromised host/upstream. It deliberately does not call endpoint count or a
synchronization flag an independently measured accuracy bound.
Candidate online limits: kernel-derived error <=500ms, health age <10s, sample
age <5s, RTT <2s, interval width <=3s, timer allowance 1000ppm plus 5ms resolution,
suspend disagreement <=5ms and trust admission <=15 minutes. The 1000ppm allowance
is a declared platform assumption, not a proven bound for every VM. Native pilot
acceptance must record timer behavior and the supported platform. Unknown/frozen
VM timer behavior is not licensed for protected offline use. No holdover is enabled.
The authority's continuity monitor latches refusal after a 50ms wall/monotonic
mapping change. Leap or continuity ambiguity requires fresh health and new epoch
admission; old trust cannot make it usable.
The host role retains timesyncd. Clock configuration management and authority
activation are separate explicit opt-ins; default inclusion in bootstrap changes
nothing. The proposed 32–64s poll interval improves health recency; introducing
new upstream operators is outside this initial source-preserving rollout.
## Consumer adoption
Secrets Engine uses SECRETS_ENGINE_CLOCK_TRUST_FILE as an explicit configuration.
A configured but missing/unusable Clock refuses. Its validators require the lower
bound to reach not-before and upper bound to remain strictly before expiry and
claim freshness. It rechecks decision validity before and after CAS consumption.
Wrong actor/tenant/binding/policy checks and server-side CAS remain unchanged.
No configured clock means the existing disciplined-host OS validation path.
The optional wheel is reusable; no vendored second clock implementation.
Authority-side Flex Auth, Approval Engine, KeyCape and OpenBao already run on the
host's disciplined clock: they should continue validating locally rather than
adding a dependency on their own Clock endpoint. Third-party TLS, Kerberos,
browser/OIDC and SSH validity checks are not rewritten by this adapter.
Ops Warden local audit timestamps and Intelligence Radar ingestion/trial timestamps
are observations. Their relevant adoption is additive interval attribution;
retain original local timestamps and monotonic durations. Authentication and
spending contracts stay with their current owners. Native activation is separate
from the existence of an optional adapter.
## Custody and activation boundary
The authority key must arrive through platform-owned admitted custody; the Ansible
role accepts only an explicit private source file with no_log and requires a
source hash plus an admission reference. It never generates a production key or
widens a KV grant. A disposable native test key establishes test evidence only.
Client public-key/epoch admission uses an authenticated owner transport, not the
untrusted sample under examination. Signing-key rotation/revocation invalidates
all affected trust files; maximum trust lifetime is 15 minutes and no clock read
renews it. Runtime liveness is separate from /readyz time usability.
Live deployment still needs exact source/artifact/custody receipts, native failure
and recovery checks, idempotent convergence and explicit supported-platform
acceptance. RCLK-WP-0002/0004/0005 remain open until those records exist.