Skip to content

feat: mtls handshake metrics + yoq cert service cli - #443

Merged
kacy merged 2 commits into
mainfrom
feat/mtls-pr5-finale
Jun 22, 2026
Merged

feat: mtls handshake metrics + yoq cert service cli#443
kacy merged 2 commits into
mainfrom
feat/mtls-pr5-finale

Conversation

@kacy

@kacy kacy commented Jun 22, 2026

Copy link
Copy Markdown
Owner

summary

fourth PR-5 chunk (after #440, #441, #442). lands the two reviewer-
friendly extras that don't depend on the L7 data-plane refactor:

  • yoq_service_mtls_handshakes_total{side, outcome} counter surfaced
    in /metrics
  • yoq cert service <name> cli — read-only inspector for the
    raft-replicated leaf cert

both immediately useful even before the proxy switches to mtls for
outbound traffic.

what's in here

  • tls/mtls_metrics.zig — four-bucket mutex-protected counter
    (client/server × ok/failed) plus tests
  • client_session.doHandshake bumps the client side (always; the
    client only runs when ca_cert_pem is set in the caller's options)
  • session_runtime.acceptServerHandshake bumps the server side only
    when MtlsOpts was passed — keeps the existing plain-TLS
    termination path out of the counter
  • metrics_routes.zig emits the four bucket lines next to the
    existing yoq_service_mtls_* family from feat: per-service mtls leaf issuance + rotation (shadow) #434
  • tls/cli/service_cert_command.zig + commands.zig wiring +
    usage-string update. text and --json output paths.

what isn't in this PR (and why)

the L7 reverse proxy's outbound mTLS swap — i.e. teaching
forwardSingleAttempt to consume client_dial.Outcome.session instead
of a raw fd — is the one PR-5 piece intentionally split out. doing it
cleanly requires:

  • adding peer_mode to ServiceSnapshot / Upstream (cross-cutting)
  • a parallel pool layer for sessions (each carries encryption state
    and sequence counters — can't be pooled as bare fds)
  • updating forwardSingleAttempt's read/write/pool/discard paths to
    match on the union

that's its own design pass + load-bearing review. landing it here
would either be unsafe (sharing pools across encryption states) or
hidden inside a 1500-LOC PR. the helper from #442 (client_dial.dial)
is the clean target it will consume; the metrics counters in this PR
will start producing real data the moment it lands.

verification

still no auto-merge — security-sensitive instrumentation.

kacy added 2 commits June 22, 2026 21:24
four counters, one per side+outcome combo:
  yoq_service_mtls_handshakes_total{side="client",outcome="ok"}
  yoq_service_mtls_handshakes_total{side="client",outcome="failed"}
  yoq_service_mtls_handshakes_total{side="server",outcome="ok"}
  yoq_service_mtls_handshakes_total{side="server",outcome="failed"}

the client side bumps on every doHandshake (mtls always — the client
only runs when ca_cert_pem is set). the server side bumps only when
MtlsOpts was passed, keeping non-mtls TLS termination out of these
counters. tracked in a small mutex-protected fixed-size bucket array
to keep contention bounded.
reads the raft-replicated row from the certificates table (where the
cert_issuer in #434 writes mtls leafs) and prints subject, identity
URI, issued/expires timestamps, and a human-friendly remaining-hours
status. --json variant via the shared JsonWriter for tooling.

useful for debugging issuance / rotation without sqlite access.
@kacy
kacy merged commit 7f9c542 into main Jun 22, 2026
10 checks passed
@kacy
kacy deleted the feat/mtls-pr5-finale branch June 22, 2026 21:30
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