I'm trying to use multiple deploy keys for github, which means I need to match my SSH configs based on the repository name. I cannot match based on hostname, port or user because they are all the same. Only repo name and deploy keys are different.
I know this question has been asked before but I can't find a satisfactory answer because I am not interested in adding a subdomain or user to my github ssh URL. This question is specifically on how to match a URL PATH or SSH argument or other workaround that do not involve modifying the default github ssh URL.
The default ssh github url is [email protected]:githubusername/githubreponame.git
The usual SSH configs are:
# repo 1
# MATCH or HOST xxxxxxxxxxx
HostName github.com
User git
IdentityFile ~/.ssh/myrepo1name_rsa
# repo 2
# MATCH or HOST xxxxxxxxxxx
HostName github.com
User git
IdentityFile ~/.ssh/myrepo2name_rsa
As per the ssh config manual http://man7.org/linux/man-pages/man5/ssh_config.5.html you can use 2 parameters to match a config, HOST or MATCH.
We already know that HOST cannot do it. So MATCH is the only way:
The available criteria keywords for MATCH are: canonical, final, exec, host, originalhost, user, and localuser.
From those MATCH criteria keywords, it seems none of them have access to the repo name or the SSH arguments or anything useful.
The MATCH exec
criteria keyword seems promising:
The exec keyword executes the specified command under the user's shell. If the command returns a zero exit status then the condition is considered true.
exec
has access to the following variables http://man7.org/linux/man-pages/man5/ssh_config.5.html#TOKENS:
%h The remote hostname.
%i The local user ID.
%L The local hostname.
%l The local hostname, including the domain name.
%n The original remote hostname, as given on the command line.
%p The remote port.
%r The remote username.
%u The local username.
None of these variables appear useful to me.
I have tried the following:
Match exec "pwd | grep myreponame1"
HostName github.com
User git
IdentityFile ~/.ssh/myreponame1_rsa
It is partly successful, as usually when I am using git I am inside the repo directory so pwd | grep reponame
will exit true. But it doesn't work for cloning or if I use a different directory name.
I am looking for a better alternative, which would probably also use MATCH exec
in some way.
Edit: the best solution I found so far is:
Match exec "git remote get-url origin | grep reponame || echo $REPO | grep reponame"
But I'm not 100% happy with it because I need to add an env variable before git clone.
Git does not know, or care. It just runs ssh. Specifies that ssh(1) should only use the authentication identity files configured in the ssh_config files, even if ssh-agent(1) or a PKCS11Provider offers more identities.
From your repository, click Settings. In the sidebar, click Deploy Keys, then click Add deploy key. Provide a title, paste in your public key. Select Allow write access if you want this key to have write access to the repository.
As noted in "Why can't I use one ssh key on more than one github repo?" by tkeeler: This workflow becomes a problem when using automated systems and git submodules. You can't use the same deploy key in more than one repo, so the workaround becomes adding that key to their user account (or a dedicated machine account).
You can specify an SSH key for a particular GitHub user or a repository.
Change a hostname with url
rule in the global git config. Then select the correct identity for the hostname with Host
rule in the SSH agent config.
Example:
GitHub username: user1
.
Repository: [email protected]:user1/repo.git
.
User identity file: ~/.ssh/id_rsa_user1
.
~/.gitconfig
or ~/.config/git/config
:
[url "[email protected]:"]
insteadOf = https://github.com/
[url "git@github-user1:user1"]
insteadOf = [email protected]:user1
~/.ssh/config
:
AddKeysToAgent yes
IdentitiesOnly yes
Host github-user1
HostName github.com
IdentityFile ~/.ssh/id_rsa_user1
Host *.example.com
IdentityFile ~/.ssh/id_rsa_example
Git will substitute [email protected]:user1
with git@github-user1:user1
. So the new hostname will be github-user1
. Then the SSH agent will use the new hostname to select the user1
identity file ~/.ssh/id_rsa_user1
.
Now you can clone the repository with the following command:
git clone [email protected]:user1/repo.git
Notes:
Only one url
rule is applied. So this will not work:
git clone https://github.com/user1/repo.git
SSH config manual:
man ssh_config
Parameters meanings:
AddKeysToAgent
- store a key and its passphrase in the agent on first use.IdentitiesOnly
- only use configured identities even if the agent has more identities.Default identity is ~/.ssh/id_rsa
. If you use it do not set it via top level IdentityFile
or Host *
rule or you will experience the following problem:
IdentityFile ~/.ssh/id_rsa
.id_rsa_user1
is not.github-user1
host, despite Host github-user1
rule.Here's pretty much what I do:
Host github.com gist.github.com
Hostname %h
User git
RequestTTY no
RemoteCommand none
IdentitiesOnly yes
ControlMaster no
Match host github.com,gist.github.com exec "~/Developer/C++/getargv/getargv -0 -s 1 $PPID | env POSIXLY_CORRECT=1 xargs -0 getopt '46AaCfGgKkMNnqsTtVvXxYyB:b:c:D:E:e:F:I:i:J:L:l:m:O:o:p:Q:R:S:W:w:' | perl -pe 's|.*? -- ||' | fgrep -e username1"
IdentityFile ~/.ssh/keys/github_rsa
Match host github.com,gist.github.com exec "~/Developer/C++/getargv/getargv -0 -s 1 $PPID | env POSIXLY_CORRECT=1 xargs -0 getopt '46AaCfGgKkMNnqsTtVvXxYyB:b:c:D:E:e:F:I:i:J:L:l:m:O:o:p:Q:R:S:W:w:' | perl -pe 's|.*? -- ||' | fgrep -e username2"
IdentityFile ~/.ssh/keys/github_rsa2
I set the common github configs in the top Host
block, then each Match
block looks at the arguments passed to ssh, parses them, and checks for the github username and if it matches, sets the correct key.
The ~/Developer/C++/getargv/getargv
program is just an implementation of cat /proc/$PPID/cmdline
for macOS, on linux you don't need a separate tool.
This works for cloning, pushing, pulling, etc.
The simplest thing to do is to create separate alias for each respository.
Host repo1
HostName github.com
User git
IdentityFile ~/.ssh/myrepo1name_rsa
Host repo2
HostName github.com
User git
IdentityFile ~/.ssh/myrepo2name_rsa
Then use repo1:githubusername/githubreponame.git
and repo2:githubusername/githubreponame.git
as the URLS in Git.
To make it less repetitive, you can define aliases with a pattern you can match on.
Host gitrepo1
IdentityFile ~/.ssh/myrepo1name_rsa
Host gitrepo2
IdentityFile ~/.ssh/myrepo2name_rsa
Host git*
HostName github.com
User git
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With