Skip to content

listen_mode: plaintext variants are documented but unused, and weaken the node-auth lockout guarantee #4882

Description

@Sinck

Summary

listen_mode's plaintext variants appear to be unused, while being documented
as supported. The net effect is that our configuration docs advertise a way to
serve the control-plane API in cleartext.

Evidence

  • crates/api-core/src/cfg/file.rs defines
    ListenMode { PlaintextHttp1, PlaintextHttp2, Tls }, defaulting to Tls.
  • Nothing in deploy/, helm/, or the test suite selects a plaintext variant.
    crates/api-core/src/test_support/default_config.rs sets Tls.
  • Both variants are documented as supported, in
    crates/api-core/src/cfg/README.md and
    book/src/configuration/configurability.md.

Why this is more than tidiness

On a plaintext listener the accept path attaches
ConnectionAttributes { peer_certificates: vec![], .. }, so no client
certificate ever reaches the authn middleware. Machine mTLS therefore
authenticates nobody.

Combined with the [node_auth] section, that makes a validation guarantee
weaker than it reads. NodeAuthConfig::validate refuses
enabled = false + mtls_enabled = false on the grounds that it would leave
nodes with no way to authenticate — but on a plaintext listener,
mtls_enabled = true satisfies the check while authenticating nobody. Bearer
tokens are refused over plaintext explicitly at startup; machine mTLS has no
equivalent guard, because adding one would effectively make TLS mandatory
(mtls_enabled defaults to true) and break local plaintext development.

That asymmetry is currently documented rather than enforced, in
cfg/README.md and docs/design/machine-identity/node-auth-jwt.md.

Options

  1. Remove the plaintext variants and the listen_mode field, making TLS
    unconditional. Breaking for anyone who sets it, and the book would need
    updating in step. Would also let the listen_mode check drop out of the
    node-auth startup preflight, since it would become structurally impossible
    to fail.
  2. Keep them, document the supported use case (TLS terminated by a sidecar
    or service mesh would be the obvious one), and emit a startup warning when a
    plaintext mode is selected so it is at least visible in logs.

Deciding between these needs someone who knows whether plaintext has a real
deployment use. Nothing in-tree indicates one, but absence of evidence in the
repo is not conclusive.

Note

#[serde(other)] on the Tls variant means an unrecognized listen_mode
value silently becomes Tls, so a typo cannot accidentally select plaintext.
That part fails safe.

Provenance

Noticed while reviewing #4718 (node-auth bearer JWTs), which added the first
code that refuses a plaintext listener — and only for the bearer half.

Metadata

Metadata

Assignees

Labels

apiaffects API surface areasecurityThings affecting host security (attestation, santization, etc)

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions