Skip to content

feat(transport/channel): expose ServerCertVerifier API#2612

Merged
YutaoMa merged 3 commits into
grpc:masterfrom
YutaoMa:yutaoma/tls-verifier-api
Apr 30, 2026
Merged

feat(transport/channel): expose ServerCertVerifier API#2612
YutaoMa merged 3 commits into
grpc:masterfrom
YutaoMa:yutaoma/tls-verifier-api

Conversation

@YutaoMa

@YutaoMa YutaoMa commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

Motivation

Ref: #2444

tonic::transport::ClientTlsConfig currently builds the rustls::ClientConfig internally with the default WebPkiServerVerifier. There's no way to inject a custom ServerCertVerifier without abandoning ClientTlsConfig and going through Endpoint::connect_with_connector_lazy, which means reimplementing TCP + TLS handshake + ALPN enforcement + timeout handling that tonic already provides correctly.

This blocks gRFC A29 (xDS-Based TLS Security) SAN matching feature which we are adding to tonic-xds.

Solution

Adds Endpoint::tls_config_with_verifier(ClientTlsConfig, Arc<dyn ServerCertVerifier>). When invoked, TlsConnector::new builds the ClientConfig via .dangerous().with_custom_certificate_verifier(...) instead of the default root-store path. SNI, ALPN, timeout, identity, and key-log continue to apply.

Design Highlights

  • API placement on Endpoint rather than ClientTlsConfig: Adding the verifier as a field on ClientTlsConfig would require storing Arc<dyn ServerCertVerifier>. Since the ServerCertVerifier trait carries no UnwindSafe + RefUnwindSafe bounds, the dyn type does not propagate either auto trait, which would silently strip ClientTlsConfig's existing UnwindSafe + RefUnwindSafe impls — a semver-breaking auto-trait removal flagged by cargo-semver-checks. Placing the method on Endpoint (which is already !UnwindSafe) avoids the regression and keeps the verifier opt-in, scoped to users who explicitly need it.

  • Conflict detection: combining a custom verifier with ca_certificate, ca_certificates, trust_anchor, trust_anchors, with_*_roots returns TlsError::VerifierConflict at connector-construction time. A custom verifier replaces the entire default-verifier path including its trust roots, so the CA-configuration methods would be silently ignored. We chose to emit an explicit error to help prevent such footguns. Users who want both standard WebPKI behavior and additional checks can compose WebPkiServerVerifier inside their custom verifier with their own root store (as is planned for tonic-xds A29 implementation).

@YutaoMa YutaoMa marked this pull request as ready for review April 29, 2026 17:07
@YutaoMa YutaoMa requested a review from LucioFranco April 29, 2026 17:07
@YutaoMa YutaoMa merged commit 7e31f8b into grpc:master Apr 30, 2026
21 checks passed
@github-actions github-actions Bot mentioned this pull request May 4, 2026
LucioFranco pushed a commit that referenced this pull request May 7, 2026
## 🤖 New release

* `tonic`: 0.14.5 -> 0.14.6 (✓ API compatible changes)
* `tonic-build`: 0.14.5 -> 0.14.6 (✓ API compatible changes)
* `tonic-prost`: 0.14.5 -> 0.14.6 (✓ API compatible changes)
* `tonic-health`: 0.14.5 -> 0.14.6 (✓ API compatible changes)
* `tonic-types`: 0.14.5 -> 0.14.6 (✓ API compatible changes)
* `tonic-reflection`: 0.14.5 -> 0.14.6 (✓ API compatible changes)
* `tonic-prost-build`: 0.14.5 -> 0.14.6 (✓ API compatible changes)
* `tonic-web`: 0.14.5 -> 0.14.6 (✓ API compatible changes)

<details><summary><i><b>Changelog</b></i></summary><p>

## `tonic`

<blockquote>

##
[0.14.6](tonic-v0.14.5...tonic-v0.14.6)
- 2026-05-06

### Added

- *(transport/channel)* expose ServerCertVerifier API
([#2612](#2612))

### Fixed

- map no trailers ok status to unknown
([#2543](#2543))

### Other

- add max_frame_size to client Endpoint
([#2592](#2592))
- Allow setting the HTTP/2 client header table size
([#2582](#2582))
- update rust edition and version to 2024 and 1.88, respectively
([#2525](#2525))
</blockquote>

## `tonic-build`

<blockquote>

##
[0.14.6](tonic-build-v0.14.5...tonic-build-v0.14.6)
- 2026-05-06

### Other

- update rust edition and version to 2024 and 1.88, respectively
([#2525](#2525))
</blockquote>

## `tonic-prost`

<blockquote>

##
[0.14.6](tonic-prost-v0.14.5...tonic-prost-v0.14.6)
- 2026-05-06

### Other

- update rust edition and version to 2024 and 1.88, respectively
([#2525](#2525))
</blockquote>

## `tonic-health`

<blockquote>

##
[0.14.6](tonic-health-v0.14.5...tonic-health-v0.14.6)
- 2026-05-06

### Other

- update rust edition and version to 2024 and 1.88, respectively
([#2525](#2525))
</blockquote>

## `tonic-types`

<blockquote>

##
[0.14.6](tonic-types-v0.14.5...tonic-types-v0.14.6)
- 2026-05-06

### Other

- update rust edition and version to 2024 and 1.88, respectively
([#2525](#2525))
</blockquote>

## `tonic-reflection`

<blockquote>

##
[0.14.6](tonic-reflection-v0.14.5...tonic-reflection-v0.14.6)
- 2026-05-06

### Other

- fix panic when client drops connection early
([#2596](#2596))
- update rust edition and version to 2024 and 1.88, respectively
([#2525](#2525))
</blockquote>

## `tonic-prost-build`

<blockquote>

##
[0.14.6](tonic-prost-build-v0.14.5...tonic-prost-build-v0.14.6)
- 2026-05-06

### Other

- Support well known types resolved by prost to their rust counterparts
([#2544](#2544))
- update rust edition and version to 2024 and 1.88, respectively
([#2525](#2525))
</blockquote>

## `tonic-web`

<blockquote>

##
[0.14.6](tonic-web-v0.14.5...tonic-web-v0.14.6)
- 2026-05-06

### Other

- update rust edition and version to 2024 and 1.88, respectively
([#2525](#2525))
</blockquote>


</p></details>

---
This PR was generated with
[release-plz](https://github.com/release-plz/release-plz/).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
YutaoMa added a commit that referenced this pull request May 12, 2026
## Motivation

Ref: #2444

Continues the gRFC A29 (xDS-Based TLS Security) work in `tonic-xds`. The
cert provider foundation merged in #2593 gives us a pluggable source of
trust roots and identity. The next step toward end-to-end mTLS in the
data plane is to parse the cluster's TLS config from xDS, validate
server certs against the configured trust roots, and apply SAN matching
on top of WebPKI chain validation.

This PR adds the building blocks for that validation. Integration with
the
connector factory is deferred to a follow-up PR — see below.

## Solution

- **StringMatcher extraction** (`xds/resource/string_matcher.rs`):
pulled out of `routing.rs` so it can be reused. The SAN matcher uses it
for the string-comparison primitives.
- **UpstreamTlsContext parsing** (`xds/resource/security.rs`): parses
`envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext` into a
typed config.
- **SAN matcher** (`xds/resource/san_matcher.rs`): RFC 6125 wildcard DNS
matching, RFC 5952 IP canonicalization, plus URI, EMAIL, and OTHER_NAME
paths matching using the above extracted `StringMatcher`.
- **A29 `ServerCertVerifier`** (`xds/cert_provider/verifier.rs`): wraps
`WebPkiServerVerifier` and applies SAN matching after standard chain
validation. Sources trust roots from the existing
`CertProviderRegistry`.

All new types are tested in isolation against synthetic certs.

### Why integration is deferred

The tonic-side hook for installing a custom rustls `ServerCertVerifier`
on a `Channel` is still in flight as #2612. Without that API, the
verifier can't be wired into the per-cluster connector from a downstream
crate.

---------

Co-authored-by: Jeff Jiang <jefjiang@linkedin.com>
YutaoMa added a commit that referenced this pull request May 26, 2026
## Motivation

Ref: #2444

Closes out gRFC A29 (xDS-Based TLS Security) in `tonic-xds`. The cert
provider foundation merged in #2593 and #2616 left the connector
integration deferred — its pre-req `Endpoint::tls_config_with_verifier`
landed in #2612.

With that hook available, this PR wires up the per-cluster TLS
connector.

## Solution

Five commits, each independently reviewable:

- `file_watcher` background refresh.
- Eager cert parsing in cert provider, verifier access it per handshake.
- Atomically swap `Connector` on CDS update. Existing endpoint channels
keep their connector; new connections pick up the latest. Invalid CDS
updates are logged and the previous-good connector is kept.
- **Data-plane `TlsConnector`** — for clusters with `Some(security)`,
the connector holds the A29 verifier plus an optional identity provider
(mTLS). `connect()` fetches identity per call, assembles a
`ClientTlsConfig`, and builds the endpoint.
- Docs + dead_code cleanup
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.

2 participants