Skip to content

[Feature Request] Accept a pre-built rustls::ClientConfig in client TLS options #1248

@kollektiv

Description

@kollektiv

Is your feature request related to a problem?

temporalio_client::TlsOptions accepts TLS material as PEM byte strings only:

pub struct TlsOptions {
    pub server_root_ca_cert: Option<Vec<u8>>,
    pub client_cert: Option<Vec<u8>>,
    pub client_private_key: Option<Vec<u8>>,
    // ...
}

This works when certificates are static files, but it can't represent a rustls::ClientConfig built with a custom ResolvesClientCert or ServerCertVerifier, which is the standard rustls pattern for:

  • Short-lived certificates with dynamic in-process rotation
  • Custom server-certificate verification (pinning, SAN-URI trust-domain extraction, federated roots)
  • TLS configuration owned by another crate that already manages the rustls setup

In these cases the caller already holds an Arc<rustls::ClientConfig> whose embedded resolver/verifier re-reads the cert source on every handshake. Re-serializing that to PEM bytes produces a one-time snapshot: rotation breaks, custom verification is lost.

Describe the solution you'd like

Allow passing an Arc<rustls::ClientConfig> directly, bypassing PEM parsing. For example:

pub enum ClientTlsConfig {
    /// Existing path: PEM bytes parsed into a rustls config internally.
    Pem(TlsOptions),
    /// New: caller-supplied rustls config used as-is.
    Rustls(Arc<rustls::ClientConfig>),
}

Or equivalently, an additional field on the existing options struct that takes precedence when set.

tonic::transport::ClientTlsConfig already exposes .rustls_client_config(Arc<ClientConfig>), so the plumbing through to the underlying channel should be minimal; the request is to expose that path through temporalio_client's public surface.

Describe alternatives you've considered

  • Extract PEM bytes from the issued config and pass those. Works for the initial certificate's lifetime, but the connection holds the snapshot. When the source rotates, the worker keeps presenting the stale cert until process restart.
  • Reconnect on a timer. Possible but ugly: requires guessing rotation cadence, drops in-flight long-polls, and still can't represent a custom verifier.
  • Fork/patch the client crate. Unblocks, but maintenance burden.

Additional context

The ClientConfig in question is itself stable for the process lifetime; the dynamism lives inside the ResolvesClientCert / ServerCertVerifier it was built with. So a one-time Arc<rustls::ClientConfig> hand-off is sufficient: there's no need for a "reloadable" hook on the temporalio_client side, just pass-through of the config as-is.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions