Wybierz klucz prywatny do użytku z Git

84

Mam 2 serwery Git, które wymagają 2 różnych kluczy SSH.

git clone user1@server1:blahblahblahużywa ~/.ssh/id_rsa, ale muszę określić, którego klucza użyć w zależności od serwera, z którym się łączę.

Jaki parametr wiersza polecenia Git wykonuje to zadanie? (Używam Linuksa.)

user349302
źródło
2
Odpowiedź na to pytanie znajduje się pod adresem superuser.com/questions/232373/… .
Daira Hopwood
możliwy duplikat Podaj klucz SSH dla git push bez użycia ~ / .ssh / config
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Odpowiedzi:

60

Jeśli łączysz się przez SSH, klucz będzie kontrolowany przez parametr SSH, a nie parametr git.

SSH szuka w ~/.ssh/configpliku parametrów konfiguracyjnych. Zmodyfikuj ten plik i dodaj wpisy IdentityFile dla dwóch serwerów Git w następujący sposób:

Host server1.whatever.com
  IdentityFile /path/to/key_1
Host server2.whatever.com
  IdentityFile /path/to/key_2

Ten artykuł zawiera więcej szczegółów.

Cameron Skinner
źródło
13
To nie odpowiadało na pytanie. Pytanie brzmi, jak podać gitowi ten parametr, gdy ssh obsługuje autoryzację?
keks
@Keks: Nie możesz przekazywać argumentów ssh za pomocą wiersza poleceń git. Ta odpowiedź zawiera obejście. Możliwe są również inne obejścia, na przykład git.wiki.kernel.org/index.php/… . Zauważ, że to podejście również nie wykorzystuje argumentów wiersza poleceń do modyfikowania zachowania ssh.
Cameron Skinner
12
To prawda, jednak Twoja pierwotna odpowiedź nie odpowiadała na pytanie. Możesz także użyć ssh-agenti użyć, ssh-adda następnie po prostu użyć git. Kiedy git łączy się przez ssh, klucz jest już włączony. Widzisz, jest kilka sposobów, a Twoja pierwotna odpowiedź po prostu nie pomaga.
keks
To jest właściwie tylko łącze. Czy mógłbyś podsumować istotne fragmenty artykułu w swojej odpowiedzi?
Flimm
@Flimm: Dodano podsumowanie.
Cameron Skinner
105

Jest inna możliwość. To do ustawienia core.sshCommandnp

git config --local core.sshCommand "/usr/bin/ssh -i /home/me/.ssh/id_rsa_foo"

Jest jeden konkretny scenariusz, w którym ta strategia jest szczególnie przydatna: kiedy masz wiele kont na Github, tak jak wszystkie konta sshna Github jako, [email protected]i używa sshklucza do określenia, którym jesteś użytkownikiem Github. W takim przypadku ani .ssh/confignie ssh-agentzrobisz tego, co chcesz.

Aktualizacja - nie możesz uruchomić powyższego, dopóki nie masz lokalnego repozytorium, więc jeśli próbujesz sklonować repozytorium zdalne, musisz ręcznie określić klucz zgodnie z odpowiedzią drewbie18:

git clone -c core.sshCommand="/usr/bin/ssh -i /home/me/.ssh/id_rsa_foo" [email protected]:me/repo.git

Po sklonowaniu repozytorium możesz użyć git configpolecenia, aby ustawić to na stałe.

Richarda Smitha
źródło
8
To powinna być wybrana odpowiedź. Wymagana konfiguracja jest ładnie zlokalizowana w repozytorium, które wymaga użycia innego klucza ssh, aby uzyskać dostęp do różnych serwerów git. Nie ma potrzeby modyfikowania ~ / .ssh / config (a nawet / etc / hosts, w przypadku wielu kont na GitHub).
mr.b
1
Jest jednak jeden problem: nie możesz sklonować repozytorium przed jego skonfigurowaniem, a aby je skonfigurować, musisz najpierw sklonować. LUB, możesz git initrepozytorium, skonfigurować je lokalnie, aby używał poprawnego polecenia ssh, a następnie dodać zdalne (3 kroki, w porównaniu do tylko 1 z "git clone").
pan b
3
Aby sklonować repozytorium, użyłbym rozwiązania @ Gussa, poniżej, ustawiając zmienną środowiskową GIT_SSH_COMMAND. Ale w normalnym użytkowaniu wolę moje rozwiązanie, ponieważ pozwala uniknąć ponownego eksportowania tej zmiennej za każdym razem, gdy uruchamiam nową powłokę.
Richard Smith
ratownik! jest mnóstwo ludzi pokazujących, jak używać ./ssh/config, aby to ustawić, i jak używać ssh-agent / ssh-add -K dla mac. Używał go przez rok, ale nagle przestał działać w High Sierra z najnowszymi poprawkami. core.sshCommand działał, gdy wszystko inne zawiodło. dzięki!
Steve
2
Dziękuję za to eleganckie rozwiązanie. Jednakże po prostu chcę precyzyjny że core.sshCommand jest dostępna tylko dla git> = 2.10.0
slonepi
32

Ogólnie chcesz do tego użyć ~/.ssh/config. Po prostu sparuj adresy serwerów z kluczami, których chcesz ich użyć w następujący sposób:

Host github.com
  IdentityFile ~/.ssh/id_rsa.github
Host heroku.com
  IdentityFile ~/.ssh/id_rsa.heroku
Host *
  IdentityFile ~/.ssh/id_rsa

Host *oznacza dowolny serwer, więc używam go, aby ustawić ~/.ssh/id_rsajako domyślny klucz do użycia.

Zaz
źródło
9
Ten pomysł nie działa, jeśli masz wiele kont na jednym serwerze, takim jak GitHub, i chcesz mieć inny klucz prywatny dla każdego z nich.
Flimm
W przypadku wielu kont na jednym serwerze zobacz tę odpowiedź stackoverflow.com/questions/3225862/ ...
lexicalscope
23

W moim scenariuszu, podobnym do scenariusza @Richard Smith (którego rozwiązanie, BTW, nie zadziałało dla mnie), muszę użyć różnych kluczy dla tego samego serwera w różnych repozytoriach.

Obejściem dla mnie było poprawne skonfigurowanie sesji ze zmienną środowiskową GIT_SSH_COMMAND, na przykład:

export GIT_SSH_COMMAND="ssh -o IdentitiesOnly=yes -i ~/.ssh/my-secret-identitiy"

Aktualizacja :

Inną rzeczą, na którą należy zwrócić uwagę, jest to, że prawidłowe ustawienie zmiennej środowiskowej może być kłopotliwe, więc używam narzędzi modyfikacji wiersza polecenia udostępnianych przez takie rzeczy, jak Liquid Prompt lub Fish Shell, aby podłączyć się do powłoki i kontynuować aktualizację zmiennych środowiskowych zgodnie aktualny katalog i niektóre zasady. Na przykład wszystkie moje projekty osobiste, które wymagają mojego osobistego klucza SSH z Gitlab, znajdują się pod nim, ~/Documents/Projects/personalwięc kiedy hak powłoki działa pwdi stwierdza, że ​​bieżący katalog znajduje się pod tą ścieżką, automatycznie ustawia GIT_SSH_COMMANDzmienne w razie potrzeby.

Guss
źródło
15

Użyj ssh-add path-to-private-keygo działa po wyjęciu z pudełka.

khelll
źródło
5
Nie, jeśli masz dwa klucze wdrażania i działają one tylko z określonymi repozytoriami. W takim przypadku może użyć niewłaściwego klucza i powiedzieć, że nie masz dostępu.
cdmckay
Mam problem, który powiedział cdmckay
Suge
7

Możesz ustawić konfigurację --global lub --local, global zaktualizuje ~/.gitconfigplik, local zaktualizuje konfigurację w repozytorium .git/configi nadpisze konfigurację globalną (~ / .gitconfig)

git config --local --add core.ssh Command 'ssh -i ~ / .ssh / my_key'

Maoz Sadok
źródło
2
zadziałało jak urok, właśnie tego potrzebowałem, rozwiązania dla konkretnego repozytorium.
Kwestor Lucem
6

Użytkownik systemu Windows tutaj, właśnie natknąłem się na ten problem i mam nieco inne rozwiązanie niż dotychczas przeczytałem. Problem, z którym się spotkałem, polega na tym, że po prostu chciałem sklonować repozytorium przy użyciu określonego prywatnego klucza ssh i nie muszę globalnie konfigurować mojej konfiguracji git ani dodawać określonych ustawień git bash, ponieważ wykonuję swoją pracę w PowerShell. Zasadniczo chcę tylko, aby klucze prywatne znajdowały się w moim folderze .ssh i odnoszę się do nich w określonych repozytoriach zgodnie z wymaganiami.

W tym celu działa następujące polecenie:

git clone -c core.sshCommand="ssh -i ~/.ssh/<PRIVATE KEY NAME>" <CLONE URL>

Zasadniczo po zainicjowaniu repozytorium git ustawia opcję core.sshCommand przed uruchomieniem klonu. Więc konkretny klucz ssh, którego chcesz użyć dla tego repozytorium, jest ustawiony TYLKO dla tego repozytorium. To może nie być idealne rozwiązanie dla wszystkich przypadków, ale chcę tego.

drewbie18
źródło
Dziękuję Ci. Nie byłam świadoma -cmożliwości git clone. Jest to lepsze niż ustawienie środowiska, jak sugeruję podczas klonowania.
Richard Smith
1

Inne odpowiedzi zainspirowały mnie do napisania małego skryptu, który wybiera klucz ssh w zależności od opcji wiersza poleceń lub (jeśli jest obecny) wartości git remote -v. Mam nadzieję, że to pomoże!

Aby właściwie odpowiedzieć na pytanie: użyj gat.

Zobacz także https://bitbucket.org/eikerobert/gat/src/master/

#!/bin/bash

usegat=false

for VAR in "$@"
do
    if [ "$VAR" != "${VAR/[email protected]:myaccount/}" ]; then
        usegat=true
    fi
done

if [ $usegat=false ]; then
   /usr/bin/git rev-parse --is-inside-work-tree >/dev/null 2>&1
   isinsidegitrepo=$?
    #echo $isinsidegitrepo
   if [ $isinsidegitrepo = 0 ]; then
       remote=`/usr/bin/git remote -v`
       if [ "$remote" != "${remote/[email protected]:myaccount/}" ]; then
           usegat=true
       fi
   fi
fi


if [ $usegat = true ]; then
    # echo "TRUE"
    /usr/bin/git -c core.sshCommand="/usr/bin/ssh -i /home/myaccount/.ssh/mykey" "$@"
else
     #echo "FALSE"
    /usr/bin/git "$@"
fi
Eike
źródło
1

Inną opcją jest napisanie małego skryptu do wykonania core.sshCommand go nieco mądrzejszym - sprawdź, czy bieżący katalog roboczy ma skonfigurowany określony klucz SSH, a jeśli tak, użyj go, w przeciwnym razie - polegaj na standardowej rozdzielczości klucza SSH.

Oto moja pierwsza wersja:

#!/bin/bash
key="$(git config ssh.key)"
if [ -n "$key" ]; then
        ssh -o IdentitiesOnly=yes -i "$key" "$@"
else
        ssh "$@"
fi

Następnie skonfiguruj go jako globalne polecenie git SSH:

chmod 755 ~/.local/bin/git-ssh-command
git config --global core.sshCommand ~/.local/bin/git-ssh-command

( ~/.local/binto aktualny standard „umieszczania tutaj skryptów użytkownika” w systemach operacyjnych SystemD )

Po skonfigurowaniu możesz skonfigurować dowolne repozytorium, aby korzystało z określonego klucza SSH, ustawiając opcję konfiguracji ssh.key:

git config --local ssh.key ~/.ssh/my-non-default-private-key

Dodatkowe opcjonalne sztuczki

  • Ustaw globalny ssh.key aby mieć „domyślny awaryjny klucz SSH inny niż domyślny” lub coś w tym stylu.
  • Ponieważ git jest wykonywany core.sshCommandw katalogu głównym repozytorium, twój niestandardowy git-ssh-commandmoże to sprawdzić i mieć pewne heurystyki dotyczące nazw katalogów. Można to zrobić w elsesekcji, więc heurystyka działa tylko wtedy, gdy nie ma określonego klucza ssh.key.
  • Możesz dodać git remote -v czek, aby dodać heurystykę opartą na pilotach, jak w skrypcie Eike
  • Jeśli chcesz spojrzeć na piloty repozytorium, ale masz wiele pilotów, które wymagają różnych kluczy, możesz dodać remote="$1:$(sed "s,.* ,,;s,',,g"<<<"$2")"na początku skryptu, aby rozwiązać problem z pilotem, na którym jest obsługiwany - i porównać z tym ( $remotewyglądałby jak środkowa kolumna na git remote -vwyjściu).

Aktualizacja:

Oto wersja niestandardowego polecenia SSH, które sprawdza zdalny adres URL i wykonuje pewne heurystyki - w moim przypadku mam kilka różnych tożsamości z tą samą publiczną usługą hostingu git (jedną do pracy, jedną do celów osobistych itp.) I mogę wybrać poprawną tożsamość, patrząc na zdalny adres URL (sprawdzając grupę Gitlab lub organizację Github itp.):

#!/bin/bash
if [[ "$2" =~ ^git-lfs-authenticate.* ]]; then # reconstruct url for git-lfs
        remote="$1:$(awk '{print$2}'<<<"$2")"
else # reconstruct url for standard git commands
        remote="$1:$(sed "s,.* ,,;s,',,g"<<<"$2")"
fi
#echo "Detected $remote from $@" >&2 # optional debug log
key="$(git config ssh.key)"
if [ -n "$key" ]; then # use specified SSH key, if set
        ssh -o IdentitiesOnly=yes -i "$key" "$@"
elif [[ "$remote" == [email protected]:my-company* ]]; then # use company id
        ssh -o IdentitiesOnly=yes -i ~/.ssh/company-id "$@"
elif [[ "$remote" =~ [email protected]:.*other-org.* ]]; then # bitbucket has weird urls
        ssh -o IdentitiesOnly=yes -i ~/.ssh/custom-org-key "$@"
else # otherwise use whatever the agent has (my personal key)
        ssh "$@"
fi
Guss
źródło