Files
alknet/docs/architecture/questions/064-client-side-tls-helper.md
T
glm-5.2 bf6ce957c0 docs(arch): tighten tls/endpoint/client specs — remove connect/connect_quic, move CallCredentials to core, shed alknet-call TLS deps
Review of the three new crates (alknet-tls, alknet-endpoint, alknet-client)
+ revised core found compile-blocking inconsistencies, stale claims, and
dep-graph contradictions. All resolved:

Critical:
- C1: CallClient::connect / ChannelClient::connect_quic REMOVED (not
  delegated) — keeping them as thin wrappers over AlknetClient::dial_quic
  would make protocol crates depend on alknet-client, contradicting the
  dep graph. Callers compose dial + take-over (2 lines).
- C2: alknet-client feature gates now pull alknet-core/quinn +
  alknet-core/iroh (for Connection::from_quinn_with_alpn / from_iroh).
- C3: rustls-native-certs + webpki-roots added to alknet-tls deps
  (always-present, not feature-gated — CA-verify path is transport-agnostic).

Warning:
- W1: CallCredentials/RemoteIdentity moved to alknet-core (from
  alknet-call) — the dial must not depend on the call protocol; not a
  two-way-door, it determines the dep graph.
- W2: webpki-roots fallback implemented in spec (ADR-088 §5 added) —
  the code claimed a fallback that never existed; now the store is never
  empty, NoRootAnchors unreachable, containerized deployments work.
- W3: EndpointError removed entirely (BindFailed + HandlerNotFound both
  vestigial after ADR-083); shutdown() is now infallible.
- W4: FingerprintPinVerifier moved to alknet-tls (from alknet-call) —
  alknet-call sheds quinn/rustls/rustls-pemfile/rustls-native-certs
  entirely; CallClient becomes a pure protocol crate.

Plus: ClientError removed (only produced by removed connect); S1
(CallCredentials → ClientVerifierContext mapping + auth_token stripped
at TLS boundary documented); amendment notes on ADR-017, ADR-069,
ADR-080, ADR-082, ADR-087, ADR-090; overview crate graph + README index
updated.

29 files, consistency-reviewed.
2026-07-16 11:33:18 +00:00

62 lines
3.5 KiB
Markdown

# OQ-64: Should `alknet-tls` Provide a Client-Side TLS Config Helper?
- **Origin**: `docs/architecture/crates/tls/README.md` (the "Server-only
for now" section flagged this as deferred); ADR-084 (requires the
client-side `rustls::ClientConfig` to use the same `aws_lc_rs`
provider — previously enforced by convention, not shared code).
- **Status**: resolved
- **Door type**: one-way (`TlsClientConfig` as the shared client-side
TLS config in `alknet-tls` is structural — every outbound-dialing
crate depends on it. Reversing would re-distribute verifier selection
+ provider wiring across crates.)
- **Priority**: high (upgraded from medium — the hub-as-client
requirement makes this a prerequisite for the first hub deployment,
not a future extraction)
- **Resolution**: **Yes. `alknet-tls` provides `TlsClientConfig`.** It
is not blocked on the dial-seam extraction (OQ-55).
The previous deferral linked OQ-64 and OQ-55 as "the same seam,"
creating a circular dependency: the TLS config is deferred behind the
dial, but the dial needs the TLS config. The circle is broken by
separating the two concerns:
1. **`TlsClientConfig`** — the `rustls::ClientConfig` + ADR-034
verifier selection + ADR-084 crypto provider. Transport-agnostic.
All decisions are made. Buildable today. It is a **prerequisite**
for any dial, not a consequence of it.
2. **The dial** (`AlknetClient::dial()`) — transport-specific
connection establishment. Extracting a transport-polymorphic dial
from one shape (QUIC) would bake QUIC in. **Legitimate deferral
(OQ-55, unchanged).**
`TlsClientConfig::new` takes a verifier context (the inputs to
ADR-034's rule: `PeerEntry` presence, expected fingerprint, remote
cert type) and returns a `rustls::ClientConfig`. The caller
(transport-specific dial helper — now `AlknetClient::dial_quic` /
`dial_tcp_tls` per ADR-089; the per-protocol `CallClient::connect` /
`ChannelClient::connect_quic` convenience constructors are removed
per ADR-089 §5) passes it to the transport's connector. Iroh is
the exception — it has its own TLS and does not consume a
`rustls::ClientConfig`; the iroh dial helper applies the same
ADR-034 rule via iroh's `NodeId` verification API.
The hub makes this non-optional: a hub dials out to workers it
supervises and to other hubs (hub-as-client). The hub's
`dial_worker_connection` / `supervise_worker` need a
`TlsClientConfig` for the outbound dial. The first hub deployment
(web + native) dials workers over QUIC with the worker's fingerprint
pinned. There is no "later" — it is on the critical path for the
first hub and for `alknet-worker`.
See [ADR-087](../decisions/087-tlsclientconfig-not-blocked-on-dial.md)
for the full decision, including the circular-hedge analysis, the
hub-as-client requirement, and the iroh exception.
- **Cross-references**: [ADR-087](../decisions/087-tlsclientconfig-not-blocked-on-dial.md)
(the decision), [ADR-034](../decisions/034-outgoing-only-x509-and-three-peer-roles.md)
§3 (verifier selection — the rule `TlsClientConfig::new`
centralizes), [ADR-084](../decisions/084-aws-lc-rs-crypto-provider.md)
(provider consistency — enforced by code, not convention, for the
client side), [ADR-082](../decisions/082-alknet-tls-extraction.md)
(`TlsServerConfig` — the server-side analogue), OQ-55 (the dial seam
— remains deferred; this OQ's resolution does not affect it),
OQ-63 (`TlsError` shape — now covers both server and client variants)