如何在没有客户端 SSL 证书的情况下在 python gRPC 客户端中打开安全通道

How to open a secure channel in python gRPC client without a client SSL certificate

我有一个 grpc 服务器(在 Go 中),它具有有效的 TLS 证书并且不需要客户端 TLS。出于某种原因,我无法在 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(ORBIUM_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)
}

我的猜测基于 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())

如果server-side上的证书是公开签名的,可以使用:

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/

https://grpc.github.io/grpc/python/_modules/grpc.html#secure_channel has the docs for channel = grpc.secure_channel(ORBIUM_ADDR, grpc.ssl_channel_credentials()). This function relies on the class channel, see docs https://grpc.github.io/grpc/python/_modules/grpc/aio/_channel.html.

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