feat(client-rust): accept gateway cert by default over TLS (or documented pin-only fallback)

This commit is contained in:
Joseph Doherty
2026-06-01 07:11:09 -04:00
parent 4c093a64fa
commit 572b268d81
3 changed files with 151 additions and 0 deletions
+28
View File
@@ -22,6 +22,7 @@ pub struct ClientOptions {
api_key: Option<ApiKey>,
plaintext: bool,
ca_file: Option<PathBuf>,
require_certificate_validation: bool,
server_name_override: Option<String>,
connect_timeout: Duration,
call_timeout: Duration,
@@ -38,6 +39,7 @@ impl ClientOptions {
api_key: None,
plaintext: true,
ca_file: None,
require_certificate_validation: false,
server_name_override: None,
connect_timeout: Duration::from_secs(10),
call_timeout: Duration::from_secs(30),
@@ -67,6 +69,22 @@ impl ClientOptions {
self
}
/// Require TLS certificate verification even without a pinned CA. Default
/// false: the gateway's self-signed certificate is accepted (internal-tool
/// posture). Setting a CA file always verifies.
///
/// Note for Rust: tonic 0.13's `ClientTlsConfig` exposes no hook for a
/// custom rustls verifier, so the Rust client cannot accept an arbitrary
/// self-signed certificate the way the other clients do. With the default
/// (false) and no pinned CA, [`crate::client::GatewayClient::connect`]
/// rejects the TLS connection and asks for a CA file. Either pin a CA via
/// [`ClientOptions::with_ca_file`] (the supported lenient path on Rust) or
/// set this `true` to verify against the system trust roots.
pub fn with_require_certificate_validation(mut self, require: bool) -> Self {
self.require_certificate_validation = require;
self
}
/// Override the SNI/server name used during the TLS handshake. Useful
/// when the dial-target host name does not match the certificate.
pub fn with_server_name_override(mut self, server_name_override: impl Into<String>) -> Self {
@@ -121,6 +139,12 @@ impl ClientOptions {
self.ca_file.as_ref()
}
/// Whether TLS certificate verification is required even without a pinned
/// CA. See [`ClientOptions::with_require_certificate_validation`].
pub fn require_certificate_validation(&self) -> bool {
self.require_certificate_validation
}
/// Optional SNI / server-name override for TLS handshakes.
pub fn server_name_override(&self) -> Option<&str> {
self.server_name_override.as_deref()
@@ -161,6 +185,10 @@ impl fmt::Debug for ClientOptions {
.field("api_key", &self.api_key.as_ref().map(|_| "<redacted>"))
.field("plaintext", &self.plaintext)
.field("ca_file", &self.ca_file)
.field(
"require_certificate_validation",
&self.require_certificate_validation,
)
.field("server_name_override", &self.server_name_override)
.field("connect_timeout", &self.connect_timeout)
.field("call_timeout", &self.call_timeout)