您如何指定`go get` 将使用哪个 ssh 密钥

如何解决您如何指定`go get` 将使用哪个 ssh 密钥

我在同一台笔记本电脑(运行 Ubuntu 20 版)上使用两个不同的 github 帐户(个人和工作)。我需要能够使用我的工作 github 帐户的 ssh 密钥从工作中访问私有存储库。

我已经使用一些简洁的 git 配置控件完成了所有工作,即在我放置的 ~/.gitconfig 文件中:

[url "git@github.com:work_account/"]
    insteadOf = https://github.com/work_account/
[includeIf "gitdir:~/src/github.com/personal_account/"]
    path=~/.gitconfig_personal
[includeIf "gitdir:~/src/github.com/work_account/"]
    path=~/.gitconfig_work

个人配置包含:

[user]
name = Your Name
email = your.name@gmail.com
[core]
sshCommand = ssh -i ~/.ssh/id_rsa

工作配置包含:

[user]
name = Your Name
email = your.name@work.com
signingkey = <ID of GPG key>
[core]
sshCommand = ssh -i ~/.ssh/id_ecdsa
[commit]
gpgsign = true
[gpg]
program = gpg

这对于从 github 拉取和推送(并使用 gpg 密钥签署工作提交)非常有用,但对于私有存储库上的 go get 则失败。出于某种奇怪的原因,go get 试图使用我的个人 ssh 密钥 (~/.ssh/id_rsa) 而不是我的工作 ssh 密钥 (~/.ssh/id_ecdsa)。我已经设置了 GOPRIVATE 环境变量,即

export GOPRIVATE=github.com/work_account/*

go get 的输出是这样的:

$ go get github.com/work_account/private_repo
go get github.com/work_account/private_repo: module github.com/work_account/private_repo: git ls-remote -q origin in /home/marc/pkg/mod/cache/vcs/ff3efb332cb48232e5da90ff2073685cbdac4a86e3a47aa11663696f4943637a: exit status 128:
        ERROR: Repository not found.
        fatal: Could not read from remote repository.

        Please make sure you have the correct access rights
        and the repository exists.

我可以看到我的 ssh 代理有两个密钥:

$ ssh-add -l
521 SHA256:EKvhgg24_blah_bApjLSqX4J7l0 your.name@work.com (ECDSA)
4096 SHA256:r/qcO94F+ox_blah_JkTiVk+aERk your.name@gmail.com (RSA)

当我删除我的个人 ssh 密钥(即 rm ~/.ssh/id_rsa*)时,go get 在私有存储库上运行良好,所以我知道它肯定只是在尝试使用错误的 ssh 密钥。出于某种原因,它忽略了 git 配置 core.sshCommand

解决方法

经过大量的反复试验和挖掘,我找到了解决方案。如果我在私有存储库中设置环境变量 GIT_SSH_COMMAND="ssh -i ~/.ssh/id_ecdsa",那么 go get 使用正确的 ssh 密钥,然后用于私有存储库。 go get 似乎忽略了 git config core.sshCommand,但考虑了环境变量 GIT_SSH_COMMAND

为了简化我的生活,我使用程序 direnv 在保存我的工作存储库的文件夹中设置此环境变量。顶级文件夹中的 .envrc 文件如下所示:

export GIT_SSH_COMMAND="ssh -i ~/.ssh/id_ecdsa"
,

您需要在 ~/.ssh/config 文件中使用它。如果它不存在,只需创建它。它指定用于每个主机的 ssh 密钥。您可以通过添加无效域来添加各种别名:

Host gitlab.com
IdentityFile ~/.ssh/id_ed25519

Host github.com
IdentityFile ~/.ssh/id_ed25519

Host github.invalid
HostName github.com
IdentityFile ~/.ssh/id_rsa

然后每次使用 git@github.invalid 时,都使用正确的 ssh 密钥。

相关的是对 ~/.gitconfig 的添加,它有助于导入私有存储库。它使用 ssh 获得这些主机的所有 git 操作:


[url "git@github.com:"]
        insteadOf = https://github.com/
[url "git@gitlab.com:"]
        insteadOf = https://gitlab.com/

另请参阅环境变量 GOPRIVATE,其中列出了不使用代理的私有存储库。 Example

GOPRIVATE=*.corp.example.com,rsc.io/private
,

您可以使用 SSH 代理。 ssh-agent 是 openssh 的一部分。它还在内存中保存未加密的密钥和证书。它们可供 ssh 使用。

例如,当您拥有带有 passphase 的 ssh-key 时,这非常有用。默认情况下,它每次都会要求您输入密钥密码,go 正在尝试从上游克隆/拉取代码。

有几个命令,你可以使用:

  • echo $SSH_AGENT_PID - 查看代理是否已分配给当前会话。 SSH_AGENT_PID 变量应返回 ssh-agent 的 pid。
  • eval $(ssh-agent) - 开始新的 ssh-agent 会话。
  • ssh-add -l - 列出 ssh 会话中可用的密钥
  • ssh-add ~/.ssh/tmp/id_rsa - 将 ~/.ssh/tmp/id_rsa 键添加到当前会话。

示例会话可以是:

ip-192-168-200-63:tf-r0 daniel$ echo $SSH_AGENT_SOCK
ip-192-168-200-63:tf-r0 daniel ^C

ip-192-168-200-63:src daniel$ eval `ssh-agent`
Agent pid 50734
ip-192-168-200-63:src daniel$ echo $SSH_AGENT_PID 
50734
ip-192-168-200-63:src daniel$ ssh-add -l
The agent has no identities.
ip-192-168-200-63:src daniel$ ssh-add ~/.ssh/tmp/id_rsa
Enter passphrase for /Users/daniel/.ssh/tmp/id_rsa: 
Identity added: /Users/daniel/.ssh/tmp/id_rsa (/Users/daniel/.ssh/tmp/id_rsa)
ip-192-168-200-63:src daniel$ ssh-add -l
2048 SHA256:nm/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX /Users/daniel/.ssh/tmp/id_rsa (RSA)
ip-192-168-200-63:src daniel$ 

之后,我可以使用受密码保护的 ssh 密钥提取远程代码,而无需每次都输入,需要密钥。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?