Mesh command/ack planes are h2c-only — the per-cluster PSK crosses the network in cleartext on a write surface (accept, or add a UseTls option) #545
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The two mesh planes introduced by the ClusterClient→gRPC migration are h2c (cleartext HTTP/2) only, and their authentication is a per-cluster pre-shared key carried in an
authorization: Bearerheader. So the PSK crosses the network in cleartext on every call, and — unlike the three planes that precede it — the surface it opens is a write surface.What is exposed.
mesh_transport.v1.NodeCommandService/Executeon each driver node's telemetry listener (:4056), gated byMeshCommandAuthInterceptoragainstMeshTransport:GrpcPsk. Anyone who can read one call off the wire can afterwards restart drivers, acknowledge alarms and dispatch deployments to every node in that cluster.mesh_transport.v1.CentralCommandService/ReportApplyon the ConfigServe listener (:4055), gated byCentralCommandAuthInterceptoragainst the per-cluster key fromIMeshPskProvider. Capturing that key lets a caller forge deployment acks.Both dial via
GrpcChannel.ForAddress("http://…")(MeshGrpcCommandDialer,GrpcApplyAckSender) and are configured withhttp://endpoints (MeshTransport:CentralGrpcEndpoints,ClusterNode.Host+GrpcPort).This is precedent-consistent, not a regression. The three existing cross-mesh gRPC planes — telemetry stream (Phase 5), config-serve/artifact fetch (Phase 3) and LocalDb pair sync — are all h2c with a shared-bearer interceptor, on the same trusted-site-link assumption. Per-cluster keys already bound the blast radius to one cluster (a compromised SITE-A key cannot drive SITE-B), which is strictly better than the fleet-wide-key alternative that was rejected in the design.
Decision needed (it is deliberately not being taken inside the migration program, which is a like-for-like transport swap):
UseTls/ scheme option toMeshTransport(and, for consistency, to the sibling planes) so an operator on an untrusted link can move both mesh planes tohttps://with a server certificate. That is a per-plane options + validator + rig-config change, and it should be done for all five planes together or not at all — a mixed posture where two planes are TLS and three are not is harder to reason about than either uniform answer.Note that the honest scope of a TLS flip is wider than the two new planes: doing only the mesh planes would leave the same key material class (
Telemetry:ApiKey,ConfigServe:ApiKey, LocalDb sync key) still in cleartext on the same links.Filed from the ClusterClient→gRPC Phase 1A live gate (
docs/plans/2026-08-06-clusterclient-to-grpc-tracking.md§ Issues filed by this program; raised in the 1A.2 Opus code review as a non-blocking follow-up).Resolved by recording the accepted posture — option 1, merged to
master@1df84703and pushed (commit17a822b7, docs-only).Decision: accept the risk and record it once, for all five planes. New subsection in
docs/security.mdunder Transport Security: "Internal gRPC planes (h2c) — accepted cleartext posture", containing the five-plane table (service, listener config key, auth key, interceptor), an honest read/write characterization (telemetry + config-serve are read-planes; LocalDb sync writes the node's boot cache; the two mesh planes are command/write surfaces — a three-way split, sharper than this issue's two-way framing), the trusted-link assumption, the per-cluster blast-radius bound (OT-MESH-PSK-<clusterId>via${secret:}; dev keys enumerated), and the recorded alternative: a UseTls/scheme option must cover all five planes together or not at all.docs/Configuration.md's MeshTransport section cross-links it.A dedicated docs-accuracy review verified every claim against source: proto service names, the
Program.cslistener-sharing claims (NodeCommandService on theTelemetry:GrpcListenPortlistener, CentralCommandService onConfigServe:GrpcListenPort), options-class key names,MeshPskProvider.SecretNamePrefix, compose values phrased as rig values (not fixed ports), andGrpcChannel.ForAddress("http://…")in all five dialers. The issue's note that the honest TLS scope is wider than the two new planes is now the doc's own framing.Deliberately not done here: no code change, no UseTls option. If an untrusted link ever carries these planes, reopen as the five-plane TLS program the doc describes.