Skip to content

fix(security): refuse auth reloads the running TLS cannot enforce - #269

Merged
catinspace-au merged 2 commits into
mainfrom
fix/mtls-reload
Nov 15, 2026
Merged

catinspace-au merged 2 commits into
mainfrom
fix/mtls-reload

Conversation

@catinspace-au

Copy link
Copy Markdown
Contributor

A reload replaced the whole auth section, including the mode. The client-certificate policy is built once at start. Reloading from bearer into mtls on a plaintext listener accepted unauthenticated ingest until a restart.

  • create_auth_state takes the listener's running Handshake. It refuses mtls or both when the handshake admits clients without a certificate. The watcher keeps the current auth and logs an error.
  • All six reloading listeners pass it: HTTP, Splunk HEC, Prometheus remote write, OTLP HTTP, OTLP gRPC and Vector gRPC.

The gRPC and OTLP gRPC interceptor demanded a bearer token on every request, so mtls refused every RPC. The interceptor now skips bearer-token checks under mtls, as the HTTP middleware does. OTLP HTTP shares otlp.auth with OTLP gRPC, so validation affects both.

tls.client_auth hot reload is outside this change.

The first three tests fail on main:

  • a_reload_into_mtls_over_plaintext_keeps_the_current_auth reloads every listener into mtls. For 1s the token must still work and a bare request must still be refused.
  • the_grpc_interceptor_checks_what_the_mode_names covers the interceptor under mtls and bearer.
  • client_certificates_are_required_on_every_mtls_listener runs both gRPC ports under mtls and sends an RPC with the client certificate.
  • a_certificate_mode_needs_a_handshake_that_requires_one tests the build cases for create_auth_state.

Done when CI Quality and Test are green.

`mtls` and certificate authentication in `both` are checked only by the TLS handshake. Each listener builds its handshake once at startup. A reload could switch auth to either mode. Listeners started plaintext or with `tls.client_auth: none` then accepted every request unauthenticated until restart.

`create_auth_state` takes the listener's running handshake and refuses `mtls` or `both` if it admits clients without certificate verification. The reload watcher keeps the current auth if replacement auth fails to build. A refused reload logs an error and leaves auth unchanged.

Every listener that reloads auth passes its handshake: HTTP, Splunk HEC, Prometheus remote write, OTLP on both ports and gRPC.

The gRPC and OTLP gRPC interceptor demanded a bearer token for every request. `mtls` builds no token provider, so an `mtls` port refused every RPC. Under `mtls`, the interceptor skips token checks, matching the HTTP middleware. Startup validation and the reload check both reject handshakes that do not verify the certificate.
Document gRPC support for `auth.mode: mtls` with `tls.client_auth: required`. The hardening and sidecar pages no longer send certificate users to `mode: none`.

The internals page says a reload into `mtls` or `both` is refused when the running handshake accepts any client. The current auth stays.
@catinspace-au
catinspace-au merged commit 7397a88 into main Nov 15, 2026
23 checks passed
@catinspace-au
catinspace-au deleted the fix/mtls-reload branch November 15, 2026 08:59
@github-actions

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant