Since the release of 1.13, Go has native Go Modules support, with
go mod. Similar to other tooling in the Go ecosystem, like
go fmt for code formatting, it is intended to be the default, community-concended approach to dependency management. It supersedes existing approaches, such as Glide and Dep, and integrates smoothly within the existing Go workflow.
It works out of the box, without any additional configuration.
However, that is only true when all dependencies are publicly available. With dependencies on private packages, additional configuration is needed.
Resolving dependencies over SSH instead of HTTPS
Without any additional steps, trying to load a private dependency into the Go Modules project, will result in the following error:
go: downloading github.com/myorg/privaterepo v0.0.0-20200408100711-ed766a2975ce
go get github.com/myorg/privaterepo: github.com/myorg/[email protected]: verifying module: github.com/myorg/[email protected]: reading https://sum.golang.org/lookup/github.com/myorg/[email protected]: 410 Gone
not found: github.com/myorg/[email protected]: invalid version: git fetch -f origin refs/heads/*:refs/heads/* refs/tags/*:refs/tags/* in /tmp/gopath/pkg/mod/cache/vcs/13e63a509893edc19353a80fa2c6e28db213d146f72fe43ba65c1ec86624027b: exit status 128:
fatal: could not read Username for 'https://github.com': terminal prompts disabled
The problem here is that, by default, Go’s dependency resolving approach attempts to download the package with git over HTTPS.
We want to (instead of using HTTPS) download the private dependency over SSH, such that we can use the local SSH keys to gain access to the package repository. This assumes that you have configured SSH with credentials that can access the private repositories. If you have not, Github has an excellent tutorial how to set it up.
Because this is not something we can change in Go, what we can do is to configure git to rewrite all HTTPs to the equivalent git URLs:
By-passing GOPROXY for private dependencies
Although this has been resolved in the newer versions of Go, in earlier versions resolving the dependencies over SSH still does not completely solve the issue. When we try to download the private dependency, with the SSH patch, the following error will occur:
go: github.com/myorg/[email protected]: reading https://proxy.golang.org/github.com/myorg/privaterepo/@v/v0.0.0-20200512204819-655dcc74320a.mod: 410 Gone
This error occurs due to the introduction of a new default for
GOPROXY in Go 1.13. From that version on, Go uses a module mirror (https://proxy.golang.org) to resolve the modules. This mirror obviously will not contain or be able to find the private repositories.
To fix this, there are a couple of options:
GOPROXY A crude solution to resolve this issue is to simply skip the proxy. This will avoid Go to hit the intermediate proxy servers completely and directly contact Github. To do this, set:
Another option is to specifically mark packages as private by adding them to
GOPRIVATE. You can either mark specific packages:
Alternatively, you could mark all packages in your organization as private:
To permanently use this fix, you can either export these variables in your shell start-up scripts, or you can override the defaults of Go:
go env -w
To verify that the changes have persisted, you can see the environment used for Go commands with:
go env | grep 'GOPROXY\|GOPRIVATE'
With the fixes in place you should be able to access all private repositories that you can accessible with your loaded SSH credentials. In case, you want to use HTTPS or cannot rely on SSH, there are alternative (in my opinion, more cumbersome) documented approaches that rely on Github access tokens.
- General introduction to the workflow around go modules: https://blog.golang.org/using-go-modules
- The what and why around Go module proxies: https://arslan.io/2019/08/02/why-you-should-use-a-go-module-proxy
- About Go modules in general: https://golang.org/doc/go1.13#modules