Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save jrapoport/d12f60029eef017354d0ec982b918258 to your computer and use it in GitHub Desktop.
Save jrapoport/d12f60029eef017354d0ec982b918258 to your computer and use it in GitHub Desktop.
How to use different ssh deploy keys for multiple private github repositories with Golang Modules (go mod)

How to use different ssh deploy keys for multiple private github repositories with Go Modules

Let's assume you are using Go Modules and have a go.mod file that contains multiple private repos each with a different ssh key. How can you get go mod download to do the right thing -- i.e. use ssh key A with private repo A and ssh key B with private repo B?

Ok, here we go!

Let's assume you have some github.com user with multiple private repos:

https://github.com/someuser/private-repo-1

https://github.com/someuser/private-repo-2

and a go.mod file that looks something like this:

module github.com/alice/repo

go 1.11

require (
	github.com/someuser/private-repo-1 v0.0.0
	github.com/someuser/private-repo-2 v0.0.0
	github.com/bob/public-repo v0.0.0
)

As part of an automated process (e.g. running go mod download in a Docker container) you need to clone these private repos without using a password and make sure that you use the right key with its corresponding repo.

(I'm skipping over all the ways to try and get this to work that don't)

In order to access the repos we are going to use Github deploy keys. Because a given deploy key can only be added to one specific repo, you'll need to generate a keypair for each:

$ ssh-keygen -t ecdsa -C "someuser@domain.com"
...
> private1_id_ecdsa, private1_id_ecdsa.pub # keys for private-repo-1

$ ssh-keygen -t ecdsa -C "someuser@domain.com"
...
> private2_id_ecdsa, private2_id_ecdsa.pub # keys for private-repo-2

Next you'll add each key to its corresponding repo via Settings > Deploy keys in Github:

private1_id_ecdsa.pub => github.com/someuser/private-repo-1

private2_id_ecdsa.pub => github.com/someuser/private-repo-2

Now you'll need to tell your ssh client what private key to use for which repo. Open up ~/.ssh/config and add:

Host private1.github.com
  HostName github.com
  IdentityFile ~/.ssh/private1_id_ecdsa
  IdentitiesOnly yes
  
Host private2.github.com
  HostName github.com
  IdentityFile ~/.ssh/private2_id_ecdsa
  IdentitiesOnly yes

This tells ssh when it sees a repo at private1.github.com/foo to use the private1_id_ecdsa deploy key, and likewise a repo at private2.github.com/bar should use the private2_id_ecdsa deploy key.

Ok great, but your repos are github.com/someuser/private-repo-1 and github.com/someuser/private-repo-1, so how can we make this work correctly with go mod download?

Bring the Magic

Edit your ~/.gitconfig file and add:

[url "git@private1.github.com:someuser/private-repo-1"]
        insteadOf = https://github.com/someuser/private-repo-1

[url "git@private2.github.com:someuser/private-repo-2"]
        insteadOf = https://github.com/someuser/private-repo-2

Now when go mod download encounters a url in your mod file like https://github.com/someuser/private-repo-1 it will automagicallly rewrite the host so your ~/.ssh/config picks it up correctly and uses the right key. \:D/ Yay!

p.s. You won't need to use GOPRIVATE when calling go mod -- it will just work -- but you might want to anyway if you're concerned about info leakage.

@jstangroome
Copy link

Very nice combination of SSH config aliases and git config insteadOf. Thanks for such a well written example.

@jrapoport
Copy link
Author

Very nice combination of SSH config aliases and git config insteadOf. Thanks for such a well written example.

Thanks for the kind words.

@antimatter96
Copy link

I can't thank you enough
You are a life saver

@Ivasan7
Copy link

Ivasan7 commented Dec 10, 2021

Lifesaver! Thanks a lot! 😻

@GaikwadPratik
Copy link

@jrapoport ,

Thank you for the gist. it explains things so nicely...

I have a question. Can we use ssh key defined for all the private repositories under a specific user instead of creating separate keys for different repository? Basically, I've created SSH key for my work account, can I use it to go get for all of the private repositories under that account?

Awaiting your response

@Ivasan7
Copy link

Ivasan7 commented Mar 4, 2022

@GaikwadPratik

The question is not for me directly, but here is my experience any way :)

So the simple answer yes. It is called a machine user, in my opinion it has two major disadvantages though:

  • takes a Github seat in your repo if it is an organisation
  • by using one key you create a bigger security risk, because if the key is compromised the attacker would have access to everything

This is exactly the reason Github discourages this kind of approach and introduced the Deploy key concept. Here the your only limiatation is as it is mentioned before that you have to have a separate key per repository. This is slightly more inconvenient and requires more bookkeeping, however a safer AND more granular approach. Youn can easily limit access to certain keys to certain repos, via org secret access per repo.

Hope this makes sense and useful for you.

Cheers,

Sandor

@GaikwadPratik
Copy link

GaikwadPratik commented Mar 4, 2022

@Ivasan7 ,

Thank you for explaining...

I get the security implications. But I want to try it out for something. There is another disadvantage of adding key per repo. You have to add it for every user that is going to have access to that repo. If one key is compromised for that repo, you have to ask all the users to change the keys. And furthermore, in order to be able to add/update the keys you need to have admin access to the repo(which is very dangerous in my opinion that every user has admin access) or admin has to manage the keys all the time.

Can you also explain how you did it, or what steps I have to take, on my side to enable it?

@jrapoport
Copy link
Author

as @Ivasan7 alluded to, @GaikwadPratik - it's really a question for gh support. If a given ssh key has access to a given repo, it will work. The issue is whether or not gh allows it. For a gh deploy key, gh prevents you from using your ssh key with more than one repo. As @Ivasan7 mentioned, you can work around that by using a machine account, but with serious tradeoffs.

@GaikwadPratik
Copy link

@jrapoport,

so I've two keys. One for my personal account and the other for work account. When I clone the work repo, I have to use git@github.com-work:workorg/repo.git. my ssh config is as follows:

#personal repo
Host gitHub.com 
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_rsa
  IdentitiesOnly yes
  
 #work repo
Host github.com-work
  HostName github.com
  User git
  IdentityFile ~/.ssh/work
  IdentitiesOnly yes

so my question, is there a way to use nameoforgkeyinsshconfig for go get of private repo of work organization in work repositories only?

@jtcho
Copy link

jtcho commented Jul 15, 2022

Thank you very much for this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment