如何告诉git使用哪个私钥?


645

ssh可以-i选择在身份验证时告诉使用哪个私钥文件:

-i identity_file

    选择一个文件,从中读取用于RSA或DSA身份验证的身份(私钥)。缺省值是~/.ssh/identity用于协议版本1,和~/.ssh/id_rsa~/.ssh/id_dsa对于协议版本2.身份文件也可以在每个主机的基础在配置文件中指定。可能有多个-i选项(以及在配置文件中指定的多个标识)。

有没有类似的方法来判断git~/.ssh目录中具有多个私钥的系统上使用哪个私钥文件?


3
在StackOverflow中也可以看到此问题
Flimm,2015年

Answers:


670

在中~/.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

117
如果您需要使用不同的密钥连接到同一主机怎么办?
Valentin Klinghammer

6
@Quelltextfabrik-您可以使用其他主持人添加另一部分:nerderati.com/2011/03/…–
Ben

1
在我的联机帮助页中,@ Cliff Nop:“ HostName:指定要登录的真实主机名。可用于为主机指定昵称或缩写。” 我的ssh版本是openssh-6.7p1。
Grissiom

11
如果配置文件是新的,别忘了chmod 600 ~/.ssh/config
elysch

2
@ValentinKlinghammer @Flimm的答案提供了此问题的解决方案。它是使用core.sshCommandgit配置的。superuser.com/a/912281/162466
VasyaNovikov

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
Abdull

7
@Abdull在Bash中,在与命令相同的行上进行分配,仅导出该命令的环境变量。试试看:example=hello /usr/bin/env | grep example
Flimm

3
事情变得更好:从Git 2.10开始,您可以将命令存储在Git配置中:stackoverflow.com/a/38474220/520162
eckes 2016年

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

使用GIT_SSH_COMMAND环境变量(Git 2.3.0+)传递ssh参数。

例如:

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

您可以在一行中输入所有内容-忽略$并忽略\

选项3: GIT_SSH

使用GIT_SSH环境变量传递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

注意:以上几行是shell(终端)命令行,您应该将其粘贴到终端中。他们将创建一个名为的文件ssh,使其可执行并(间接)执行该文件。

注意:GIT_SSH自v0.99.4(2005)起可用

选项4: ~/.ssh/config

~/.ssh/config按照其他答案中的建议使用文件,以指定私钥的位置,例如

Host github.com
  User git
  Hostname github.com
  IdentityFile ~/.ssh/id_rsa

1
//,但是,如果转发您在ssh-agent中的身份,如该问题那样呢?superuser.com/questions/971732/...
弥敦道Basanese

1
我允许我重新格式化此帖子:IMO,这是迄今为止最全面的答案。在其原始设计中,快速扫描显示了该帖子,其中描述了该问题的单个复杂解决方案,因此我错过了。
艾伯托

3
$ ssh-agent sh -c 'ssh-add ~/.ssh/id_rsa; git fetch user@host'什么都没有为我工作。荣誉
丹尼尔·德赫斯特

1
我不得不使用~/.ssh/config方法,env vars对我不起作用...
Greg Dubicki

1
GIT_SSHv0.99.4(2005年8月)开始可用,因此基本上是因为Git存在(2005年4月)。
多米尼克

32

编写一个ssh使用所需参数调用的脚本,然后将脚本的文件名放入中$GIT_SSH。或者只是将您的配置放在中~/.ssh/config


2
关于如何执行此操作的另一种解释
Sithsu 2014年

1
~/.ssh/config是要走路。
hek2mgl 2015年

我在机器(A)上工作,我从该机器git push到仅接受ssh密钥身份验证的服务器(B)。当我直接那台机器工作时,虽然我在(A)上的〜/ .ssh / config设置工作得很好,但是当我从其他位置(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代理-如果您想要无人值守的克隆/推送/拉取(例如在cron中),则非常有用
  • 绝对不需要外部工具

2
这个答案正是我要让Chef的git资源使用存储库特定的部署密钥从私有Github存储库克隆/获取所需的。与基于环境/基于脚本的方法相比,此方法的另一个优点是,由于密钥路径是在工作存储库的配置中编码的,因此它将在初始克隆和后续提取/推送中使用相同的密钥。
亚当·佛朗哥

2
哇!这太好了,对此一无所知。感谢您的回答,在木偶环境中也非常有帮助,可以避免管理上的额外麻烦.ssh/config。+1!
gf_

1
此解决方案不能与--recursive标志一起使用。子模块未使用指定的密钥获取,因此如果它们需要身份验证,则会失败。
Daniele Testa

1
每个子模块是一个完全不同的存储库,具有自己的一组远程控件。为了您的方便,它们由Git粘合在一起,但是子模块的远程绝不与父存储库中的远程绑定。恐怕您必须使用每个子模块中的ext传输来设置远程,以便父级中的递归起作用。
flaviovs

2
如果遇到以下错误fatal: transport 'ext' not allowed,则必须通过将该白名单列入ext协议export GIT_ALLOW_PROTOCOL=ext。基本上,git-remote-ext远程帮助器(支持“ ext :: ssh example.com%S foo / repo” URL)允许任意命令执行。通常,这从来都不是问题,因为用户总是看到并信任他们传递给git的URL。但是,git子模块通过.gitmodules文件允许攻击者请求客户端获取任意git URL。hackerone.com/reports/104465
Gomino

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  

2
这是我一直在寻找的答案,因为我有用于家庭和工作的单独的GitHub帐户。我只需要设置Host work.github.com HostName github.com IdentityFile ~/.ssh/work,然后在每次克隆工作存储库时都将“ github.com”替换为“ work.github.com”。它仍然连接到“ github.com”,但是使用非默认密钥对。
米克尔

1
详细信息的网址(“ itblog.study.land / ...”)不再起作用:(
Carl Smotricz

@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将尝试将值作为file执行。因此,您必须创建一个脚本。

$ 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

一切都会工作。


谢谢。请注意:直通参数使用“ $ @”而不是$ *,因为当参数包含空格时,前者的行为正确。
Piotr Findeisen

@PiotrFindeisen感谢您的来信。但是,我并不完全理解它-在zsh中,它可以帮助我将字符串与空格保持在一起,而在bash中则不能。您能告诉我更多信息或指出一些解释吗?我不想盲目添加一些修改。
Jan Vlcinsky '16

您应该删除答案的前半部分。没有人对不可行的解决方案感兴趣,而浪费的阅读内容却混淆了底部的正确答案,效果很好。
塞林

@Cerin如果您的意思是删除“避免错误”,我将其保留在那里。它有共同的陷阱要避免,而且很短。我敢肯定,有人会尝试通过将所有事物都提供给变量来优化解决方案(这发生在我身上),所以我试图缩短成功之路。
Jan Vlcinsky

5

您可以只使用ssh-ident而不是创建自己的包装器。

您可以在以下网址阅读更多信息:https : //github.com/ccontavalli/ssh-ident

它会在首次需要时按需加载ssh密钥,甚至在有多个登录会话,xterm或NFS共享目录的情况下,也会按需加载一次。

使用一个很小的配置文件,它可以自动加载不同的密钥,并根据需要将它们保持在不同的代理中(用于代理转发)。


5

我有一个需要单独的github帐户的客户端。因此,我只需要为此项目使用一个单独的密钥。

我的解决方案是将此添加到我的.zshrc / .bashrc中:

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

每当我想为该项目使用git时,我都会用git替换“ infogit”:

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

对我来说,更容易记住。


4

所以我将GIT_SSH env变量设置为$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.identitygit config值:

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

瞧!

如果您可以为每个身份使用不同的电子邮件地址,则它变得更加简单,因为您可以仅在电子邮件地址之后命名密钥,然后让git config的user.email驱动密钥选择,~/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=]

不要忘记多余的点!这使脚本设置了环境变量!--key和--port是可选的。


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为要使用的默认密钥。


2

我在@shellholic和这个SO线程上构建了一些柚木。我以GitHub为例,并假设您有一个私钥~/.ssh/github(否则,请参见此SO线程),并且已将公钥添加到了GitHub个人资料中(否则请参见GitHub的help)。

如果需要,请在创建新的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 

@HeyWatchThis在此SO线程上建议添加IdentitiesOnly yes以防止SSH默认行为,即发送与每个协议的默认文件名匹配的身份文件。有关更多信息和参考,请参见该线程。


这是我的错误:“如果您已经进行了远程设置...”。非常感谢!!!
艾伦·安德拉德

常见错误-这就是答案
戈达德

1

只需使用ssh-agentssh-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

克隆您的存储库。

重新启动计算机后,需要执行以上命令。


请说明该过程,包括如何创建代理
Srikrushna

0

我使用的是git版本2.16,不需要一个脚本,甚至不需要配置或修改的命令。

  • 刚刚将我的私钥复制到.ssh / id_rsa
  • 将权限设置为600

git自动读取密钥。我什么都没问,也没有抛出错误。一切正常。


您是否注意到问题是关于“ ~/.ssh目录中具有多个私钥的系统”?
斯科特(Scott)

0

虽然这个问题并没有要求,但我这个答案提供给其他只想解决

gitlab解决方案

我尝试使用方法,但即使git文档也建议将其~/.ssh/config用于除简单情况以外的其他操作。就我而言,我正在推送到服务器-我想以特定用户的身份进行操作-这当然是由期间的而不是username定义的。实施后,我只需执行以下操作: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做)

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

(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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.