[DB-23477] Verify node hostnames against the cluster endpoint - #39
Open
HarshDaryani896 wants to merge 1 commit into
Open
[DB-23477] Verify node hostnames against the cluster endpoint#39HarshDaryani896 wants to merge 1 commit into
HarshDaryani896 wants to merge 1 commit into
Conversation
YBManagedHostnameVerifier did not match the host against the certificate.
It read a SAN out of the certificate and opened a connection to that SAN
string, then queried yb_servers() to decide whether the host was a cluster
member. That could never work:
- a YugabyteDB Aeon certificate carries only a wildcard DNS SAN
(*.<cluster-uuid>.aws.ybdb.io), which resolves to nothing, so the
control connection failed with UnknownHostException. The wildcard guard
covered only TYPE_IP_ADDRESS, and was ineffective even there because san
was assigned before the check.
- that control connection was built from the same Properties, still
carrying sslhostnameverifier and verify-full, so on a cluster whose SAN
did resolve it re-entered verify() and recursed until StackOverflowError.
The static field meant to prevent this is only assigned once the
constructor returns, which never happened on the first call.
- a certificate with no usable SAN left san null, and
setProperty("PGHOST", null) threw NullPointerException.
Every certificate shape hit one of those three, so the membership check the
class exists to perform never executed in any released version.
Failures were also wrapped in RuntimeException, which bypassed every
SQLException handler in LoadBalanceService, including the fallback to a
normal connection - so a connection pool died at startup instead of
degrading.
The information needed was in the connection URL all along. Load balancing
now records the user's host in yb-endpoint-host before replacing it with a
node address, and verify() performs two checks with no I/O: the dialed host
against the certificate (per-node certificates, YBA and on-premises), then
the recorded endpoint (a cluster-wide certificate, Aeon). Wildcard matching
is RFC 6125 and already implemented by PGjdbcHostnameVerifier.
The resulting guarantee equals verify-full connecting to the endpoint
directly: the peer must present a certificate that chains to sslrootcert and
is valid for the name the user asked for. The endpoint is recorded for the
control connection too, since the refresh retry path can point it at a node
address from yb_servers().
MakeSSL no longer special-cases this class by name; it has a (Properties)
constructor and goes through ObjectFactory like any other verifier, which
restores verifyPeerName to its upstream shape.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
HarshDaryani896
force-pushed
the
fix/ybmanaged-hostname-verifier-endpoint
branch
from
September 10, 2026 11:00
8330ba4 to
5cc42bb
Compare
ashetkar
reviewed
Sep 11, 2026
ashetkar
approved these changes
Sep 11, 2026
ashetkar
left a comment
There was a problem hiding this comment.
Please bump up the version before merging
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes DB-23477.
The problem
sslhostnameverifier=com.yugabyte.ysql.YBManagedHostnameVerifier— the setting our docs tell Aeon users to apply forverify-full+ load balancing — fails 100% of connections. A customer hit this in production:The verifier never matched the host against the certificate. It read a SAN out of the certificate and dialed that SAN string as a hostname, then queried
yb_servers()to decide whether the host was a cluster member. A SAN is a pattern for matching names, not an address, so every certificate shape hit one of three failures:UnknownHostException— a wildcard resolves to nothingStackOverflowError— see belowNullPointerExceptionfromsetProperty("PGHOST", null)The membership check the class exists to perform has therefore never executed.
The recursion is worth calling out: the control connection was built from the same
Properties, still carryingsslhostnameverifierandverify-full, so it re-enteredverify(). Thestaticfield meant to prevent that is only assigned once the constructor returns, which never happens on the first call.Failures were also wrapped in
RuntimeException, which bypassed everySQLExceptionhandler inLoadBalanceService— including the "Failed to apply load balance. Trying normal connection" fallback. That is why pools died at startup rather than degrading.The fix
The information needed was in the connection URL all along.
LoadBalanceServicerecords the user's host inyb-endpoint-hostbefore replacing it with a node address.verify()then makes two comparisons with no I/O at all:Wildcard matching is RFC 6125 and already implemented in
PGjdbcHostnameVerifier.verifyHostName.The resulting guarantee equals
verify-fullconnecting straight to the endpoint: the peer must present a certificate that chains to the configuredsslrootcertand is valid for the name the user asked for. This is what the Node.js smart driver already does viaservername.Removing the round trip removes the recursion, the null SAN and the
RuntimeExceptiontogether, and deletesgetCurrentServers(), the SAN loop, the static control connection and four unused fields — about 180 lines.The endpoint is recorded for the control connection too, because the refresh retry path in
checkAndRefreshcan point it at a node address fromyb_servers(), which a cluster-wide certificate does not cover.MakeSSLno longer special-cases this class by name — it has a(Properties)constructor and goes throughObjectFactorylike any other verifier, restoringverifyPeerNameto its upstream shape.Testing
🤖 Generated with Claude Code