【问题标题】:How to open a secure channel in python gRPC client without a client SSL certificate如何在没有客户端 SSL 证书的情况下在 python gRPC 客户端中打开安全通道
【发布时间】:2022-08-08 18:27:31
【问题描述】:

我有一个具有有效 TLS 证书且不需要客户端 TLS 的 grpc 服务器(在 Go 中)。出于某种原因,我无法在 Python 中实现没有 mTLS 的客户端,即使我可以在 Golang 中这样做。

在Python中我有

os.environ[\"GRPC_VERBOSITY\"] = \"DEBUG\"
# os.environ[\"GRPC_DEFAULT_SSL_ROOTS_FILE_PATH\"] = \"/etc/ssl/certs/ca-bundle.crt\"

channel = grpc.secure_channel(ADDR, grpc.ssl_channel_credentials())
grpc.channel_ready_future(channel).result(timeout=10)

这给了我以下错误

D0513 08:02:08.147319164   21092 security_handshaker.cc:181] Security handshake failed: {\"created\":\"@1652446928.147311309\",\"description\":\"Handshake failed\",\"file\":\"src/core/lib/security/transport/security_handshaker.cc\",\"file_line\":377,\"tsi_code\":10,\"tsi_error\":\"TSI_PROTOCOL_FAILURE\"}

如果我通过取消注释掉注释行来使用 SSL 证书,我可以让它工作。我知道我的服务器不会请求、要求或验证客户端证书,因为以下 Go 代码完美运行

conn, err := grpc.DialContext(
    ctx,
    gRPCAddr,
    grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(nil, \"\")),
)
dummyClient := dummy.NewDummyServiceClient(conn)
if _, err := dummyClient.Ping(context.Background(), &dummy.PingRequest{
    Ping: \"go client ping\",
}); err != nil {
    return fmt.Errorf(\"failed to ping: %w\", err)
}
  • 是否有可能其中一个中间 CA 无效?您应该能够使用 openssl 的 s_client 对其进行测试,并尝试连接到服务器 ip/port。
  • @CarlMastrangelo 一开始我也是这么想的,但是中间 CA 肯定是有效的,因为 go 客户端能够使用传输凭据连接到服务器(使通道成为安全通道)?
  • 如果我的记忆服务于 Go 客户端处理 TLS 的方式(纯 Go 重新实现)与 BoringSSL/OpenSSL 库(由 Python 和包装语言使用)不同。 TLS 库的差异可能是验证存在差异的原因。因此,使用 openssl s_client 检查肯定会显示出来。

标签: python ssl grpc grpc-python grpc-go


【解决方案1】:

https://grpc.github.io/grpc/python/_modules/grpc.html#secure_channelchannel = grpc.secure_channel(ORBIUM_ADDR, grpc.ssl_channel_credentials()) 的文档。此功能依赖于类通道,请参阅文档https://grpc.github.io/grpc/python/_modules/grpc/aio/_channel.html

基本上,类 Channel 包装 C 代码以提供安全通道。包装好的 C 代码需要证书。如果您可以在 C 中实现,那么只更改 C 代码可能是最简单的。

【讨论】:

    【解决方案2】:

    如果服务器端的证书是公开签名的,您可以使用:

    grpc.secure_channel(ORBIUM_ADDR, grpc.ssl_channel_credentials())
    

    但这似乎对你不起作用,所以我猜服务器证书是由你拥有的根证书签名的。您可以将根证书传递到 root_certificates 字段 [1],并将其他两个字段留空。此用例记录在我们的身份验证指南 [2] 中。

    with open(os.environ["GRPC_DEFAULT_SSL_ROOTS_FILE_PATH"], 'rb') as f:
        creds = grpc.ssl_channel_credentials(f.read())
    
    channel = grpc.secure_channel(ORBIUM_ADDR, creds)
    

    [1]https://grpc.github.io/grpc/python/grpc.html#grpc.ssl_channel_credentials

    [2]https://grpc.io/docs/guides/auth/

    【讨论】:

    • 谢谢你的回答,但正如问题中提到的,我已经考虑过了。我正在寻找一种在客户端不需要证书的方法。这个功能在 Go gRPC 目标中是可能的。我试图在 Python 中模拟它。
    【解决方案3】:

    我的猜测基于 Python GRPC 文档https://grpc.github.io/grpc/python/grpc.html

    channel = grpc.insecure_channel(ORBIUM_ADDR)
    

    代替:

    channel = grpc.secure_channel(ORBIUM_ADDR, grpc.ssl_channel_credentials())
    

    【讨论】:

    • 该问题指定了一个安全通道。 insecure_channel 不安全且未启用 TLS。我仍然想要 TLS,但我想打开一个没有任何客户端证书的安全 TLS 启用通道(因为我只想要服务器端 TLS)
    猜你喜欢
    • 2020-11-23
    • 2012-06-07
    • 1970-01-01
    • 2017-10-10
    • 2017-04-28
    • 1970-01-01
    • 2019-10-25
    • 2013-04-07
    • 1970-01-01
    相关资源
    最近更新 更多