How to match SSH config based on URL path or SSH arguments (for github deploy keys)?
Solution 1:
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:
- The default identity is set with
IdentityFile ~/.ssh/id_rsa
. - The default identity is in the agent and
id_rsa_user1
is not. - The agent will use the default identity for
github-user1
host, despiteHost github-user1
rule.
Solution 2:
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
Solution 3:
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.