当前位置: 首页 > 知识库问答 >
问题:

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

拓拔欣嘉
2023-03-14

我有一个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)
}

现在我正在尝试使用一个转发代理(我已经测试过了,在正常的HTTP api请求上运行良好)。但是,它通过代理不断地在gRPC请求时失败。

我使用的是cuttle,它在内部使用goproxy,并具有以下设置。请注意,unsecureskipverify布尔值已在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上访问将超时。

共有1个答案

楚建柏
2023-03-14

背景:

TLS连接的每一端都需要预先安排的信任。大多数客户端在连接到远程主机时使用系统信任链(GeoTrust、DigiCert CA的受信任证书都列在那里,允许您安全地访问以下站点:https://facebook.com, https://google.com)

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

  • 通过unsecureskipverify: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,
}

代理还需要信任服务器-因此,如果服务器的证书不在系统信任链中,则需要类似的tls。像上面一样配置设置。

 类似资料:
  • 我刚刚通过nodejs.org上的软件包安装了node和npm,每当我试图搜索或安装npm时,它都会抛出以下错误,除非我执行该命令。我觉得这是一个权限问题?我已经是管理员了。

  • 我需要将数据发布到REST接口,但是接收主机使用的是自签名证书(这一点不会改变),因此我需要忽略我收到的明显的证书验证错误。 我的初始脚本如下所示: 如前所述,这将生成以下StackTrace: 回溯(最近一次调用):文件“send_data.py”,第15行,在urlopen(post_it_早已,context=ctx)文件“c:\users\myusername\appdata\local\

  • 我正在尝试将嵌套映射转换为JSONObject,如下所示: (我试着按照这个例子放HashMap 我这样称呼它 我不明白的是为什么 null?据我所知,返回一个

  • 问题内容: 我在编写一个简单的shell脚本,发现我的shell脚本不需要shebang行 如果我授予脚本执行权限,并使用执行。运行正常。 我正在使用shell,实际上是指向。 我知道shebang行用于告诉shell在您的其余脚本中使用哪个解释器。 如果我错过了perl中的shebang行,请赋予执行权限并运行,它不起作用。 这里到底发生了什么?如果使用,实际上何时需要shebang行? 问题答