'docker multi-stage build Go image - x509: certificate signed by unknown authority

I try to build images in private corp network use :

FROM golang:latest as builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN  GO111MODULE="on" CGO_ENABLED=0 GOOS=linux go build -o main ${MAIN_PATH}

FROM alpine:latest
LABEL maintainer="Kozmo"
RUN apk add --no-cache bash
WORKDIR /app
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]

and get x509: certificate signed by unknown authority error

Step 1/13 : FROM golang:latest as builder
 ---> 2421885b04da
Step 2/13 : WORKDIR /app
 ---> Using cache
 ---> 6555644dbd16
Step 3/13 : COPY go.mod go.sum ./
 ---> 55d45a30f492
Step 4/13 : RUN go mod download
 ---> Running in 88c21c6b4fab
go: github.com/dgrijalva/jwt-go/[email protected]: Get "https://proxy.golang.org/github.com/dgrijalva/jwt-go/v4/@v/v4.0.0-preview1.mod": x509: certificate signed by unknown authority
The command '/bin/sh -c go mod download' returned a non-zero code: 1
make: *** [docker] Error 1

I tried to find an answer in

X509: Certificate Signed by Unknown Authority (Running a Go App Inside a Docker Container)

and

docker build: cannot get the github public repository, x509: certificate signed by unknown authority

and

x509 certificate signed by unknown authority - go-pingdom

, but result is the same.


❗️If add -insecure flag

...
RUN go env -w GOPROXY=direct GOFLAGS="-insecure"
COPY go.mod go.sum ./
...

to Dockerfile 👉🏻 unrecognized import path error wrap previous x509 error and an unreachable package change to golang.org/x/crypto

go: golang.org/x/[email protected]: unrecognized import path "golang.org/x/crypto": https fetch: Get "https://golang.org/x/crypto?go-get=1": x509: certificate signed by unknown authority

What is the problem❓

(I understand that problem is in the certificates and authentication when git get dependencies, but I try to make process of building images more common)



Solution 1:[1]

? Coping self certificates (.crt) helped

1?? add .crt to required dir

.
??? backend
    ??? Dockerfile
    ??? Makefile
    ??? cmd
    ?   ??? main.go
    ??? etc
    ?   ??? ssl
    ?   ?   ??? github.crt #??a copy of the self certificate 

2?? COPY certificates to 'builder'-container

FROM golang:latest as builder
COPY  etc/ssl/ /etc/ssl/certs/ #??add certificates to the container 
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download

Solution 2:[2]

I'll suggest a couple of things:

  • Build your code within the same OS distribution as the final code image, so that you are sure that your code will run in that specific distribution. Also some distributions require certs to be in different folders, so be aware of that.
  • Using alpine for the first image will substantially decrease your build time. You can see here latest size is ~260M, but alpine is ~100M.
  • Better will be to use an specific version of alpine, so that you can be sure that your code runs in that version (I leave this at your discretion)
  • Something very powerful of Golang is that you can run it in an empty docker image called scratch, this means, your final docker images does not contain more than your own executable.
  • If you need your own certificates you must have them in your code and copy them before executing update-ca-certificates so that they get included in the final file

Here's an example of the dockerfile with what I explained above

FROM golang:alpine as builder
WORKDIR /app

# This will download all certificates (ca-certificates) and builds it in a
# single file under /etc/ssl/certs/ca-certificates.crt (update-ca-certificates)
# I also add git so that we can download with `go mod download` and
# tzdata to configure timezone in final image
RUN apk --update add --no-cache ca-certificates openssl git tzdata && \
update-ca-certificates

COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN  GO111MODULE="on" CGO_ENABLED=0 GOOS=linux go build -o main ${MAIN_PATH}

# Golang can run in a scratch image, so that, the only thing that your docker 
# image contains is your executable
FROM scratch
LABEL maintainer="Kozmo"
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo

# This line will copy all certificates to final image
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
WORKDIR /app
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]

If own certificates replace first docker stage with:

FROM golang:alpine as builder
WORKDIR /app

RUN apk --update add --no-cache ca-certificates openssl git tzdata

COPY your/cert/path /usr/local/share/ca-certificates/your-cert-name

RUN update-ca-certificates

COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN  GO111MODULE="on" CGO_ENABLED=0 GOOS=linux go build -o main ${MAIN_PATH}

Because you use own certificates your final Dockerfile will look like this:

FROM golang:alpine as builder
WORKDIR /app

RUN apk --update add --no-cache ca-certificates openssl git tzdata

COPY your/cert/path /usr/local/share/ca-certificates/your-cert-name

RUN update-ca-certificates

COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN  GO111MODULE="on" CGO_ENABLED=0 GOOS=linux go build -o main ${MAIN_PATH}

FROM scratch
LABEL maintainer="Kozmo"
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo

# This line will copy all certificates to final image
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
WORKDIR /app
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]

Feel free to ask me if you have any doubt :)

Solution 3:[3]

From your error message

Get "https://proxy.golang.org/github.com/dgrijalva/jwt-go/v4/@v/v4.0.0-preview1.mod": x509: certificate signed by unknown authority

It looks like the CA root of proxy.golang.org is not part of the trusted root CAs in your private corp docker environment.

I'd try to install it with :

1 - Get the certificate from proxy.golang.org :

echo -n | openssl s_client -connect proxy.golang.org:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ./golang.cer

If you open golang.cer you should see the certificates chain

enter image description here

2 - install it in your trusted root CAs :

certutil.exe -addstore root golang.cer

...or on Mac :

2a - Double click the certificate file (with ".cer" extension)

2b - Choose "System" from the keychain option. Then press "OK"

2c - When the following window pops-up, click the "Always Trust" button.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3