coffeequant
coffeequant

Reputation: 615

How do I use multiple SSH keys on GitHub?

The SSH configuration on GitHub seems to be a nightmare. I have multiple GitHub accounts, but for which I can have multiple SSH keys. In the GitHub SSH configuration section they mention this:

ssh-keygen -t rsa -C "your_email@example.com"
# Creates a new ssh key, using the provided email as a label
# Generating public/private rsa key pair.

We strongly suggest keeping the default settings as they are, so when you're prompted to "Enter a file in which to save the key", just press Enter to continue.

# Enter file in which to save the key (/Users/you/.ssh/id_rsa): [Press enter]

Why should I always use an id_rsa file? It will overwrite my existing keys. Anyway, I give a new name here and generate the key. I do all the other steps of adding it to the agent, updating in the GitHub SSH keys section.

After completing all those steps I come to the final step which is:

$ ssh -vT git@github.com
Hi animesh11! You've successfully authenticated, but GitHub does not provide shell access.
debug1: channel 0: free: client-session, nchannels 1
Transferred: sent 3128, received 1976 bytes, in 0.5 seconds
Bytes per second: sent 6077.0, received 3838.9
debug1: Exit status 1

Everything is hunky dory, but somehow git clone still complains:

$ git clone git@github.com:regentmarkets/devbox.git
Cloning into 'devbox'...
ERROR: Repository not found.
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

I am up to my wits end why the ssh -vT works and simple cloning doesn't.

Upvotes: 27

Views: 22598

Answers (7)

ANDgineer
ANDgineer

Reputation: 710

If you can keep repositories that are accessed by different SSH keys in different folders, you can follow the steps below:

  1. Generate SSH keys for each identity (work and home) by running the following commands in your terminal:
ssh-keygen -t rsa -C "andrei@work.com"  # Put into default file ~/.ssh/id_rsa
ssh-keygen -t rsa -C "andrei@home.com"  # Put into ~/.ssh/home
  1. Keep your work projects in the folder <..>/projects/work/.

  2. Create SSH configuration file ~/.ssh/config:

Match host github.com exec "[[ $PWD == *projects/work* ]]"
    IdentityFile ~/.ssh/id_rsa

Host github.com
    IdentityFile ~/.ssh/home

The Match host github.com exec "[[ $PWD == *projects/work* ]]" section specifies that when you are in a directory that contains "projects/work" in its path, use the ~/.ssh/id_rsa SSH key.

In all other folders like projects/fun git will use for github.com the SSH key ~/.ssh/home.

So you can use git clone even in not git folder (like in projects/work).

Upvotes: 6

Ben
Ben

Reputation: 5432

I know that this question is about GitHub, but GitLab has a very elegant solution for this issue, where you can set what SSH key is used on a per directory / repository basis.

git config core.sshCommand "ssh -o IdentitiesOnly=yes -i ~/.ssh/private-key-filename-for-this-repository -F /dev/null"

https://docs.gitlab.com/ee/user/ssh.html#use-different-keys-for-different-repositories

Upvotes: 0

vancy-pants
vancy-pants

Reputation: 1358

I kept having problems with this, but this is what worked for me (I'm on a mac BTW)

Using github's process, I generated a new ssh key and added it to my profile on github

I added a config file in my .ssh folder, and I referenced my work ssh key and my personal ssh key as was outlined in other answers.

Host github.com
  HostName github.com
  AddKeysToAgent yes
  UseKeychain yes
  IdentityFile ~/.ssh/work_key
Host personal
  HostName github.com
  AddKeysToAgent yes
  UseKeychain yes
  IdentityFile ~/.ssh/personal_key

Then, I added both keys to my ssh-agent with ssh-add:

ssh-add --apple-use-keychain ~/.ssh/work_key

ssh-add --apple-use-keychain ~/.ssh/personal_key

I verified that both keys were added with ssh-add -L

Then I verified the connection with ssh -T git@github.com and ssh -T git@personal, and both worked!

After that, I was able to clone repos using my personal key with this command: git clone git@personal:my_username/repo.git (swapping out the git@github.com:... that I copied from my github repo for git@personal:...

Lots of these answers and this other SO question, along with the docs, got me what I needed!

Upvotes: 12

Слава ЗСУ
Слава ЗСУ

Reputation: 495

In my case the simplest option is to use a single line command, which allows me to get repo that I need with the ssh keys that corresponds to that repo:

git clone git@github.com:<user/group>/<repo.git> -c core.sshCommand="ssh -i /path/to/private/key"

Upvotes: 2

ys_huang
ys_huang

Reputation: 103

I create a CLI command to handle this! Checkout my repo~~
This repo uses ssh-agent to switch your ssh account.

Git_SSH-Account_Switch

A CLI tool can switch an ssh account to your current shell. You will easily switch to your git account & ssh key when using the server, and using your account to manipulate the project on the server.

Installation

$ bash ./setup.sh

it will add some code in your profile & $logout_profile, and setup git-acc & .gitacc on the $HOME.
file:

git-acc.sh -> $HOME/.git-acc, git-acc function.
.gitacc -> $HOME/.gitacc, save info. that regist on git-acc.

Control

        +---------------+
        |    git-acc    |
        +---------------+

SYNOPSIS

  git-acc [account]|[option]

OPTIONS

  [account]               use which accounts on this shell, type the account name that you register.
  -h, --help              print help information.
  -add, --add_account     build git_account info. & ssh-key.
  -rm, --remove_account   remove git_account info. & ssh-key from this device


EXAMPLES

  $ git-acc tw-yshuang

Upvotes: 0

Qeole
Qeole

Reputation: 9184

As a complement to Serban's solution, here is another way to use the .ssh/config file to distinguish the users. A bit more hacky, but does not require changing the host names.

Let's say you have a pro and a personal account, and that you set up your keys like this:

$ ssh-keygen -t rsa -f ~/.ssh/perso_rsa -C "nick@perso.org"
$ ssh-keygen -t rsa -f ~/.ssh/pro_rsa   -C "name.surname@pro.company.com"

Now most of the time, there is something you can use to distinguish the two identities. Typically, when working on a git repo, your git configuration is tied to the identity you want to use, and for example git config user.email will return one of the two email addresses, the one associated to the identity for this repo.

Based on that, we can use the Match exec <cmd> filtering directive in the .ssh/config, and write something like this:

Match host github.com exec "[ $(git config user.email) = nick@perso.org ]"
    IdentityFile ~/.ssh/perso_rsa

Host github.com
    IdentityFile ~/.ssh/pro_rsa

And just use the regular git@github.com:user/project.git for both identities.

It works as follows: When the host is github.com, the first matching rule is used to determine the IdentityFile to use. For the first rule, the exec command is run and the rule is selected if that command returns a zero exit status. Our test (passed to the user's shell) checks whether git config user.email returns nick@perso.org. If this is the case, the check returns true, the rule match, and ~/.ssh/perso_rsa is picked. If not, the second rule acts as a catch-all for github.com, and ~/.ssh/pro_rsa is picked instead.

We could have added another check for the second identity, but with only two rules it is not necessary, the “catch-all” behaviour should be enough.

We could also adapt the check to test other parameters insted of the user.email from git. For example, we could check the name of the current working directory. See man ssh_config for more details on Match exec.

Additional remarks (credits to Acumenus):

  • If supported by the user's shell (bash, zsh at least), double square brackets are necessary if part of the check (in our case, $(git config user.email)) evaluates to multiple words, as single brackets will break. Ideally we would like to enquote that between double quotes, but they are used for the argument for exec already and I did not find a way to escape them.
  • With this setup, cloning new repositories through SSH will use the key associated to the default user email (first user.email entry in git config -l). To clone a repository with the other key, one solution is to first create the repository, then add a remote and pull: mkdir foo; cd foo; git init; git config ...; git remote add origin <URL>; git pull.
  • The catch-all rule is of course unnecessary if the file for the key is one that ssh looks for by default, such as $HOME/.ssh/id_rsa.
  • The host directive can be used to match several comma-separated hosts at once if necessary (Match host github.com,gitlab.com exec ...).

Upvotes: 20

Serban Constantin
Serban Constantin

Reputation: 3576

I'd use .ssh config to set up different configurations for each particular user.

For example, edit (or create) the config file in the .ssh folder under your users root, and add something similar to this:

Host user1-github
    HostName github.com
    User git
    IdentityFile ~/.ssh/user1_rsa
Host user2-github
    HostName github.com
    User git
    IdentityFile ~/.ssh/user2_rsa

Where user1_rsa and user2_rsa are the outputs of ssh-keygen -t rsa -C "user1@example.com" and ssh-keygen -t rsa -C "user2@example.com"

Then, when testing simply use ssh -vT user1-github and ssh -vT user2-github.

Also, when cloning repos use git clone user1-github:username1/project.git or git clone user2-github:username2/project.git.

Upvotes: 34

Related Questions