Description
When a TLS cluster has no explicit sni configured, the initial upstream
selection falls back to the request's Host header for SNI (stripped of port,
per RFC 6066). ClusterEntry::build_upstream does this here:
load_balancer/entry.rs:78.
The retry path does not. When a retry reselects an alternate endpoint,
upstream_peer.rs:126
calls EndpointReselector::build_upstream(addr), which takes no request context
and just clones the cluster TLS as-is
(load_balancer/reselector.rs:77).
So a cluster relying on the Host-header SNI fallback connects with the correct
SNI on the first attempt but with none on an alternate-host retry.
The reselector already carries the authority (Host rewrite) across retries for
exactly this reason (its field doc notes it is kept "so a retry to a reselected
endpoint keeps rewriting Host instead of silently reverting"), but the derived
SNI was not carried, so the two paths diverge.
Impact: TLS handshakes to the upstream can fail or select the wrong certificate
during failover, which is precisely when retries fire.
Steps to reproduce
- Configure a cluster with TLS but no explicit
sni, and more than one healthy
endpoint, so the Host header supplies the SNI.
- Send a request whose first attempt fails in a way that triggers an
alternate-host retry (e.g. a connect failure).
- The retry connects to the reselected endpoint without SNI, unlike the first
attempt.
Expected behavior
Alternate-host retries apply the same Host-derived SNI fallback as the initial
selection. The reselector's build_upstream needs the request Host (or the
SNI resolved at first selection) so it can set SNI the way
ClusterEntry::build_upstream does.
Praxis version: main (v0.5.3 line)
Description
When a TLS cluster has no explicit
sniconfigured, the initial upstreamselection falls back to the request's
Hostheader for SNI (stripped of port,per RFC 6066).
ClusterEntry::build_upstreamdoes this here:load_balancer/entry.rs:78.The retry path does not. When a retry reselects an alternate endpoint,
upstream_peer.rs:126calls
EndpointReselector::build_upstream(addr), which takes no request contextand just clones the cluster TLS as-is
(
load_balancer/reselector.rs:77).So a cluster relying on the Host-header SNI fallback connects with the correct
SNI on the first attempt but with none on an alternate-host retry.
The reselector already carries the
authority(Host rewrite) across retries forexactly this reason (its field doc notes it is kept "so a retry to a reselected
endpoint keeps rewriting Host instead of silently reverting"), but the derived
SNI was not carried, so the two paths diverge.
Impact: TLS handshakes to the upstream can fail or select the wrong certificate
during failover, which is precisely when retries fire.
Steps to reproduce
sni, and more than one healthyendpoint, so the
Hostheader supplies the SNI.alternate-host retry (e.g. a connect failure).
attempt.
Expected behavior
Alternate-host retries apply the same Host-derived SNI fallback as the initial
selection. The reselector's
build_upstreamneeds the requestHost(or theSNI resolved at first selection) so it can set SNI the way
ClusterEntry::build_upstreamdoes.Praxis version: main (v0.5.3 line)