首页 > 解决方案 > 为什么 C# Google.Cloud.Firestore 库无法与企业 MITM 防火墙连接?

问题描述

来自库的特定错误消息

CompletedListGrpc.Core.RpcException:状态(状态代码=不可用,详细信息=“连接失败”)

当 firestore.googleapis.com 的防火墙 MITM 功能被禁用时,该库可以正常工作。启用 MITM 功能后,它不起作用。

子问题:

1)图书馆代码是否有硬编码证书检查?(我找不到一个)

https://github.com/googleapis/google-cloud-dotnet/blob/master/apis/Google.Cloud.Firestore.V1/Google.Cloud.Firestore.V1/FirestoreClient.cs#L550 Line ~550

public static gaxgrpc::ServiceEndpoint DefaultEndpoint { get; } = new gaxgrpc::ServiceEndpoint("firestore.googleapis.com", 443);

2a) .Net Framework 是否自动信任 Windows 信任库中的证书?是否需要任何代码才能完成这项工作?

.Net Framework 似乎适用于 Windows 证书存储 - 请参阅https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/working-with-certificates

2b)也许证书只是受信任的,但交互式用户,而不是整个机器,因此服务帐户看不到该证书 - 我会检查这个......

3)如果这是“连接失败”的原因,图书馆是否会有关于证书的特定错误?

标签: .netsslgoogle-cloud-firestorefirewallwindows-server-2008-r2

解决方案


这可能是 GRPC 和 Windows 证书存储之间的问题。无论这是 GRPC(而不是 .Net)的基本问题还是由于在不同的帐户下运行它,将防火墙的正确根 CA 硬编码到应用程序中肯定会让您完全控制。

您可能能够覆盖 DefaultEndpoint/Channel 以使用您自己的 ServicePoint,其中还包括硬编码证书

请参阅C# 中对 GRPC 的 TLS 支持

  var cacert = File.ReadAllText(@"../ca.crt");
  var clientcert = File.ReadAllText(@"../client.crt");
  var clientkey = File.ReadAllText(@"../client.key");
  var ssl = new SslCredentials(cacert, new KeyCertificatePair(clientcert, clientkey));
  var channel = new Channel("firestore.googleapis.com", 443, ssl);
  //etc..

创建您自己的端点,然后显式提供它,以便它覆盖 DefaultEndpoint。这是您将使用您的频道调用的函数。(见https://github.com/googleapis/google-cloud-dotnet/blob/master/apis/Google.Cloud.Firestore.V1/Google.Cloud.Firestore.V1/FirestoreClient.cs#L550

public static FirestoreClient Create(grpccore::Channel channel, FirestoreSettings settings = null)
{
    gax::GaxPreconditions.CheckNotNull(channel, nameof(channel));
    return Create(new grpccore::DefaultCallInvoker(channel), settings);
}

另外,好好看看 SslCredentialsTest 代码 - https://github.com/grpc/grpc/blob/master/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs

注意:通常会使用 s_channelPool 创建一个通道。如果您手动创建它,它可能不会使用池 - 可能没有办法做到这一点。这对你来说可能是也可能不是问题。


您可以扩展它以在运行时按名称从 Windows 证书存储中手动读取公共证书信息,选择最新的。这意味着您可以使用 app.config 分配证书的 CN 以从 Windows 证书存储区获取,然后您无需手动发送软件的更新版本。


此链接似乎表明默认情况下“公共受信任的根”是受信任的:https ://forum.predix.io/questions/30875/event-hub-c-client-how-to-deal-with-the-tls-证书.html

var channel = new Channel("greeter.googleapis.com", new SslCredentials());  // Use publicly trusted roots.

这意味着尽管 firestore 没有“硬编码”的特定证书,但它通常不会与 Windows 证书存储集成,因此任何自定义安装的根 CA 都不受信任。

更仔细地查看库源代码 [ https://github.com/googleapis/gax-dotnet/blob/master/Google.Api.Gax.Grpc/ChannelPool.cs]

public Channel GetChannel(ServiceEndpoint endpoint, IEnumerable<ChannelOption> channelOptions)
{
    GaxPreconditions.CheckNotNull(endpoint, nameof(endpoint));
    var credentials = _lazyScopedDefaultChannelCredentials.Value.ResultWithUnwrappedExceptions();
    return GetChannel(endpoint, channelOptions, credentials);
}

凭据参数是自动填充的,在 , 之后_lazyScopedDefaultChannelCredentialsGoogleCredential.GetApplicationDefaultAsync()我们最终CreateDefaultCredentialAsync会指向您的 Google 服务文件,该文件可能是您从某处的 firebase 下载的。

https://github.com/googleapis/google-api-dotnet-client/blob/master/Src/Support/Google.Apis.Auth/OAuth2/DefaultCredentialProvider.cs

笔记:

这个答案很有可能只会导致自定义客户端凭据,而不是为自定义服务器端根 CA 提供硬编码凭据的能力。


推荐阅读