0
votes

My GRPC client throws the following exception talking to my server. I gather the exception means that a connection was established but the server errored?

Grpc.Core.RpcException: 'Status(StatusCode="Unavailable", Detail="Empty update", DebugException="Grpc.Core.Internal.CoreErrorDetailException: {"created":"@1615327484.993000000","description":"Failed to pick subchannel","file":"......\src\core\ext\filters\client_channel\client_channel.cc","file_line":5397,"referenced_errors":[{"created":"@1615327484.993000000","description":"Empty update","file":"......\src\core\ext\filters\client_channel\lb_policy\pick_first\pick_first.cc","file_line":201,"grpc_status":14}]}")'

The server is configured as follows. Am I missing something from the recipie?

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(options =>
            {
                options.Listen(IPAddress.Loopback, BINDING_PORT, configure => 
                { 
                    configure.UseHttps(GetCertificate());
                    configure.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http2;
                });
            });

            webBuilder.UseStartup<Startup>();
        }).UseWindowsService();

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGrpcService<LicenseService>().RequireHost($"*:{Program.BINDING_PORT}");

        endpoints.MapGet("/", async context =>
        {
            await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
        });
    });
}

I notice the server initializes via BindService, but the serviceImpl is null. Is that expected?

   public static void BindService(grpc::ServiceBinderBase serviceBinder, LicensesBase serviceImpl)
    {
      serviceBinder.AddMethod(__Method_GetLicense, serviceImpl == null ? null : new grpc::UnaryServerMethod<global::LicenseService.LicRequest, global::LicenseService.LicReply>(serviceImpl.GetLicense));
    }
2

2 Answers

1
votes

I figured out how to add client logging which produced the following trace indicating that the certificate provisioning isn't working.

Environment.SetEnvironmentVariable("GRPC_VERBOSITY", "DEBUG"); // enable traces

D0310 09:57:30.795179 Grpc.Core.Internal.UnmanagedLibrary Attempting to load native library "C:\Work\Petri\LicenseClient\LicTester\bin\x64\Debug\grpc_csharp_ext.x64.dll" D0310 09:57:30.849621 Grpc.Core.Internal.NativeExtension gRPC native library loaded successfully. D0310 09:57:30.858597 0 ......\src\core\ext\filters\client_channel\lb_policy_registry.cc:42: registering LB policy factory for "grpclb" D0310 09:57:30.858597 0 ......\src\core\ext\filters\client_channel\lb_policy_registry.cc:42: registering LB policy factory for "priority_experimental" D0310 09:57:30.858597 0 ......\src\core\ext\filters\client_channel\lb_policy_registry.cc:42: registering LB policy factory for "weighted_target_experimental" D0310 09:57:30.858597 0 ......\src\core\ext\filters\client_channel\lb_policy_registry.cc:42: registering LB policy factory for "pick_first" D0310 09:57:30.859599 0 ......\src\core\ext\filters\client_channel\lb_policy_registry.cc:42: registering LB policy factory for "round_robin" D0310 09:57:30.859599 0 ......\src\core\ext\filters\client_channel\resolver\dns\c_ares\dns_resolver_ares.cc:491: Using ares dns resolver D0310 09:57:30.860592 0 ......\src\core\ext\xds\certificate_provider_registry.cc:33: registering certificate provider factory for "file_watcher" D0310 09:57:30.861589 0 ......\src\core\ext\filters\client_channel\lb_policy_registry.cc:42: registering LB policy factory for "cds_experimental" D0310 09:57:30.861589 0 ......\src\core\ext\filters\client_channel\lb_policy_registry.cc:42: registering LB policy factory for "xds_cluster_impl_experimental" D0310 09:57:30.861589 0 ......\src\core\ext\filters\client_channel\lb_policy_registry.cc:42: registering LB policy factory for "xds_cluster_resolver_experimental" D0310 09:57:30.861589 0 ......\src\core\ext\filters\client_channel\lb_policy_registry.cc:42: registering LB policy factory for "xds_cluster_manager_experimental" E0310 09:57:30.979025 0 ......\src\core\tsi\ssl_transport_security.cc:761: Could not load any root certificate. E0310 09:57:30.979025 0 ......\src\core\tsi\ssl_transport_security.cc:1955: Cannot load server root certificates. E0310 09:57:30.979025 0 ......\src\core\lib\security\security_connector\ssl\ssl_security_connector.cc:116: Handshaker factory creation failed with TSI_INVALID_ARGUMENT. E0310 09:57:30.980022 0 ......\src\core\ext\transport\chttp2\client\secure\secure_channel_create.cc:107: Failed to create secure subchannel for secure name '127.0.0.1:59740' E0310 09:57:30.980022 0 ......\src\core\ext\transport\chttp2\client\secure\secure_channel_create.cc:49: Failed to create channel args during subchannel creation. E0310 09:57:31.027897 0 ......\src\core\tsi\ssl_transport_security.cc:761: Could not load any root certificate. E0310 09:57:31.027897 0 ......\src\core\tsi\ssl_transport_security.cc:1955: Cannot load server root certificates. E0310 09:57:31.030887 0 ......\src\core\lib\security\security_connector\ssl\ssl_security_connector.cc:116: Handshaker factory creation failed with TSI_INVALID_ARGUMENT. E0310 09:57:31.040860 0 ......\src\core\ext\transport\chttp2\client\secure\secure_channel_create.cc:107: Failed to create secure subchannel for secure name '127.0.0.1:59740' E0310 09:57:31.040860 0 ......\src\core\ext\transport\chttp2\client\secure\secure_channel_create.cc:49: Failed to create channel args during subchannel creation.

0
votes

I was hitting this problem until I figured out when creating the client, you need to pass the same certificate file as the one used to create the server.

If you do not pass any certificate file, the default root certificate file will be used, and on my machine I did not have any root certificates. I saw the same errors about unable to load any root certificates.

Also, the when creating the channel to the server, the client must use the same "Common Name" (www.example.com) that was used to create the server's certificate. Otherwise the server will reject the SSL connection request.