Golang中解决Grpc未知证书授权错误的方法

Golang中解决Grpc未知证书授权错误的方法 嗨!

我之前有一个托管在 Google App Engine 标准版上的 Web 应用程序,由于现在需要使用 WebSocket API,我将其迁移到了 Google Compute Engine,并使用 Google Datastore 作为数据库。

因此我创建了一个 Dockerfile:

FROM scratch
COPY ./cmd ./
STOPSIGNAL SIGTERM
EXPOSE 80/tcp
EXPOSE 443/tcp
ENV GRPC_GO_LOG_SEVERITY_LEVEL INFO
CMD ["/hello-datastore"]

将编译后的应用程序作为二进制文件嵌入容器中,并将镜像发布到注册表(Google Cloud Registry)。然后从容器镜像(容器优化操作系统)在 Google Cloud Platform 上启动一个实例(虚拟机)并运行应用程序。

在我的 main.go 中:

//import the datastore client
import cloud.google.com/go/datastore

//create a new client
client, err := datastore.NewClient(ctx, *projectID)
if err != nil {
	log.Fatal(err)
}

//Puting an entity fails silently.
key := datastore.NameKey("testEntity", "milk", nil)
key.Namespace = "test"
task := &TestEntity{Description: "Buy milk"}
if _, err := client.Put(ctx, key, task); err != nil {
      log.Fatalf("Put: %v", err)
}

将 GRPC_GO_LOG_SEVERITY_LEVEL 设置为 INFO 可以显示底层 gRPC 调用的详细信息,但出现了 “x509: unknown certificate authority” 的错误。

INFO: 2018/12/24 15:40:25 Subchannel Connectivity change to CONNECTING
INFO: 2018/12/24 15:40:25 pickfirstBalancer: HandleSubConnStateChange: 0xc000167930, CONNECTING
WARNING: 2018/12/24 15:40:25 grpc: addrConn.createTransport failed to connect to {datastore.googleapis.com:44
3 0  }. Err :connection error: desc = "transport: authentication handshake failed: x509: certificate sig
ned by unknown authority". Reconnecting…
INFO: 2018/12/24 15:40:25 Subchannel Connectivity change to TRANSIENT_FAILURE
INFO: 2018/12/24 15:40:25 pickfirstBalancer: HandleSubConnStateChange: 0xc000167930, TRANSIENT_FAILURE

更多关于Golang中解决Grpc未知证书授权错误的方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

确实如此!我刚刚使用了多阶段Docker构建文件,基于alpine:latest镜像构建只是为了获取ca-certificates,然后将其复制到最终镜像中(基于scratch镜像,附加了bin和/etc/ssl/certs/ca-certificates.crt文件)

谢谢

更多关于Golang中解决Grpc未知证书授权错误的方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


验证由CA颁发的证书需要一个包含各种可信CA机构证书的"根证书存储库"。操作系统通常会自带这样的存储库,但您没有将其包含在容器中。因此,在容器中运行的程序无法验证其他证书。

您需要在容器构建时添加包含根证书的软件包。

// 代码示例保留原样
func main() {
    fmt.Println("hello world")
}

在Golang中遇到gRPC的"x509: unknown certificate authority"错误通常是因为容器环境中缺少根证书。以下是几种解决方案:

方案1:使用包含根证书的基础镜像

将你的Dockerfile从scratch改为包含根证书的基础镜像:

FROM alpine:latest
RUN apk --no-cache add ca-certificates
COPY ./cmd /hello-datastore
STOPSIGNAL SIGTERM
EXPOSE 80/tcp
EXPOSE 443/tcp
ENV GRPC_GO_LOG_SEVERITY_LEVEL INFO
CMD ["/hello-datastore"]

方案2:在scratch镜像中手动添加证书

FROM scratch
COPY ./cmd /hello-datastore
COPY --from=alpine:latest /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
STOPSIGNAL SIGTERM
EXPOSE 80/tcp
EXPOSE 443/tcp
ENV GRPC_GO_LOG_SEVERITY_LEVEL INFO
CMD ["/hello-datastore"]

方案3:编译时静态链接证书

在Go代码编译时,确保启用CGO并静态链接证书:

// 在编译时使用这些标志:
// CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o cmd/hello-datastore .

对应的Dockerfile:

FROM scratch
COPY ./cmd/hello-datastore /
COPY certs/ca-certificates.crt /etc/ssl/certs/
STOPSIGNAL SIGTERM
EXPOSE 80/tcp
EXPOSE 443/tcp
ENV GRPC_GO_LOG_SEVERITY_LEVEL INFO
CMD ["/hello-datastore"]

方案4:自定义TLS配置(不推荐用于生产)

如果只是测试,可以跳过证书验证:

import (
    "crypto/tls"
    "google.golang.org/api/option"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
)

func createInsecureClient(ctx context.Context, projectID string) (*datastore.Client, error) {
    tlsConfig := &tls.Config{
        InsecureSkipVerify: true,
    }
    creds := credentials.NewTLS(tlsConfig)
    
    return datastore.NewClient(ctx, projectID, option.WithGRPCDialOption(
        grpc.WithTransportCredentials(creds),
    ))
}

推荐方案

对于生产环境,推荐使用方案1或方案2。使用Alpine基础镜像是最简单可靠的方法:

FROM alpine:latest
RUN apk --no-cache add ca-certificates tzdata
COPY ./cmd/hello-datastore /hello-datastore
STOPSIGNAL SIGTERM
EXPOSE 80/tcp
EXPOSE 443/tcp
ENV GRPC_GO_LOG_SEVERITY_LEVEL INFO
CMD ["/hello-datastore"]

这样确保容器中包含完整的根证书链,能够验证Google服务的TLS证书。

回到顶部