Skip to content

Provide batteries-included FileWatchingCertResolver for common mTLS rotation #1345

Open

Description

@brucearctor

Context

Follow-up to #1338 / #1340.

The dynamic cert resolver (#1340) provides the hook for certificate rotation, but users must implement ResolvesClientCert themselves. The most common use case — a sidecar (Vault agent, cert-manager) writes rotated cert/key files to disk — should have a batteries-included implementation.

Proposal

Provide a FileWatchingCertResolver (or ReloadingCertProvider if #1341 adds the SDK-owned trait):

let resolver = FileWatchingCertResolver::new(
    "/run/secrets/client.pem",
    "/run/secrets/client.key",
)?;

let conn_opts = ConnectionOptions::new(url)
    .tls_options(TlsOptions {
        client_cert_resolver: Some(Arc::new(resolver)),
        ..Default::default()
    });

Behavior

  • Reads cert/key on first call and caches as Arc<CertifiedKey>
  • Checks file mtime on subsequent calls; re-parses only when changed
  • Thread-safe via RwLock
  • Logs at info! when certs are reloaded, warn! on parse errors (falls back to last good cert)

Alternative: poll-based vs. inotify

Start with simple mtime polling (zero extra deps). A notify-based watcher can be added later behind a feature flag.

References

Activity

  1. chris-olszewski commented on Jun 22, 2026

    @chris-olszewski
    Member

    I do not think we would want this functionality built into the Rust SDK itself. It seems better suited for a community or contrib crate. Is there a constraint I'm missing where this would need to be built into the SDK iteself?

  2. brucearctor commented on Jun 22, 2026

    @brucearctor
    ContributorAuthor

    @chris-olszewski :

    Both the java and Go SDKs have similar functionality. Though, indeed their implimentations come from language/tool ecosystem code; those languages have different building blocks[ ex: Go gets from stdlib crypto/tls — GetClientCertificate is a per-handshake callback , and Java gets from gRPC-Java — AdvancedTlsX509KeyManager with scheduled polling ].

    The alternate path I can come up with:

    I could a small standalone crate (e.g. rustls-client-cert-reloader) that implements rustls::client::ResolvesClientCert with file-watching. This could fill the ecosystem gap — the server-side crates (tls-hot-reload, rustls-cert-reloadable-resolver) exist but nobody has done the client side. It's ~100-150 lines of real code:

    Arc<ArcSwap> for lock-free reads
    mtime polling (or optional notify behind a feature flag)
    Fallback to last-good-cert on parse error
    Temporal SDK re-exports or depends on it for the batteries-included FileWatchingCertResolver in #1345. The SDK's TlsOptions already accepts Arc from #1340, so the standalone crate slots in cleanly.

    Are we comfortable adding a new dependency from an external crate? If not that, how do we propose getting the functionality that the rust SDK lacks which I assume would be beneficial to SDK users?

    For example, let's not forget that the Python/TS[worker]/.Net sdks also depend on rust. So, addressing in rust [ core ], means we can expose to the other SDKs and bring 0 downtime cert rotation to more SDKs.

    Thoughts?

    cc: @Sushisource

  3. brucearctor commented on Jun 23, 2026

    @brucearctor
    ContributorAuthor

    And, to be clear, I am OK if this is undesired.

    [ Though, it would be surprising -- given other SDKs do support ]

  4. chris-olszewski commented on Jun 30, 2026

    @chris-olszewski
    Member

    After some more discussion, I was incorrect and this is something that would be beneficial to include. Especially with respect to the core-based SDKs getting this support.

  5. added
    Rust SDKIssues about or asking for Rust SDK release
    and removed
    Rust SDKIssues about or asking for Rust SDK release
    on Aug 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions