SSH 多账号的配置

/ 建站 / 没有评论 / 1750浏览

当我们有多个 SSH 账号时,会遇到需要使用不同 SSH 账号登录不同的远程服务器,或 push 不同的远程仓库的情况,比如:

如何在每次 push/pull/远程登录时自动匹配这些信息呢?笔者说下常用的解决方案。

多个用户信息的配置

在使用 git 推送代码到远程仓库时,若不同仓库的用户名不同,可将最常用的用户名设置为全局用户名,不常用的用户名单独在指定仓库进行设置。

全局设置

执行如下命令进行全局设置:

git config --global user.name "user_gh"
git config --global user.email "user_gh@gmail.com"

也可以编辑 ~/.gitconfig,设置如下:

[user]
    name = user_gh
    email = user_gh@gmail.com

指定设置

在指定仓库下执行如下命令:

git config user.name "user_gh"
git config user.email "user_gh@gmail.com"

也可以编辑该仓库下的 .git/config,设置如下:

[user]
    name = user_gh
    email = user_gh@gmail.com

多个 SSH key 的配置

如何让不同的 SSH key 自动识别不同的目标地址呢?笔者以开头的需求为例,说下配置 git 的过程,若需求是访问远程服务器,配置相似。

生成 SSH key

使用 ssh-keygen 命令生成公私钥,一般常用的参数如下:

如为 github.com 生成新 SSH key,key 名为 id_rsa_gh:

> ssh-keygen -f ~/.ssh/id_rsa_gh -C user_gh@gmail.com
> ls -l
id_rsa
id_rsa.pub
id_rsa_gh
id_rsa_gh.pub

注意:若已有 ~/.ssh/id_rsa 和 ~/.ssh/id_rsa.pub,建议先对这两个文件进行备份,防止误操作覆盖了这两个文件。

将生成的 SSH 公钥(~/.ssh/id_rsa_gh.pub)内容添加到 github(Settings > SSH and GPG keys > New SSH key)中。若是要登录远程服务器,将公钥添加到远程服务器的 ~/.ssh/authorized_keys 文件中。

使用 ssh-agent 管理 SSH key

在使用上述 SSH key push 文件到 github 时可能会提示 ERROR: Permission to qileq/x.git denied to some-username,这里的用户名 "some-username" 可能不是 .git/config 设置的用户名。类似的若是 ssh 登录远程服务器,可能仍需要输入密码。这两个问题的原因可能是未使用正确的 SSH 私钥,这个问题可以通过 ssh-agent 来解决。

ssh-agent 是一个管理 SSH key 的后台辅助程序,它将私钥加载到内存中,避免每次使用私钥时都需要输入密码,自动加载 ~/.ssh/id_rsa、 ~/.ssh/id_dsa 和 ~/.ssh/id_ecdsa 等各类型的默认私钥,这就是为什么我们不需要显式将 ~/.ssh/id_rsa 添加到 ssh-agent,却能访问远程服务器的原因。当 client 通过 ssh 连接到远程服务器时(或请求 github 时),服务器端会发送验证请求来识别 client 的身份,此时 client 会将验证请求转发给 ssh-agent,ssh-agent 根据配置查找已加载的私钥,然后将私钥处理过后的验证数据发送给 server 进行验证。从某种程序上来讲,ssh-agent 是 SSO 的一种实现。

ssh-agent 通过 ssh-add 来管理私钥,如下是 ssh-add 的一些习惯用法:

macOS 系统是开机自动启动 ssh-agent,而 Linux 需要执行 eval $(ssh-agent -s) 来启动 ssh-agent。在启动 ssh-agent 后,执行 ssh-add ~/.ssh/id_rsa_gh 将新生成的私钥添加到 ssh-agent,然后执行 ssh -T git@github.com 测试私钥是否正确。

这里有个问题,前面说到 ssh-agent 将私钥保存在内存中,那么当机器重启后,这些私钥信息都将失效,需要把所有需要的私钥再加载一遍。如何解决这个问题呢?这里有两种方案:

  1. 每次执行 ssh-add filename 添加私钥时,都将操作命令保存到 ~/.zshrc 或 ~/.bashrc 等终端工具中。

  2. 使用 keychain 来管理私钥。使用

    ssh-add -K filename
    

    可将私钥添加到用户的 keychain 中。

    1. macOS 自带 keychain,若 ssh 未使用 keychain,尝试在 ~/.ssh/config 中添加 UseKeychain yes,如: Host github.com UseKeychain yes
    2. Linux 通过包管理器可安装 keychain。

使用 ssh-agent 还能实现 SSH 代理转发的功能,更多内容可参考 An Illustrated Guide to SSH Agent Forwarding 和 使用 SSH 代理转发,由于这些内容和本文关系不大,故此不赘述。

配置 ssh config

编辑 ~/.ssh/config,针对不同的仓库地址配置不同的 Host、HostName、User 和 IdentityFile,如下:

Host github.com
  HostName github.com
  User user_gh
  IdentityFile ~/.ssh/id_rsa_gh

Host gitlab.com
  HostName gitlab.com
  User user_gl
  IdentityFile ~/.ssh/id_rsa_gl

这样不同的仓库即使用不同的信息了。

修改仓库配置

这里还有个问题,如果 github.com 上两个仓库使用的用户信息不同该如何处理呢?假设一个用户是 user_gh,一个用户是 qileq,分别有各自的私钥。配置过程如下:

  1. 修改 ~/.ssh/config,添加 User qileq 相关的信息,如下:

    Host github.com HostName github.com User user_gh IdentityFile ~/.ssh/id_rsa_gh

    Host github-qileq.com HostName github.com User qileq IdentityFile ~/.ssh/id_rsa_qileq

    Host gitlab.com HostName gitlab.com User user_gl IdentityFile ~/.ssh/id_rsa_gl

  2. 修改仓库的 git 信息,将仓库配置 url 中的 github.com 替换为 ssh config 中设置的 Host 值。 以 Java 教程 java-roam-guide 为例,可以使用如下两种方式来修改仓库地址:

    1. 执行命令 git remote set-url origin git@github-qileq.com:qileq/java-learning.git
    2. 将该仓库 .git/config 中的 url = git@github.com:qileq/java-learning.git 修改为 url = git@github-qileq.com:qileq/java-learning.git 修改完成后,执行 git remote -v 查看仓库地址是否正确。 注:这里的仓库设置为 git 协议,非 https 协议。

问题

Repository not found

在 push/pull 部分仓库的数据时,有如下报错:

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 确认下是否相应的私钥未加载到内存中。若未加载,通过 ssh-add 加载后再次 push/pull 重试。

可以看到 SSH 有一套强大而又复杂的规则体系,通过正确的设置能节省我们不少时间。笔者这里抛砖引玉,对多账号的设置进行了一个总结,若有不当之处,请多指正。