-
-
Save vhermecz/4e2ae9468f2ff7532bf3f8155ac95c74 to your computer and use it in GitHub Desktop.
#!/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 '$@'" | |
"$@" |
@ Expands to the positional parameters, starting from one. When the expansion occurs within double quotes, each parameter expands to a separate word. That is, "$@" is equivalent to "$1" "$2" ... If the double-quoted expansion occurs within a word, the expansion of the first parameter is joined with the beginning part of the original word, and the expansion of the last parameter is joined with the last part of the original word. When there are no positional parameters, "$@" and $@ expand to nothing
What does the set —
do then?
The -- is the standard "don't treat anything following this as an option"
Very useful script. Could you possibly add a license?
That's great, TYVM!
nice work! thanks!
Thanks for the script @vhermecz !
I have a hard time to make it work, I set the script in a bin folder and in my bashrc I export GIT_SSH_COMMAND=$(custom_keys_git_ssh)
. Unfortunately, when I run a git command in an initialized repo folder, no parameters are passed ($@ is empty). Any tips ?
Or do I have to set it directly in the local repo .gitconfig [core] sshCommand = ... ?
UPDATE: for those wondering the same, you just have to export GIT_SSH_COMMAND=custom_keys_git_ssh
Great idea! And execution. Thanks!
Very cool! 2021 and we STILL have to use "hacks" in order to get this stuff working. :/ Super sad, but this is a very lovely script. Thanks. :)
Weird that github requires this, on bitbucket it doesn't seem to be a problem
https://support.atlassian.com/bitbucket-cloud/docs/add-access-keys/
Brilliant script!
Thank you very much for sharing this 🙏
For anyone wanting to use this with GitHub actions. You can create a deploy key for each repo you want to pull in, then put the private key into the GitHub Secret of the repo that will pull it. Then you need to add the following 2 steps before you call composer install
in your main.yaml
file:
- name: Set Private Repos
run : |
mkdir ~/.ssh ~/.ssh/git-keys
echo '${{ secrets.YOUR_SECRET_DEPLOY_KEY }}' > ~/.ssh/git-keys/VENDOR-REPO-NAME
find ~/.ssh/git-keys/ -type f -name "*" -exec chmod 600 {} +
- name: Set Git SSH Wrapper
run : |
sudo apt-get -qq -y update && sudo apt-get -qq -y install wget
wget -nv -O ~/custom_keys_git_ssh https://gist.githubusercontent.com/vhermecz/4e2ae9468f2ff7532bf3f8155ac95c74/raw/f01b4b0c03d0b11dbbdc3967c7a566b2c6db17df/custom_keys_git_ssh
chmod u+x ~/custom_keys_git_ssh
git config --global core.sshCommand ~/custom_keys_git_ssh
This assumes you are using ubuntu-latest for your CI. You can also copy paste the echo '${{ secrets.YOUR_SECRET_DEPLOY_KEY }}' > ~/.ssh/git-keys/VENDOR-REPO-NAME
below itself as many times as you need for the number of private repos you are using.
If you need to get the debug output you can just set the GIT_SSH_COMMAND_DEBUGLOG
environmental variable and create a step with run: cat ~/git_ssh.log
at some point after you run composer install
. If setting GIT_SSH_COMMAND_DEBUGLOG
in your main.yaml
you MUST use /home/runner/
instead of ~/
or it won't write the output.
env:
GIT_SSH_COMMAND_DEBUGLOG: /home/runner/git_ssh.log
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.
For those confused:
tested on
ubuntu 20.04 headless server
steps
- save the above script as
custom_keys_git_ssh.sh
and chmod +x it - note the full path
- create a new ssh key pair using
ssh-keygen
- mkdir
~/.ssh/git-keys
- 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 isgit@github.com:github/practice.git
then rename the private asgithub-practice
and publicgithub-practice.pub
- run
export GIT_SSH_COMMAND=/full/path/to/custom_keys_git_ssh.sh
- add the .pub to the repo deploy keys
- grab the ssh git url. DO NOT use the https git url.
- pick the place where you want to run
git clone git@github.com:yourusername/yourrepo.git
git ssh url
DONE~!
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
Sorry @cristiancalara i have issues understanding so I think I will stick to this ssh script but thanks for sharing
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 consumesvendor/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?
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)
We tested it again with clean environment and it seems like it is working well.
Thank you for your response.
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!
Could you please explain what the
set --
does in combination with"$@"
?