GPRC背后的GPRC返回证书错误,在没有代理的情况下正常工作



我有一个grpc客户端和服务器,均为SSL证书确保。在这些工作之间没有依靠的情况下。作为测试,当我故意创建错误的证书时,它会失败。在本文的稍后证明这不是证书问题。

GRPC服务器代码:

// Creates a new gRPC server
// Create the TLS credentials
creds, err := credentials.NewServerTLSFromFile("configs/cert/servercert.pem", "configs/cert/serverkey.pem")
if err != nil {
    log.Fatalf("could not load TLS keys: %s", err)
}
// Create an array of gRPC options with the credentials
opts := []grpc.ServerOption{grpc.Creds(creds)}
// create a gRPC server object
s := grpc.NewServer(opts...)

GRPC客户端代码:

// Create the client TLS credentials
creds, err := credentials.NewClientTLSFromFile("configs/cert/servercert.pem", "")
if err != nil {
    log.Fatalf("could not load tls cert: %s", err)
}
conn, err := grpc.Dial(grpcUri, grpc.WithTransportCredentials(creds))
if err != nil {
    log.Fatalf("Unable to connect: %v", err)
}

现在,我正在尝试使用前向代理(IVE测试并在正常的HTTP API请求下工作正常(。但是,它经常通过代理人的GRPC请求失败。

我正在使用内部使用Goproxy和以下设置的cuttle。请注意,InsecureSkipVerify布尔值已尝试truefalse。有了我(有限的(对SSL的理解,它需要是false,因为它将在线检查证书,并且自然而然地签名会失败。但是,我再次尝试了truefalse

// Config proxy.
proxy := goproxy.NewProxyHttpServer()
proxy.Tr = &http.Transport{
    // Config TLS cert verification.
    TLSClientConfig: &tls.Config{InsecureSkipVerify: !cfg.TLSVerify},
    Proxy:           http.ProxyFromEnvironment,
}

在GRPC客户端和服务器之间运行代理会导致以下错误:

运输:身份验证握手失败:X509:签名证书 由未知的权威(可能是因为" X509:无效的签名(: 父证书无法签署此类证书"尝试 验证候选当局证书"测试服务器"

这表明这是证书问题,但是,GRPC在没有代理的情况下完美无缺,如前所述。

还注意:我不想在代理后面运行GRPC,但由于开发环境而被迫进行。GRPC服务器和代理在同一台Docker机器上运行。拥有相同的IP地址将导致以下配置,这将相互取消(相信我,无论如何我都尝试过(。

ENV http_proxy 192.168.99.100:3128
ENV https_proxy 192.168.99.100:3128
ENV no_proxy 192.168.99.100 # <- this would be the gRPC server IP, which is the same as the proxy. resulting in nothing being run through a proxy.

将Docker中寻址的IP分开将解决此问题,但是,我什么也没学,想解决这个问题。我尝试了像在此处回答的配置一样设置不同的docker内部IP,但是,IP将保持空(仅设置网络(,并且在新IP上访问将只是超时。

背景:

TLS连接的每一端都需要预先安排的信任。大多数客户在连接到远程主机时使用系统信任链(GeoTrust,Digicert CA的可信赖证书都在此处列出,并允许您安全地进入https://facebook.com,https://google.com等网站。(

go使用TLS时,在联系服务器时将默认为系统 - 信任链。在开发自定义解决方案时,您的应用程序服务器的公共证书可能不是在此系统 - 信任链中。因此,您有两个选择:

  • 通过InsecureSkipVerify: true禁用信任(不要这样做!(
  • 向您的客户添加自定义信托

您的应用程序服务器很可能具有自签名的证书,因此很容易获得公开证书。您还可以使用openSSL之类的工具查看服务器的公共证书 - 使用链接解决方案,您不仅可以为自己的开发服务器,而且其他任何远程服务获取公共证书 - 只需提供主机名和端口即可。


因此,只是为了总结您的情况。您有:

Client <- TLS -> Server

但要:

Client <-TLS-> Proxy <-TLS-> Server

因此,现在您的客户端现在不信任服务器现在需要信任代理,因为它只直接与代理直接交谈。代理很可能会具有自签名证书(请参见上文有关如何提取信任证书(。一旦拥有此功能,更新您的go代码以使用此自定义信任文件,例如:

// Get the SystemCertPool, continue with an empty pool on error
rootCAs, err := x509.SystemCertPool() // <- probably not needed, if we're only ever talking to this single proxy
if err != nil || rootCAs == nil {
    rootCAs = x509.NewCertPool()
}
// Read in the custom trust file
certs, err := ioutil.ReadFile(localTrustFile)
if err != nil {
    log.Fatalf("Failed to append %q to RootCAs: %v", localTrustFile, err)
}
// Append our cert to the system pool
if ok := rootCAs.AppendCertsFromPEM(certs); !ok {
    log.Fatalf("failed to append custom cert")
}
tlsConfig := &tls.Config{
    RootCAs: rootCAs,
}

代理也需要信任服务器 - 因此,如果服务器的证书不在系统 - trust-Chain中,那么它将需要类似的tls.config设置。

相关内容

最新更新