Skip to content

Instantly share code, notes, and snippets.

@vhermecz
Created June 8, 2020 11:20
Show Gist options
  • Save vhermecz/4e2ae9468f2ff7532bf3f8155ac95c74 to your computer and use it in GitHub Desktop.
Save vhermecz/4e2ae9468f2ff7532bf3f8155ac95c74 to your computer and use it in GitHub Desktop.
Allow configuring multiple ssh deploy keys with git
#!/bin/bash
# Script to use custom ssh keys for various git repositories
# Run without arguments to get usage info.
#
# How it works:
# When used with SSH, git sends the path to the repository in the SSH command.
# @see: https://github.com/git/git/blob/e870325/connect.c#L1268
# We extract this info and search for a key with the name.
# Based on the source, this seems to be used format since v2.0 at least.
# @see: https://github.com/git/git/commit/a2036d7
if [[ $# -eq 0 ]]; then
echo "Usage"
echo "Set script as GIT_SSH_COMMAND"
echo "Add SSH keys for git repositories under ~/.ssh/git-keys/ folder."
echo "File name format:"
echo " For the repository git@github.com:github/practice.git"
echo " Put the private key into the file github-practice"
echo " (Note: slash converted to dash in path, no extension)"
echo ""
echo "Uses ssh by default, use GIT_SSH_COMMAND_REALSSH envvar to override."
echo "For debugging set log output in envvar GIT_SSH_COMMAND_DEBUGLOG."
exit 1
fi
function debuglog() {
[ ! -z "$GIT_SSH_COMMAND_DEBUGLOG" ] && (echo `date +%FT%T` "$@") >> $GIT_SSH_COMMAND_DEBUGLOG
return 0
}
for CMD_BUF in "$@"; do :; done
debuglog "Value of cmd.buf is: '$CMD_BUF'"
# @source: https://superuser.com/a/1142939/277157
declare -a "array=($( echo "$CMD_BUF" | sed 's/[][`~!@#$%^&*():;<>.,?/\|{}=+-]/\\&/g' ))"
for CMD_PATH in "${array[@]}"; do :; done
CMD_PATH=$(echo "$CMD_PATH" | sed 's/\\//g')
IDENTITY=
if [[ $CMD_PATH == *.git ]] ;
then
REPOKEY=$(echo "$CMD_PATH" | sed 's/\.git//g' | sed 's/\//-/g')
KEYFILE=$(echo ~/.ssh/git-keys/$REPOKEY)
if [[ -f "$KEYFILE" ]]
then
debuglog "Key '$KEYFILE' exists"
IDENTITY=$(echo "-i $KEYFILE")
else
debuglog "Key '$KEYFILE' is missing"
fi
else
debuglog "No repo name detected. Skipping"
fi
SSH=${GIT_SSH_COMMAND_REALSSH:-ssh}
set -- $SSH $IDENTITY "$@"
debuglog "Calling with '$@'"
"$@"
@abbluiz
Copy link

abbluiz commented Jan 12, 2022

For some reason, I cannot make it work when ~/.ssh/config has:

Host *
    IdentitiesOnly=yes

Also, it gives me this warning:

Cloning into 'laravel-oauth-introspection'...
Warning: Identity file  /home/labb/.ssh/git-keys/userh-dev-laravel-oauth-introspection not accessible: No such file or directory.

Even though that file exists.

However, if I don't include .ssh/config, it does work.

Tested on Alpine 3.15 and Fedora 35.

@simkimsia
Copy link

For those confused:

tested on

ubuntu 20.04 headless server

steps

  1. save the above script as custom_keys_git_ssh.sh and chmod +x it
  2. note the full path
  3. create a new ssh key pair using ssh-keygen
  4. mkdir ~/.ssh/git-keys
  5. move the key pair in step 3 into ~/.ssh/git-keys and rename the keys as suggested by the script i.e. if the git url is git@github.com:github/practice.git then rename the private as github-practice and public github-practice.pub
  6. run export GIT_SSH_COMMAND=/full/path/to/custom_keys_git_ssh.sh
  7. add the .pub to the repo deploy keys
  8. grab the ssh git url. DO NOT use the https git url.
  9. pick the place where you want to run git clone git@github.com:yourusername/yourrepo.git git ssh url

DONE~!

@cristiancalara
Copy link

In newer versions of git, we can set the "core.sshCommand" option to avoid using the "GIT_SSH_COMMAND" from the command line - see an more in depth answer here https://gist.github.com/gubatron/d96594d982c5043be6d4?permalink_comment_id=4063722#gistcomment-4063722

@simkimsia
Copy link

Sorry @cristiancalara i have issues understanding so I think I will stick to this ssh script but thanks for sharing

@nheimann1
Copy link

nheimann1 commented Apr 23, 2022

Thank you for that.

It works for me when using git clone but doesn't work when the repo is deinfed in composer.

For some reason the debug log is not working for me as well ,so I can't provide the logs here.

What I did:

  • For context, I got to this script from this blog from the part of Repository-name based key selection
  • I config git to use this script by git config --global core.sshCommand /path/to/your/wrapper.sh
  • My repo name is vendor/repo1.subname.git
  • I copied the private/public keys to ~/.ssh/git-keys/vendor-repo1.subname
  • When I git clone the project it only works when I keep the name of the private key vendor-repo1.subname. If I change it, it doesn't work, which tells me it indeed uses this script
  • When I'm doing composer install on a different project which consumes vendor/repo1.subname.git
"repositories":
[
       {
               "type": "vcs",
               "url": "git@github.com:vendor/reop1.subname.git"
       }
]

I get the result Your GitHub credentials are required to fetch private repository metadata (git@github.com:vendor/repo1.subname.git)

Any ideas?

@kraftner
Copy link

I am just guessing here, but maybe the problem is related to this: composer/composer#5312 (also see https://getcomposer.org/doc/05-repositories.md#git-alternatives)

@nheimann1
Copy link

We tested it again with clean environment and it seems like it is working well.

Thank you for your response.

@Flowster
Copy link

Hi just created https://github.com/Flowster/git-ssh-key-action a Github action that uses this gist.
Let me know if it works for you too!

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