为给定域的git push指定SSH密钥


341

我有以下用例:我希望能够推送到git@git.company.com:gitolite-admin使用用户的私钥gitolite-admin,而我想推送到git@git.company.com:some_repo使用“我自己的”私钥。AFAIK,我无法使用来解决此问题~/.ssh/config,因为在两种情况下,用户名和服务器名是相同的。由于我通常使用自己的私钥,因此在~/.ssh/configfor 中定义了私钥git@git.company.com。有谁知道一种方法来覆盖用于单个git调用的密钥?

(此外:gitolite会根据密钥来区分谁在进行推送,因此就访问,所有权和审核而言,user @ server字符串对于不同用户而言是相同的,这不是问题。)


Answers:


596

即使用户和主机相同,也可以在中区分它们~/.ssh/config。例如,如果您的配置如下所示:

Host gitolite-as-alice
  HostName git.company.com
  User git
  IdentityFile /home/whoever/.ssh/id_rsa.alice
  IdentitiesOnly yes

Host gitolite-as-bob
  HostName git.company.com
  User git
  IdentityFile /home/whoever/.ssh/id_dsa.bob
  IdentitiesOnly yes

然后,您只需使用gitolite-as-alicegitolite-as-bob不是URL中的主机名:

git remote add alice git@gitolite-as-alice:whatever.git
git remote add bob git@gitolite-as-bob:whatever.git

注意

您要包括IdentitiesOnly yes防止使用默认ID 的选项。否则,如果您还拥有与默认名称匹配的ID文件,则将首先尝试使用它们,因为与其他配置选项不同(该选项遵循“先入胜”),该IdentityFile选项会附加到身份列表中进行尝试。参见:https : //serverfault.com/questions/450796/how-could-i-stop-ssh-offering-a-wrong-key/450807#450807


9
很好,谢谢。我不知道您可以在〜/ .ssh / config中随意选择“别名”作为Host规范
Confusion

4
也感谢您的回答!对我来说,一个陷阱是IdentityFile必须是完整路径(我只将id_rsa.rick作为我对IdentityFile的参数,但这失败了)。有关IdentityFile的其他语法,请参见ssh_config(5)手册页。
rickumali 2011年

1
非常感谢您提供清晰而有用的答案。我试图使它工作一段时间,并在假定同一用户必须使用相同的id_rsa私钥文件的前提下放弃了。
DrCord

7
git@遥控器中的部分不是必需的,因为它User在配置行中给出。
2013年

2
我一直在为此解决方案苦苦挣扎,直到我在主机IdentitiesOnly yes所在行之后立即添加了另一行IdentityFile。似乎正在传递多个身份,其中一个身份被阻止访问主机。
Fitter Man

57

Mark Longair提供的上述方法的替代方法是使用别名,该别名将使用替代的SSH密钥在任何远程上运行任何 git命令。这个想法基本上是在运行git命令时切换您的SSH身份。

相对于其他别名中的主机别名方法的优点:

  • 即使您不能明确指定,也可以使用任何 git命令或别名remote
  • 使用许多存储库更容易,因为您只需要在每个客户端计算机上设置一次,而不需要在每个客户端计算机上每个存储库设置一次。

我使用一些小脚本和git别名admin。这样我可以做到,例如:

git admin push 

使用备用(“ admin”)SSH密钥推送到默认远程服务器。同样,您可以使用任何push使用此别名的命令(而不仅仅是)。您甚至git admin clone ...可以克隆只能使用“ admin”键访问的存储库。

第1步:创建备用SSH密钥,可以选择设置密码,以防在他人的计算机上执行此操作。

步骤2:创建一个名为“ ssh-as.sh”的脚本,该脚本运行使用SSH的内容,但使用给定的SSH密钥而不是默认密钥:

#!/bin/bash
exec ssh ${SSH_KEYFILE+-i "$SSH_KEYFILE"} "$@"

步骤3:创建一个名为“ git-as.sh”的脚本,该脚本使用给定的SSH密钥运行git命令。

#!/bin/bash
SSH_KEYFILE=$1 GIT_SSH=${BASH_SOURCE%/*}/ssh-as.sh exec git "${@:2}"

步骤4:添加一个别名(使用适用于下面“ PATH_TO_SCRIPTS_DIR”的名称):

# Run git commands as the SSH identity provided by the keyfile ~/.ssh/admin
git config --global alias.admin \!"PATH_TO_SCRIPTS_DIR/git-as.sh ~/.ssh/admin"

有关更多详细信息,请访问:http : //noamlewis.wordpress.com/2013/01/24/git-admin-an-alias-for-running-git-commands-as-a-privileged-ssh-identity/


4
很好的答案。为了安全起见,请不要忘记在$@-> 前后加上双引号"$@"
kevinarpe 2014年

@sinelaw这仍然有效吗?我一直都得到许可被拒绝的错误
Alok Kumar

55

您可以利用git环境变量GIT_SSH_COMMAND。在您的终端中的git仓库下运行此命令:

GIT_SSH_COMMAND='ssh -i ~/.ssh/your_private_key' git submodule update --init

替换~/.ssh/your_private_key为您要使用的ssh私钥的路径。你可以改变随后的git命令(在本例中是git submodule update --init)别人喜欢git pullgit fetch等等。


1
完整文档位于git-scm.com/docs/git#git-codeGITSSHcode ; 它需要一个recentish GIT中(> = 2.3 *)虽然。
Christian Ulbrich '18

2
感谢您提供一种简单的解决方案,除了设置一个环境变量外,不需要任何其他操作。
诺亚·萨斯曼

4
请注意,〜/ .ssh / id_rsa(或任何默认密钥)将优先于您通过-i传递的密钥。因此,您真的想使用GIT_SSH_COMMAND ='ssh -i〜/ .ssh / your_private_key -o IdentitiesOnly = yes'使其忽略其他密钥
staktrace

如何更新git push?我在文档中找不到它
lebed2045

创建bash或git别名会很好-类似于sinelaw的答案,但是使用此方法而不是必须在某个地方创建脚本。
Inigo

14

一种基于Unix的系统(Linux,BSD,Mac OS X),默认身份存储在$ HOME / .ssh目录中的2个文件中: private key: $HOME/.ssh/id_rsa public key: $HOME/.ssh/id_rsa.pub 如果ssh不带选项使用-i,它将使用默认私钥对远程系统进行身份验证。

如果您要使用另一个私钥,例如$ HOME / .ssh / deploy_key,则必须使用ssh -i ~/.ssh/deploy_key ...

真烦人 您可以将以下行添加到$ HOME / .bash_profile中 ssh-add ~/.ssh/deploy_key ssh-add ~/.ssh/id_rsa

因此,每次使用sshor gitscp(基本上ssh也是)时,就不必再使用option -i了。

您可以在文件$ HOME / .bash_profile中添加任意数量的键。


10

另一种选择是使用ssh-ident来管理您的ssh身份

它会根据您当前的工作目录,ssh选项等自动加载并使用不同的密钥……这意味着您可以轻松地拥有一个工作目录/私有目录,并通过ssh透明地使用不同的密钥和身份。


9

我在Win7上使用Git Bash。以下对我有用。

在〜/ .ssh / config或c:/ users / [您的用户名] /。ssh / config中创建一个配置文件。在文件中输入:

Host your_host.com
     IdentityFile [absolute_path_to_your_.ssh]\id_rsa

我想主机必须是URL,而不仅仅是主机的“名称”或ref。例如,

Host github.com
     IdentityFile c:/users/[user_name]/.ssh/id_rsa

路径也可以以/ c / users / [用户名] / ....格式编写

Giordano Scalzo提供的解决方案也很棒。 https://stackoverflow.com/a/9149518/1738546


9

从git 2.10起,也可以使用gitconfig sshCommand设置。文件状态

如果设置了此变量,则当git fetch和git push需要连接到远程系统时,它们将使用指定的命令而不是ssh。该命令与GIT_SSH_COMMAND环境变量的格式相同,并且在设置环境变量后将被覆盖。

一个使用示例为: git config core.sshCommand "ssh -i ~/.ssh/[insert_your_keyname]

在某些情况下,这是行不通的,因为ssh_config会覆盖命令,在这种情况下,请尝试ssh -i ~/.ssh/[insert_your_keyname] -F /dev/null不使用ssh_config。


8

在阅读其他答案的基础上,我结合了以下技术并与github一起测试了以下方法,该方法结合了一些技术:

  • 正确的SSH配置
  • git URL重写

这种方法的优点是,设置完成后,不需要任何额外的工作即可将其正确设置-例如,您无需更改远程URL或记住以不同的方式克隆事物-URL重写使其可以正常工作。

~/.ssh/config

# Personal GitHub
Host github.com
  HostName github.com
  User git
  AddKeysToAgent yes
  UseKeychain yes
  IdentityFile ~/.ssh/github_id_rsa

# Work GitHub
Host github-work
  HostName github.com
  User git
  AddKeysToAgent yes
  UseKeychain yes
  IdentityFile ~/.ssh/work_github_id_rsa

Host *
  IdentitiesOnly yes

~/.gitconfig

[user]
    name = My Name
    email = personal@personal.email

[includeIf "gitdir:~/dev/work/"]
    path = ~/dev/work/.gitconfig

[url "github-work:work-github-org/"]
    insteadOf = git@github.com:work-github-org/

~/dev/work/.gitconfig

[user]
    email = work@work.email

只要您将所有工作库都放在〜/ dev / work和其他个人资料下,git在对服务器执行请求/克隆/推送时将使用正确的SSH密钥,并且还将正确的电子邮件地址附加到所有你的承诺。

参考文献:


克隆如何工作?includeIf我应该.git以为只有目录才能工作?
detly

等等,我明白了,它是由URL重写完成的。这个答案非常有用!
很有

4

如果在Windows上使用Git的ssh版本,则ssh配置中的身份文件行看起来像

IdentityFile /c/Users/Whoever/.ssh/id_rsa.alice

这里/cc:

要检查,在git的bash中

cd ~/.ssh
pwd 

3

您可能需要删除(或注释掉)默认的主机配置 .ssh /配置


1

您在文件配置密钥ssh中最指定的位置:

# Default GitHub user
Host one
 HostName gitlab.com
 User git
 PreferredAuthentications publickey
 IdentityFile ~/.ssh/key-one
 IdentitiesOnly yes

#two user
Host two
 HostName gitlab.com
 User git
 PreferredAuthentications publickey
 IdentityFile ~/.ssh/key-two
 IdentitiesOnly yes

0

就像其他人提到的那样,core.sshCommandconfig可用于覆盖SSH密钥和其他参数。

这是一个示例,其中有一个备用键名为,~/.ssh/workrsa并希望将其用于克隆到下的所有存储库~/work

  1. .gitconfig在下创建一个新文件~/work
[core]
  sshCommand = "ssh -i ~/.ssh/workrsa"
  1. 在您的全局git config中~/.gitconfig,添加:
[includeIf "gitdir:~/work/"]
  path = ~/work/.gitconfig

0

一种使用的可能性~/.ssh/config是使用Match限制而不是Host限制。特别是Match Exec调用shell命令来决定是否应用声明。在bash中,您可以使用以下命令:

[ git@git.company.com:gitolite-admin = $(git config --get remote.origin.url)'' ]

这使用bash [命令来验证两个字符串是否相等。在这种情况下,它正在测试字符串是否git@git.company.com:gitolite-admin与从$(git config --get remote.origin.url)''命令获得的输出匹配。

您可以使用任何其他命令来标识外壳程序所在的存储库。对于这个工作是重要的$SHELL变量定义你的shell,在我的情况/bin/bash。完整的示例如下~/.ssh/config

Match Exec "[ git@git.company.com:gitolite-admin = $(git config --get remote.origin.url)'' ]"
  IdentityFile ~/.ssh/gitolite-admin
  IdentitiesOnly yes
  ForwardAgent no
  ForwardX11 no
  ForwardX11Trusted no

Match Exec "[ git@git.company.com:some_repo = $(git config --get remote.origin.url)'' ]"
  IdentityFile ~/.ssh/yourOwnPrivateKey
  IdentitiesOnly yes
  ForwardAgent no
  ForwardX11 no
  ForwardX11Trusted no

在此示例中,我假定其中~/.ssh/yourOwnPrivateKey包含您自己的私钥,并且~/.ssh/gitolite-admin包含用户的私钥gitolite-admin。我加入了IdentitiesOnly yes声明,以确保只有Mark Longair提到的git服务器提供了一个密钥。其他声明只是git的标准ssh选项。

如果some_repo要使用不同的键来使用多个配置,则可以添加此配置。如果您有多个存储库,git@git.company.com并且大多数都使用,~/.ssh/yourOwnPrivateKey则将此密钥作为主机的默认值包含会更有意义。在这种情况下,~/.ssh/config将是:

Match Exec "[ git@git.company.com:gitolite-admin = $(git config --get remote.origin.url)'' ]"
  IdentityFile ~/.ssh/gitolite-admin
  IdentitiesOnly yes

Host git.company.com
  IdentityFile ~/.ssh/yourOwnPrivateKey
  IdentitiesOnly yes
  ForwardAgent no
  ForwardX11 no
  ForwardX11Trusted no

请注意,顺序很重要,并且Host git.company.com限制应出现在Match Exec一个或多个之后。


0

使用来配置您的存储库git config。例如:

git config --add --local core.sshCommand 'ssh -i ~/.ssh/<<<PATH_TO_SSH_KEY>>>'
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.