C#中的gRPC客户端不适用于具有mTLS支持的Go中的gRPC服务器

庞尼:

在Golang中有一个gRPC服务器,该服务器使用以下ServerOptions启用了mTLS:

// getServerOptions returns a list of GRPC server options.
// Current options are TLS certs and opencensus stats handler.
func (h *serviceHandler) getServerOptions() []grpc.ServerOption {
    tlsCer, err := tls.LoadX509KeyPair(tlsDir+"tls.crt", tlsDir+"tls.key")
    if err != nil {
        logger.WithError(err).Fatal("failed to generate credentials")
    }

    cfg := &tls.Config{
        Certificates: []tls.Certificate{tlsCer},
        ClientAuth:   tls.RequireAndVerifyClientCert,
        GetConfigForClient: func(*tls.ClientHelloInfo) (*tls.Config, error) {
            h.certMutex.RLock()
            defer h.certMutex.RUnlock()
            return &tls.Config{
                Certificates: []tls.Certificate{tlsCer},
                ClientAuth:   tls.RequireAndVerifyClientCert,
                ClientCAs:    h.caCertPool,
            }, nil
        },
    }
    // Add options for creds and OpenCensus stats handler to enable stats and tracing.
    return []grpc.ServerOption{grpc.Creds(credentials.NewTLS(cfg)), grpc.StatsHandler(&ocgrpc.ServerHandler{})}
}

服务器在Golang中gRPC客户端正常工作,但是在证书交换握手之后,对于以下gRPC c#客户端失败。

        static async Task Main(string[] args)
        {
            string baseAddress = "x.x.x.x";
            var x509Cert = new X509Certificate2("client.pfx", "123");
            var client = CreateClientWithCert("https://" + baseAddress + ":443", x509Cert);

            try {
                var response = await client.PostAllocateAsync(new AllocationRequest {Namespace = "Default"});
                Console.Write(response.State.ToString());
            } 
            catch(RpcException e)
            {
                Console.WriteLine($"gRPC error: {e.Status.Detail}");
            }
            catch 
            {
                Console.WriteLine($"Unexpected error calling agones-allocator");
                throw;
            }
        }

        public static AllocationService.AllocationServiceClient CreateClientWithCert(
            string baseAddress,
            X509Certificate2 certificate)
        {

            var loggerFactory = LoggerFactory.Create(logging =>
            {
                logging.AddConsole();
                logging.SetMinimumLevel(LogLevel.Trace);
            });

            // Add client cert to the handler
            var handler = new HttpClientHandler();
            handler.ClientCertificates.Add(certificate);
            handler.ServerCertificateCustomValidationCallback = 
                HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

            // Create the gRPC channel
            var channel = GrpcChannel.ForAddress(baseAddress, new GrpcChannelOptions
            {
                HttpClient = new HttpClient(handler),
                LoggerFactory = loggerFactory,
            });

            return new AllocationService.AllocationServiceClient(channel);
        }
    }

这是跟踪日志:

dbug: Grpc.Net.Client.Internal.GrpcCall[1]
      Starting gRPC call. Method type: 'Unary', URI: 'https://x.x.x.x/v1alpha1.AllocationService/PostAllocate'.
dbug: Grpc.Net.Client.Internal.GrpcCall[18]
      Sending message.
trce: Grpc.Net.Client.Internal.GrpcCall[21]
      Serialized 'V1Alpha1.AllocationRequest' to 9 byte message.
trce: Grpc.Net.Client.Internal.GrpcCall[19]
      Message sent.
fail: Grpc.Net.Client.Internal.GrpcCall[6]
      Error starting gRPC call.
System.Net.Http.HttpRequestException: An error occurred while sending the request.
 ---> System.IO.IOException: The response ended prematurely.
   at System.Net.Http.HttpConnection.FillAsync()
   at System.Net.Http.HttpConnection.ReadNextResponseHeaderLineAsync(Boolean foldedHeadersAllowed)
   at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithNtConnectionAuthAsync(HttpConnection connection, HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.DiagnosticsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
   at Grpc.Net.Client.Internal.GrpcCall`2.RunCall(HttpRequestMessage request)
dbug: Grpc.Net.Client.Internal.GrpcCall[8]
      gRPC call canceled.
fail: Grpc.Net.Client.Internal.GrpcCall[3]
      Call failed with gRPC error status. Status code: 'Internal', Message: 'Error starting gRPC call: An error occurred while sending the request.'.
dbug: Grpc.Net.Client.Internal.GrpcCall[4]
      Finished gRPC call.
gRPC error: Error starting gRPC call: An error occurred while sending the request.

有人可以帮我了解失败的原因吗?使用SslCredentials也会失败出于隐私原因,xxxx是IP替代品。

庞尼:

我编写了一些示例代码来重现此处报告的跨平台不兼容问题。

根本原因是在golang服务器中使用GetConfigForClient(在这种情况下用于刷新客户端CA证书)时,来自C#客户端的请求失败。但是,当将它替换为VerifyPeerCertificate时,问题已解决。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

Grpc.Core.RpcException方法未实现与C#客户端和Java服务器

适用于具有最简单的客户端-服务器架构的移动应用程序的OAuth2吗?

将Python Thrift客户端与Go gRPC服务器接口

基于Go的grpc服务器流不断堆积响应以转到go客户端

如何正确设置gRPC客户端-服务器

gRPC:如何使用Go服务器在Java客户端中获取多个返回值

如果服务器关闭,如何在C#中使gRPC客户端超时?

拦截服务器和客户端中的gRPC C ++调用

Google Closure中是否有适用于客户端-服务器应用程序的JavaScript代码覆盖工具?

GRPC错误代码12客户端服务器应用程序C ++ [调试]

在服务器端C#中读取grpc中的元数据

C ++中仅gRPC的Tensorflow服务客户端

无法在普通C#gRPC客户端和服务器之间建立连接

如何从python中的gRPC客户端关闭gRPC服务器?

从服务器返回的gRPC metada仅在C#客户端使用异步调用时才可用?

SetState不适用于服务器中的数据

如何使具有服务器流连接的Android grpc客户端保持活动状态?

如何将.NET Framework中的gRPC客户端与安全的.NET Core服务器连接?

在grpc客户端之间传输“斑点”-服务器

适用于Windows客户端的Ubuntu终端服务器

具有Jeditable的jQuery数据表不适用于服务器端处理

任何适用于Android的服务器/客户端模型?

如果没有服务器,则GRPC客户端onNext不会失败

在服务器套接字C#中获取有关客户端的数据

gRPC 中数据如何从客户端发送到(多服务)服务器

侦听 Socket.io 事件适用于服务器端但不适用于客户端

检测grpc服务器中关闭的客户端连接

golang中GRPC客户端服务器架构中的Proto不匹配

元数据不适用于客户端,仅适用于服务器响应