Как сказать git, какой закрытый ключ использовать?

647

sshимеет -iвозможность указать, какой файл закрытого ключа использовать при аутентификации:

-i identity_file

    Выбирает файл, из которого читается идентификатор (закрытый ключ) для аутентификации RSA или DSA. По умолчанию используется ~/.ssh/identityверсия протокола 1 ~/.ssh/id_rsaи ~/.ssh/id_dsaверсия протокола 2. Файлы идентификации также могут быть указаны для каждого хоста в файле конфигурации. Можно иметь несколько -iпараметров (и несколько идентификаторов, указанных в файлах конфигурации).

Есть ли аналогичный способ сказать, gitкакой файл закрытого ключа использовать в системе с несколькими закрытыми ключами в ~/.sshкаталоге?

jrdioko
источник
2
Также связано serverfault.com/questions/194567/…
Machavity

Ответы:

672

В ~/.ssh/configдобавьте:

host github.com
 HostName github.com
 IdentityFile ~/.ssh/id_rsa_github
 User git

Теперь вы можете сделать git clone git@github.com:username/repo.git.

ПРИМЕЧАНИЕ. Убедитесь, что разрешения для IdentityFile равны 400. SSH будет неявным образом отклонять слишком читаемые ключи SSH. Это будет выглядеть как отказ от полномочий. Решение в этом случае:

chmod 400 ~/.ssh/id_rsa_github
shellholic
источник
117
Что если вам нужно подключиться к одному и тому же хосту с разными ключами?
Валентин Клингхаммер
6
@Quelltextfabrik - вы можете добавить еще один раздел с другим хостом
Бен Чалленор
1
@Cliff Nop, на моей man-странице: " HostName: Указывает реальное имя хоста для входа в систему. Это можно использовать для указания псевдонимов или сокращений для хостов." Моя версия ssh - openssh-6.7p1.
Гриссиом
11
Если файл конфигурации новый, не забудьте сделатьchmod 600 ~/.ssh/config
elysch
2
@ValentinKlinghammer ответ от @Flimm имеет решение для этого вопроса. Это использовать core.sshCommandконфигурацию git. superuser.com/a/912281/162466
ВасяНовиков
345

Переменная среды GIT_SSH_COMMAND:

Начиная с версии Git 2.3.0, вы можете использовать переменную окружения GIT_SSH_COMMANDследующим образом:

GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa_example" git clone example

Обратите внимание, что -iиногда это может быть изменено вашим конфигурационным файлом, и в этом случае вы должны дать SSH пустой конфигурационный файл, например так:

GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa_example -F /dev/null" git clone example

Конфигурация core.sshCommand:

Начиная с Git версии 2.10.0, вы можете настроить это для репо или глобально, так что вам больше не нужно устанавливать переменную окружения!

git config core.sshCommand "ssh -i ~/.ssh/id_rsa_example -F /dev/null"
git pull
git push
Флимм
источник
1
Мне пришлось экспортировать переменную оболочки в переменную окружения, чтобы это работало, т. export GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa_example"git clone example
Е.
7
@Abdull В Bash выполнение присваивания в той же строке, что и команда, экспортирует переменную среды только для этой команды. Попробуйте: example=hello /usr/bin/env | grep example.
Flimm
3
все стало еще лучше:
начиная
2
@Noitidart /dev/null- это только допустимое имя файла в UNIX-подобных операционных системах, оно не работает в Windows.
Flimm
2
Для меня GIT_SSH_COMMANDне работал , пока я не использовал IdentitiesOnly, например, командой: GIT_SSH_COMMAND="ssh -i ~/.ssh/mysubdir/id_rsa -o 'IdentitiesOnly yes'" git push.
Тайлер Коллиер
111

Там нет нет прямого способа сказать , gitкоторый секретный ключ использовать, потому что она опирается на sshдля аутентификации в хранилище. Тем не менее, есть еще несколько способов достижения вашей цели:

Опция 1: ssh-agent

Вы можете использовать ssh-agentдля временной авторизации вашего личного ключа.

Например:

$ ssh-agent sh -c 'ssh-add ~/.ssh/id_rsa; git fetch user@host'

Вариант 2: GIT_SSH_COMMAND

Передайте аргументы ssh, используя GIT_SSH_COMMANDпеременную окружения (Git 2.3.0+).

Например:

$ GIT_SSH_COMMAND='ssh -i ~/.ssh/id_rsa -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' \
  git clone user@host

Вы можете напечатать все это в одной строке - игнорируйте $и пропустите \.

Вариант 3: GIT_SSH

Передайте аргументы ssh, используя GIT_SSHпеременную окружения, чтобы указать альтернативный sshдвоичный файл.

Например:

$ echo 'ssh -i ~/.ssh/id_rsa -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no $*' > ssh
$ chmod +x ssh
$ GIT_TRACE=1 GIT_SSH='./ssh' git clone user@host

Примечание. Вышеуказанные строки являются командными строками оболочки (терминала), которые вы должны вставить в свой терминал. Они создадут файл с именем ssh, сделают его исполняемым и (косвенно) выполнят его.

Примечание: GIT_SSHдоступно с версии v0.99.4 (2005).

Вариант 4: ~/.ssh/config

Используйте ~/.ssh/configфайл, как предложено в других ответах, чтобы указать местоположение вашего личного ключа, например

Host github.com
  User git
  Hostname github.com
  IdentityFile ~/.ssh/id_rsa
kenorb
источник
1
// Что если ваша личность в ssh-agent будет переадресована, как в этом вопросе? superuser.com/questions/971732/…
Натан Басанезе,
1
Я позволил мне переформатировать этот пост: IMO, это, безусловно, самый полный ответ. В своем оригинальном дизайне быстрое сканирование предложило пост, где описывалось единственное сложное решение проблемы, поэтому я пропустил его.
Альберто
3
$ ssh-agent sh -c 'ssh-add ~/.ssh/id_rsa; git fetch user@host'работал для меня, когда больше ничего не будет. Престижность.
Дэниел Дьюхерст
1
Я должен был использовать ~/.ssh/configметод, env vars не работал для меня ...
Грег Дубицки
1
GIT_SSHдоступен начиная с версии 0.99.4 (август 2005 г.) , поэтому в основном существует с Git (апрель 2005 г.).
Доминик
32

Напишите скрипт, который вызывает sshнужные аргументы, и укажите имя файла скрипта $GIT_SSH. Или просто введите вашу конфигурацию ~/.ssh/config.

Игнасио Васкес-Абрамс
источник
2
Еще одно объяснение, как это сделать.
Ситсу,
1
~/.ssh/configЕсть путь.
hek2mgl
Я работаю на машине (A), с которой я отправляю push на сервер (B), который принимает только аутентификацию по ssh-ключу. Хотя мои настройки ~ / .ssh / config в (A) работают отлично, когда я работаю непосредственно на этом компьютере, это не так, когда я вхожу в другое место (C). Использование $GIT_SSHи скрипт решили эту проблему. Спасибо!
bsumirak
18

Если вы не хотите указывать переменные окружения каждый раз, когда вы запускаете git, не хотите другой скрипт-обертку, не запускаете ssh-agent (1) и не хотите загружать другой пакет только для этого, используйте git -remote-ext (1) внешний транспорт:

$ git clone 'ext::ssh -i $HOME/.ssh/alternate_id git.example.com %S /path/to/repository.git'
Cloning into 'repository'
(...)
$ cd repository
$ git remote -v
origin  ext::ssh -i $HOME/.ssh/alternate_id git.example.com %S /path/to/repository.git (fetch)
origin  ext::ssh -i $HOME/.ssh/alternate_id git.example.com %S /path/to/repository.git (push)

Я считаю это решение превосходным, потому что:

  • Это репозиторий / удаленный
  • Избегайте раздувания скриптов
  • Не нужен агент SSH - полезно, если вы хотите без присмотра клоны / push / pull (например, в cron)
  • Определенно, внешний инструмент не нужен
flaviovs
источник
2
Этот ответ был именно тем, что мне было необходимо, чтобы gitресурс Chef использовал специфичные для репозитория ключи развертывания для клонирования / извлечения из частных репозиториев Github. Дополнительное преимущество этого метода по сравнению со средой / сценарием состоит в том, что, поскольку путь к ключу закодирован в конфигурации рабочего репозитория, он будет использовать один и тот же ключ как при первоначальном клонировании, так и при последующих выборках / толчках.
Адам Франко
2
ВАУ! Это просто здорово, не знал об этом. Спасибо за ответ, также весьма полезный в марионеточной среде, чтобы избежать лишних хлопот, чтобы управлять .ssh/configи т. Д. +1!
gf_
1
Это решение не работает вместе с флагом --recursive. Подмодули не выбираются с использованием указанного ключа, и поэтому происходит сбой, если им требуется авторизация.
Даниэле Теста
1
Каждый подмодуль - это совершенно другое хранилище со своим набором пультов. Для вашего удобства они склеены Git, но никакие пульты для субмодуля не связаны с теми, что в родительском репозитории. Я боюсь, что вы должны установить пульт, используя extтранспорт в каждом подмодуле, чтобы рекурсия в родительском работала.
flaviovs 22.12.16
2
Если вы столкнулись со следующей ошибкой fatal: transport 'ext' not allowed, вы должны внести в белый список протокол ext через export GIT_ALLOW_PROTOCOL=ext. По сути, удаленный помощник git-remote-ext (который поддерживает URL "ext :: ssh example.com% S foo / repo") позволяет выполнять произвольную команду. Обычно это не проблема, потому что пользователь всегда видит и доверяет URL, который он передает git. Однако подмодули git через файл .gitmodules позволяют злоумышленнику запросить у клиента выборку произвольных URL-адресов git. hackerone.com/reports/104465
Гомино,
18

Используйте пользовательскую конфигурацию хоста ~/.ssh/config, например:

Host gitlab-as-thuc  
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_rsa.thuc
    IdentitiesOnly yes

затем используйте свое собственное имя хоста следующим образом:

git remote add thuc git@gitlab-as-thuc:your-repo.git  
thucnguyen
источник
2
Это ответ, который я искал, так как у меня есть отдельные учетные записи GitHub для дома и работы. Мне просто нужно было установить Host work.github.com HostName github.com IdentityFile ~/.ssh/work, а затем заменить «github.com» на «work.github.com» всякий раз, когда я клонирую рабочий репозиторий. Он по-прежнему подключается к «github.com», но использует пару ключей не по умолчанию.
Миккель
1
URL для деталей (" itblog.study.land / ..." ) больше не работает :(
Карл Смотриц
@CarlSmotricz оригинал один был перенесен сюда: medium.com/@thucnc/...
thucnguyen
4
НАКОНЕЦ-ТО!!! Этот ответ на самом деле показывает, как вы можете использовать то, что вы положили в ~/.ssh/configфайл. В каждом другом ответе не указывается, как вы можете установить хост при добавлении источника, что автоматически позволяет git использовать правильный файл ключа. БЛАГОДАРЮ ВАС!!
BrianVPS
1
Хорошо, это было то, что я искал :)
Лукас Д'Авила
15

После моей борьбы $GIT_SSHя хотел бы поделиться тем, что сработало для меня.

На моих примерах я предполагаю, что у вас есть личный ключ, расположенный по адресу/home/user/.ssh/jenkins

Ошибка, которую следует избегать: значение GIT_SSH включает опции

$ export GIT_SSH="ssh -i /home/user/.ssh/jenkins"

или что-то подобное не удастся, так как git попытается выполнить значение в виде файла . По этой причине вы должны создать скрипт.

Рабочий пример сценария $ GIT_SSH /home/user/gssh.sh

Сценарий будет вызываться следующим образом:

$ $GIT_SSH [username@]host [-p <port>] <command>

Пример работы скрипта может выглядеть так:

#!/bin/sh
ssh -i /home/user/.ssh/jenkins $*

Обратите внимание $*на в конце, это важная часть этого.

Еще более безопасная альтернатива, которая предотвратит любой возможный конфликт с чем-либо в вашем конфигурационном файле по умолчанию (плюс явное упоминание используемого порта):

#!/bin/sh
ssh -i /home/user/.ssh/jenkins -F /dev/null -p 22 $*

Предполагая, что сценарий включен /home/user/gssh.sh, вы должны:

$ export GIT_SSH=/home/user/gssh.sh

и все будет работать.

Ян Влчинский
источник
Благодарю. Просто обратите внимание: используйте $ @ вместо $ * для проходных аргументов, так как первый ведет себя правильно, когда аргументы содержат пробелы.
Петр Финдейзен
@PiotrFindeisen Спасибо за вашу заметку. Тем не менее, я не понимаю это полностью - в Zsh это помогает мне сохранить строки с пробелом в один кусок, а в Bash нет. Можете ли вы рассказать мне больше или указать на некоторые объяснения? Я не хочу добавлять некоторые модификации вслепую.
Ян Влчинский
Вы должны удалить первую половину вашего ответа. Никто не заинтересован в решении, которое не работает, и это потраченное впустую чтение, которое скрывает правильный ответ внизу, который работает чудесно.
Cerin
@Cerin Если вы хотите удалить «Ошибка, чтобы избежать», я оставлю ее там. Это общая ошибка, которую следует избегать, и она очень короткая. Я уверен, что кто-то попытается оптимизировать решение, предоставив все вещи в переменную (это случилось со мной), поэтому я попытался сократить путь к успеху.
Ян Влчинский
5

Вы можете просто использовать ssh-идент вместо создания своей собственной оболочки.

Вы можете прочитать больше на: https://github.com/ccontavalli/ssh-ident

Он загружает ssh-ключи по требованию при первой необходимости, один раз, даже с несколькими сеансами входа в систему, xterms или общими домами NFS.

С крошечным файлом конфигурации он может автоматически загружать разные ключи и хранить их разделенными в разных агентах (для переадресации агентов) в зависимости от того, что вам нужно сделать.

rabexc
источник
5

У меня был клиент, которому нужна была отдельная учетная запись на github. Поэтому мне нужно было использовать отдельный ключ только для этого проекта.

Моим решением было добавить это в мой .zshrc / .bashrc:

alias infogit="GIT_SSH_COMMAND=\"ssh -i ~/.ssh/id_specialkey\" git $@"

Всякий раз, когда я хочу использовать git для этого проекта, я заменяю "infogit" на git:

infogit commit -am "Some message" && infogit push

Для меня это легче запомнить.

Майкл Коул
источник
4

Поэтому я установил переменную env GIT_SSH в $HOME/bin/git-ssh.

Для поддержки того, чтобы моя конфигурация репозитория диктовала, какую идентификационную информацию ssh использовать, мой ~/bin/git-sshфайл таков:

#!/bin/sh
ssh -i $(git config --get ssh.identity) -F /dev/null -p 22 $*

Тогда у меня есть глобальная настройка git config:

$ git config --global ssh.identity ~/.ssh/default_id_rsa

И в любом git-репозитории я могу просто установить локальное ssh.identityзначение git config:

$ git config --local ssh.identity ~/.ssh/any_other_id_rsa

Вуаля!

Если вы можете иметь разные адреса электронной почты для каждой личности, это становится еще проще, потому что вы можете просто назвать свои ключи после своих адресов электронной почты, а затем использовать user.email из git config для выбора ключа ~/bin/git-sshследующим образом:

#!/bin/sh
ssh -i $HOME/.ssh/$(git config --get user.email) -F /dev/null -p 22 $*
Брендан Болдуин
источник
2

Мое решение было таким:

создать скрипт:

#!/bin/bash
KEY=dafault_key_to_be_used
PORT=10022 #default port...
for i in $@;do
   case $i in
    --port=*)
        PORT="${i:7}";;
    --key=*)KEY="${i:6}";;
   esac
done
export GIT_SSH_COMMAND="ssh -i $HOME/.ssh/${KEY} -p ${PORT}"
echo Command: $GIT_SSH_COMMAND

затем, когда вам нужно изменить запуск var:

. ./thescript.sh [--port=] [--key=]

Не забывайте лишнюю точку! это заставляет скрипт устанавливать окружение vars !! --key и --port не обязательны.

Salsicha
источник
2

Как правило, вы хотите использовать ~/.ssh/configдля этого. Просто соедините адреса серверов с ключами, которые вы хотите использовать для них, следующим образом:

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

Host *обозначает любой сервер, поэтому я использую его, чтобы установить ~/.ssh/id_rsaв качестве ключа по умолчанию для использования.

Zaz
источник
2

Я основываюсь на @shellholic и этой ТАКОЙ ветке с несколькими тиками. Я использую GitHub в качестве примера и предполагаю, что у вас есть закрытый ключ ~/.ssh/github(в противном случае см. Эту ветку SO ), и что вы добавили открытый ключ в свой профиль GitHub (в противном случае см. Справку GitHub ).

При необходимости создайте новый файл конфигурации SSH ~/.ssh/configи измените разрешения на 400

touch ~/.ssh/config
chmod 600 ~/.ssh/config

Добавьте это в ~/.ssh/configфайл:

Host github.com
    IdentityFile ~/.ssh/github
    IdentitiesOnly yes

Если у вас уже есть удаленная настройка, вы можете удалить ее, в противном случае вам все равно может быть предложено ввести имя пользователя и пароль:

git remote rm origin

Затем добавьте пульт в репозиторий git и обратите внимание на двоеточие перед именем пользователя:

git remote add origin git@github.com:user_name/repo_name.git

И тогда команды git работают нормально, например:

git push origin master
git pull origin 

@HeyWatchЭто в этой теме SO предлагает добавить, IdentitiesOnly yesчтобы предотвратить поведение SSH по умолчанию при отправке файла идентификации, соответствующего имени файла по умолчанию для каждого протокола. Смотрите эту ветку для получения дополнительной информации и ссылок.

miguelmorin
источник
Это была моя ошибка: «Если у вас уже есть удаленная настройка ...». Большое спасибо!!!
Аллан Андраде
распространенная ошибка --- это ответ
Годдард
1

Просто используйте ssh-agentи ssh-addкоманды.

# create an agent
ssh-agent

# add your default key
ssh-add ~/.ssh/id_rsa

# add your second key
ssh-add ~/.ssh/<your key name>

После выполнения вышеуказанных команд вы можете использовать обе клавиши одновременно. Просто введите

git clone git@github.com:<yourname>/<your-repo>.git

клонировать ваш репозиторий.

Вы должны выполнить вышеуказанную команду после перезагрузки компьютера.

Цзиньмяо Ло
источник
Пожалуйста, объясните процесс, в том числе Как я могу создать агента
Срикрушна
0

Я использую git версии 2.16, и мне не нужен ни один фрагмент скрипта, даже конфигурация или измененные команды.

  • Просто скопировал мой закрытый ключ в .ssh / id_rsa
  • установить разрешения на 600

И Git читает ключ автоматически. Я ничего не спрашиваю, и это не выдает ошибку. Просто отлично работает.

akprajapati
источник
Вы заметили, что вопрос о «системе с несколькими закрытыми ключами в ~/.sshкаталоге»?
Скотт
0

Хотя вопрос не требует этого, я этот ответ для всех, кто хочет решить эту проблему специально для .

Гитлаб раствор

Я попытался использовать подход с , но даже в документации git рекомендуется использовать ~/.ssh/configчто-то большее, чем простой случай. В моем случае я сервер - и я хотел сделать это как определенный пользователь - который, конечно, определяется во время а не именем пользователя git. После внедрения я просто выполняю следующее:

~/myrepo> git mycommit -m "Important Stuff"
~/myrepo> git mypush
[proceed to enter passphrase for private key...]

Настроить

Вспомните расположение вашего /myfolder/.ssh/my_gitlab_id_rsa в моем случае.

Добавить запись в ~/.ssh/config:

Host gitlab-delegate
    HostName gitlab.mydomain.com
    User git
    IdentityFile /myfolder/.ssh/my_gitlab_id_rsa
    IdentitiesOnly yes

Добавьте в ~/.gitconfig:

mypush = "!f() { \
           path=$(git config --get remote.origin.url | cut -d':' -f2); \
           branch=$(git rev-parse --abbrev-ref HEAD); \
           git remote add gitlab_as_me git@gitlab-delegate:$path && \
           git push gitlab_as_me $branch && \
           git pull origin $branch; \
           git remote remove gitlab_as_me; \
         }; f"

В качестве бонуса я выполняю свои коммиты на этом же хосте как определенный пользователь с этим :

mycommit = "!f() { \
             git -c "user.name=myname" -c "user.email=myname@mysite.com" commit \"$@\"; \
           }; f"

объяснение

Все вышеперечисленное предполагает, что соответствующий удаленный узел originи соответствующая ветвь в настоящее время извлечены. Для справки я столкнулся с несколькими пунктами, которые необходимо было решить:

  • Решение требует создания нового пульта gitlab_as_me, и мне не нравилось видеть, как лишний пульт висит в дереве журналов, поэтому я удаляю его, когда закончу
  • Для создания удаленного необходимо генерировать URL удаленного на лету - в случае с gitlab это было достигнуто с помощью простого bash
  • Выполняя толчок к gitlab_as_meвам, вы должны четко указать, какую ветку вы толкаете
  • После выполнения нажатия ваш локальный originуказатель должен быть «обновлен», чтобы соответствовать gitlab_as_me(это git pull origin $branchделает)
dtmland
источник
0

Если у вас есть несколько учетных записей GIT, и вы хотите другой ключ SSH

Вы должны выполнить тот же шаг для генерации ключа SSH, но убедитесь, что вы

ssh-keygen -t ed25519 -C "your-email-id@gmail.com" 

Введите путь, который вы хотите сохранить (например: my-pc / Desktop / .ssh / ed25519)

Добавьте открытый ключ к вашему gitlab ( Как добавить ключ ssh в gitlab )

Вы должны новый ssh ​​идентификатор, используя команду ниже

ssh-add ~/my-pc/Desktop/.ssh/ed25519
Srikrushna
источник
(1) Вы цитируете кого-то или что-то? Если это так, пожалуйста, укажите источник. Если нет, пожалуйста, не используйте форматирование цитаты. (2) Что такое «ed25519»? …………………………… Пожалуйста, не отвечайте в комментариях; отредактируйте  свой ответ, чтобы сделать его более понятным и полным.
Скотт
0
    # start :: how-to use different ssh identity files

    # create the company identity file
    ssh-keygen -t rsa -b 4096 -C "first.last@corp.com"
    # save private key to ~/.ssh/id_rsa.corp, 
    cat ~/.ssh/id_rsa.corp.pub # copy paste this string into your corp web ui security ssh keys

    # create your private identify file
    ssh-keygen -t rsa -b 4096 -C "me@gmail.com"
    # save private key to ~/.ssh/id_rsa.me, note the public key ~/.ssh/id_rsa.me.pub
    cat ~/.ssh/id_rsa.me.pub # copy paste this one into your githubs, private keys

    # clone company internal repo as follows
    GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa.corp -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" \
    git clone git@git.in.corp.com:corp/project.git

    export git_msg="my commit msg with my corporate identity, explicitly provide author"
    git add --all ; git commit -m "$git_msg" --author "MeFirst MeLast <first.last@corp.com>"
    GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa.corp -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" \
    git push 
    # and verify 
    clear ; git log --pretty --format='%h %ae %<(15)%an ::: %s

    # clone public repo as follows
    GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa.corp -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" \
    git clone git@github.com:acoolprojectowner/coolproject.git

    export git_msg="my commit msg with my personal identity, again author "
    git add --all ; git commit -m "$git_msg" --author "MeFirst MeLast <first.last@gmail.com>"
    GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa.me -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" \
    git push ; 
    # and verify 
    clear ; git log --pretty --format='%h %ae %<(15)%an ::: %s

    # stop :: how-to use different ssh identity files
Йордан Георгиев
источник