fredjoonpark opened a new issue, #1319:
URL: https://github.com/apache/arrow-java/issues/1319

   ### Describe the enhancement requested
   
   The Flight SQL JDBC driver has no way to set the hostname used for TLS 
certificate verification (and SNI) separately from the host it connects to. The 
driver always verifies the server certificate against the `host` in the JDBC 
URL.
   
   This breaks TLS whenever the client connects through an address or hostname 
that doesn't match the server's certificate, for example:
   
   - **Tunnels and port-forwarding:** reaching a private server through SSH 
(`ssh -L`), AWS Systems Manager Session Manager port forwarding, or `kubectl 
port-forward`. The client connects to `localhost`, but the certificate is 
issued for the server's real hostname.
   - **Private endpoints and aliases:** connecting through a hostname other 
than the one on the certificate, for example an AWS PrivateLink interface 
endpoint DNS name (`vpce-...amazonaws.com`) when private DNS isn't enabled, or 
an internal alias that points at a load balancer.
   - **Connecting by IP address:** service discovery or client-side load 
balancing that returns IP addresses (for example Kubernetes endpoints or AWS 
Cloud Map), when the certificate only contains DNS names in its SAN.
   - **Private network gateways** that require the client to dial a specific 
address (IPv4 or IPv6) instead of the server's own hostname.
   
   The available workarounds all have significant drawbacks:
   
   - `disableCertificateVerification=true` removes server authentication 
entirely.
   - Making the certificate's hostname resolve to the target address 
(`/etc/hosts`, custom DNS, or a JDK `InetAddressResolverProvider`) applies to 
the whole OS or JVM. It requires control over that environment, and it can't 
send the same hostname to different addresses for different connections in one 
process.
   - Adding the connection address (`localhost`, an IP address or an endpoint 
hostname) to the server certificate's SAN requires control over the server 
certificate. Managed services usually don't allow that, and the address may 
change.
   - Using `FlightClient` directly with `overrideHostname` works, but doesn't 
help JDBC-based tools.
   
   **Example**
   
   ```
   
jdbc:arrow-flight-sql://192.0.2.10:443?useEncryption=true&tlsRootCerts=/path/ca.pem
   ```
   
   fails with:
   
   ```
   No subject alternative names matching IP address 192.0.2.10 found
   ```
   
   even though the server presents a valid certificate for `flight.example.com`.
   
   Observed with `flight-sql-jdbc-driver` 19.0.0. The code path is unchanged on 
`main`.
   
   **Flight client already supports this**
   
   `FlightClient.Builder.overrideHostname(String)` and 
`NettyClientBuilder.overrideHostname(String)` already exist and map to gRPC's 
`overrideAuthority`. This was confirmed as the supported way to set SNI for the 
Java Flight client in apache/arrow#26155 (ARROW-10144). The JDBC driver builds 
its client with `NettyClientBuilder` in 
`ArrowFlightSqlClientHandler.Builder.build()`, but never calls 
`overrideHostname`, and there is no connection property to set it.
   
   **Proposal**
   
   - Add an optional connection property, `hostnameOverride` (string, default 
unset), to `ArrowFlightConnectionProperty`.
   - When set and `useEncryption=true`, call 
`clientBuilder.overrideHostname(value)` in 
`ArrowFlightSqlClientHandler.Builder.build()`.
   - Handle the clients the driver creates for additional endpoint locations in 
`getStreams()`. These are built from a copy of the original builder (`new 
Builder(original).withHost(endpointUri.getHost())...`), so a plain copied field 
would wrongly verify a different endpoint host against the override. Apply the 
override only when the endpoint host matches the original connection host, and 
otherwise clear it so those locations keep the current behavior.
   - Ignore the property when encryption is disabled, and document it next to 
`disableCertificateVerification` and `tlsRootCerts`.
   
   **Prior art in other JDBC drivers**
   
   - Trino JDBC: `hostnameInCertificate`
   - Microsoft SQL Server JDBC: `hostNameInCertificate`
   
   **Tests**
   
   Connect over TLS to an IP literal (for example `127.0.0.1` or `[::1]`) using 
a test certificate whose SAN only contains a DNS name:
   
   - Without the property: verification fails.
   - With `hostnameOverride=<dns-name>`: the connection succeeds with full 
verification.
   
   I'm happy to submit a PR for this.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to