ListenAndServeTLS 在本地运行 - x509:由 docker 中的未知权威签名的证书

Jim*_*mbo 4 ssl go docker

我正在使用mkcert生成自签名证书和授权。当我在本地使用这些文件时ListenAndServeTLS,我可以成功连接 cURL。我的主机操作系统是 MacOS。

但是,当尝试在 docker 容器中运行此 Go 代码时,出现以下错误:

x509:由未知机构签署的证书

许多其他帖子表明问题ca-certificates没有安装,应该运行:apk add ca-certificates. 我已经这样做了,我仍然有问题。


生成证书

mkcert -cert-file ./cert.pem -key-file ./key.pem localhost
Run Code Online (Sandbox Code Playgroud)

这意味着证书对域“localhost”有效,可通过 https://localhost 访问。

在 Go 中加载证书和权限

    // Load cert + key.
    cert, _ := tls.LoadX509KeyPair("cert.pem", "key.pem")

    // Load our CA. (Mkcert also generates this btw, check the docs).
    caCert, _ := ioutil.ReadFile("rootCA.pem")

    // Add our CA so it's considered an acceptable rootCA.
    rootCAs, _ := x509.SystemCertPool()
    rootCAs.AppendCertsFromPEM(caCert)

    server := http.Server{
        Addr:    ":1234",
        Handler: router,
        TLSConfig: &tls.Config{
            Certificates: []tls.Certificate{cert},
            RootCAs:      rootCAs,
        },
    }

    _ = server.ListenAndServeTLS("", "")
Run Code Online (Sandbox Code Playgroud)

这运行良好并在本地工作。

将其放入 docker 容器中

ARG GO_VERSION=1.14

FROM golang:${GO_VERSION}-alpine AS builder

RUN apk add --no-cache ca-certificates git curl

ENV CGO_ENABLED=0

WORKDIR /app

COPY go.mod .
COPY go.sum .
RUN go mod download

COPY . /app

RUN go build -o ./bin/app .

FROM alpine AS final

WORKDIR /app

COPY --from=builder /user/group /user/passwd /etc/

COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/

COPY --from=builder /app/bin/app /app

ENTRYPOINT ["./app"]
Run Code Online (Sandbox Code Playgroud)

docker-compose 文件

    my-app:
        build:
            context: ./
            dockerfile: Dockerfile
        ports:
            - 1234:1234
Run Code Online (Sandbox Code Playgroud)

运行上述容器并通过 TLS 连接时,我收到上述未知权限错误。

我错过了什么?

col*_*tor 7

问题在于您的多阶段Dockerfile. 当您复制第一阶段的所有必要工件(源、证书等)时,最后阶段您只复制二进制文件bin/app

COPY --from=builder /app/bin/app /app
Run Code Online (Sandbox Code Playgroud)

您还需要复制服务运行时使用的 PEM 文件:

COPY --from=builder \
    /app/cert.pem \
    /app/key.pem  \
    /app/rootCA.pem \
        /app/
Run Code Online (Sandbox Code Playgroud)

错误检查

无论操作看起来多么微不足道,始终检查错误(和布尔值返回):

cert, err := tls.LoadX509KeyPair("cert.pem", "key.pem")
if err != nil {
    log.Fatalf("failed to load server key pairs: %v", err)
}

rootCAs, err := x509.SystemCertPool()
if err != nil {
    log.Fatalf("failed to load system keychain: %v", err)
}

caCert, err := ioutil.ReadFile("rootCA.pem")
if err != nil {
    log.Fatalf("failed to read CA trust file rootCA.pem: %v", err)
}

ok := rootCAs.AppendCertsFromPEM(caCert)
if !ok {
    log.Fatal("failed to load CA trust: bad PEM format?")
}

log.Fatalf(
    "server error: %v",  // e.g. "port in use" 
    server.ListenAndServeTLS("", ""),
)
Run Code Online (Sandbox Code Playgroud)

像这样严格的错误检查将很快发现像这样的 Docker 构建问题。