-
Notifications
You must be signed in to change notification settings - Fork 4k
Description
What version of gRPC-Java are you using?
<grpc.version>1.69.0</grpc.version>
What is your environment?
macOS 15.1.1
java version "21.0.5" 2024-10-15 LTS
Java(TM) SE Runtime Environment (build 21.0.5+9-LTS-239)
Java HotSpot(TM) 64-Bit Server VM (build 21.0.5+9-LTS-239, mixed mode, sharing)
What did you expect to see?
When using grpc-java client with XDS configuration I was expecting the client request to succeed but instead it failed. The only way the client application will work is when I manually set the authority via channelBuilder.overrideAuthority(), but doing this doesn't seem to make sense since the GRPC client now needs to know something I feel should have been provided in the XDS response with the endpoints.
Note that I've enabled:
- the
trusted_xds_serverserver feature in the bootstrap.json - set the feature flag
GRPC_EXPERIMENTAL_XDS_AUTHORITY_REWRITEto true - and returned
auto_host_rewrite: truein the RouteMatch for that virtual host.
Since this GRPC server is behind an envoy that is handling multiple TLS certificates the SNI information needs to be sent via the TLS handshake, and I think that is what may be happening here. Is there something that I need to do in order to send :authority as SNI info either in the XDS response or during the ManagedChannel setup?
What did you see instead?
Exception in thread "main" io.grpc.StatusRuntimeException: UNAVAILABLE: io exception
Channel Pipeline: [SslHandler#0, ProtocolNegotiators$ClientTlsHandler#0, WriteBufferingAndExceptionHandler#0, DefaultChannelPipeline$TailContext#0]
at io.grpc.stub.ClientCalls.toStatusRuntimeException(ClientCalls.java:268)
at io.grpc.stub.ClientCalls.getUnchecked(ClientCalls.java:249)
at io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:167)
at com.example.service.v1.LookupGrpc$LookupBlockingStub.resolve(LookupGrpc.java:160)
at com.example.adc.App.main(App.java:38)
Caused by: java.net.SocketException: Connection reset
at java.base/sun.nio.ch.SocketChannelImpl.throwConnectionReset(SocketChannelImpl.java:394)
at java.base/sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:426)
at io.grpc.netty.shaded.io.netty.buffer.PooledByteBuf.setBytes(PooledByteBuf.java:255)
at io.grpc.netty.shaded.io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:1132)
at io.grpc.netty.shaded.io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:356)
at io.grpc.netty.shaded.io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:151)
at io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788)
at io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724)
at io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650)
at io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562)
at io.grpc.netty.shaded.io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:994)
at io.grpc.netty.shaded.io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.grpc.netty.shaded.io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:842)
Steps to reproduce the bug
public class App
{
public static void main( String[] args )
{
String target = "xds:///cluster1:443";
ChannelCredentials credentials = TlsChannelCredentials.create();
ManagedChannelBuilder<?> channelBuilder = Grpc.newChannelBuilder(target, credentials);
// NOTE: Client call will fail unless this is enabled.
// channelBuilder.overrideAuthority("cluster1.us-east-1.example.com");
final LookupGrpc.LookupBlockingStub blockingStub = LookupGrpc.newBlockingStub(channelBuilder.build());
Request req = Request.newBuilder().addIps(IP.newBuilder()
.setType(IPAddressType.IPV4)
.setOriginAddress("8.8.8.8")).build();
final Response result = blockingStub.resolve(req);
if (result != null) {
try {
System.out.println(JsonFormat.printer().print(resolve));
} catch (InvalidProtocolBufferException e) {
throw new RuntimeException(e);
}
}
}
}
my bootstrap.json looks like this:
{
"client_default_listener_resource_name_template": "%s",
"xds_servers": [
{
"server_uri": "localhost:8080",
"channel_creds": [
{
"type": "insecure"
}
],
"server_features": [
"xds_v3",
"trusted_xds_server"
]
}
],
"cluster": "example-client-cluster",
"node": {
"id": "app1",
"locality": { "region": "us-west-1" },
"metadata": {}
}
}
This is the ADS response from the XDS server:
Listener
- address:
socket_address:
address: 0.0.0.0
port_value: 9999
api_listener:
api_listener:
'@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
http_filters:
- name: envoy.filters.http.router
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
suppress_envoy_headers: true
rds:
config_source:
ads: {}
resource_api_version: V3
route_config_name: cluster1_route_config
stat_prefix: cluster1
name: cluster1:443
RouteConfiguration
- name: cluster1_route_config
virtual_hosts:
- domains:
- cluster1.us-east-1.example.com
name: default
routes:
- match:
prefix: ""
name: default_route
route:
auto_host_rewrite: true
cluster: cluster1
Clusters
- eds_cluster_config:
eds_config:
ads: {}
resource_api_version: V3
name: cluster1
type: EDS
Endpoints
- cluster_name: cluster1
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 12.34.45.56
port_value: 443
hostname: cluster1.us-east-1.example.com
- endpoint:
address:
socket_address:
address: 12.34.45.57
port_value: 443
hostname: cluster1.us-east-1.example.com
load_balancing_weight: 1
locality:
region: us-west-1