对多个 github 项目使用相同的部署键

Github 不允许在多个项目中使用相同的 ssh 部署密钥,这在某些情况下非常有用(例如,CI 服务器处理带有私有子模块的项目)。我已经看到了各种各样的线程,似乎说这种限制是出于“安全原因”,但我还没有看到一个令人信服的解释,究竟什么样的风险会提高。

注意,Github 不允许重用 帐户水平密钥的事实是有道理的(两个用户不应该共享密钥)。我质疑的只是对 启动钥匙的限制。

需要说明的是,我是 没有,正在寻找变通方法(创建一个虚拟用户,使用多个密钥,...) ,但只是为了对 Deploy Keys 的这种限制提供一个合理的解释。

相关文章:

43771 次浏览

唯一的原因,通过你参考的解决方案(创建一个单一的“构建”用户,或者共享相同的 id_rsa.REPONAME.pub每个回购)说明是:

避免为不同用户共用公钥/私钥

尽管在您的情况下(构建多个项目)不会出现这种情况,但是允许重用相同的 ssh 键将为两个 与众不同用户共享相同的 ssh 键提供可能性,这将破坏 认证的用途。

认证意味着:
“使用某个 ssh 键应该意味着您应该 知道是谁正在使用它”。

但是,正如 Jtlindsey回答中所指出的,这与身份验证/身份/良好策略关系不大,而更多地与附加到这些密钥的“ 角色”有关。(部署某个存储库的角色)。

正如 Tkeeler在“ 为什么我不能对多个 github 回购使用一个 ssh 键?”中指出的:

当使用自动化系统和 git 子模块时,这个工作流就成了一个问题。
您不能在多个回购中使用相同的部署密钥,因此解决方案变成将该密钥添加到他们的用户帐户(或专用的机器帐户)。

采取最少的阻力路径,大多数用户会添加到自己的帐户,导致更大的安全风险。

GitHub 应该让用户根据每个存储库来选择和承担风险


GitHub 页面“ 管理部署键 ”详细介绍了使用 ssh 的各种帐户:

  • SSH 代理转发 : 代理转发使用 SSH 进入服务器并运行 git 命令时在本地开发计算机上已经设置的 SSH 密钥。
    您可以有选择地让远程服务器访问本地 ssh-agent,就像它在服务器上运行一样。
    因此,不需要在服务器上复制您的私钥。

  • 机器用户 : (这是“虚拟帐户”策略)将密钥附加到用户帐户。因为这个帐户不会被人类使用,所以它被称为机器用户。
    不过,您可以像对待人类一样对待这个用户,将密钥附加到机器用户帐户,就好像它是一个普通帐户一样。
    允许客户合作者或团队访问它需要访问的回购协议。
    所以一个私钥关联到一个“机器用户”,每个服务器一个。

(哈哈在评论中指向一个部署键限制号,并且您只能有一个计算机用户帐户)

  • 部署 key (每个 GitHub repo 一个) SSH 密钥,该密钥存储在服务器上,并授予对 GitHub 上单个 repo 的访问权。
    此密钥直接连接到回购,而不是连接到用户帐户
    不要转到您的帐户设置,转到目标回购的管理页面。
    转到“ Deploy Keys”,点击“ Add deploy key”。粘贴公钥并提交。

这一次,ssh 密钥没有附加到一个用户(对于这个用户,您可以授予对多个 repo 的访问权) ,而是附加到一个 repo。
好几个 repo 授予 ssh 访问权等同于“机器用户”。

认证而言:

  • 使用相同的密钥进行多次回购是可以的,当它是由一个用户完成的时候(已经说了密钥与他/她的帐户相关)
  • 使用相同的钥匙进行多次回购是不可以的,当钥匙被回购附加时,因为你根本不知道 访问了什么。
    这与“机器用户”不同,在“机器用户”中,“用户”被声明为许多回购的合作者。
    在这里(Deploy key) ,没有什么“通敌者”,只是授予回购的直接 ssh 访问。

Yusuf Bhabhrawala 评论中进一步说明了这个模型的局限性:

考虑这些非常合理的用例——使用私有 pip 模块的 python 项目或使用私有 npm 包的节点项目——都来自同一组织中的另一个 repo。

目前还没有办法部署这个非常简单的用例,无论是使用部署密钥还是帐户密钥(这暴露了太多其他回购协议)。

Chris Stenkamp指向“ 如何发现“ pip install git+ssh://...”在哪里搜索 ssh 键?”,这涉及到设置 GIT_SSH_COMMAND的环境变量。

我花了很多心思来合理化这个暗示,并且想出了这个方案。

假设您为分配给多个存储库的用户创建了一个部署键。现在您想要撤销那个密钥,但是它在多个地方使用。因此,不能撤销所有访问权限,您可能无意中只撤销部分访问权限。

这听起来似乎是一个好处,但是一旦你考虑到人的因素,这种多对一的关系实际上是内在的不安全的。这是因为在没有检查每个存储库和单独比较每个公钥的情况下,您不能确切地知道是否已经撤销了所有访问,以防您忘记了实际分配公钥的位置。

分配和管理如此多的独特密钥肯定是令人沮丧的,但是 GitHub 如何制定他们的策略: 当你撤销一个密钥时,你保证会撤销该密钥授予的所有访问权限,因为它只在一个地方使用。的安全影响是显而易见的

不幸的是,在这种情况下,github 只是误解了密钥对和帐户或项目之间的区别。

由于密钥对用于身份验证和授权,因此它实际上是一个标识。Github 账户是另一个身份。将 github 帐户连接到密钥对可以有效地在基于 github 帐户的身份和密钥对身份之间建立1: N 的映射。

相反,github 强制项目到基于密钥对的标识的1: N 映射。现实世界的类似情况是,有一扇门可以让许多不同的人打开,进入项目。但是一旦他们中的任何一个拿到了门的钥匙,他们就再也拿不到其他任何门的钥匙了。

如果一个密钥被破坏,那么从包含破坏的角度来看,不经常重用密钥是有意义的。但这只是一个良好的管理 政策。防止键被多次使用 原则上没有多大意义。有些门的钥匙永远不会被重复使用,这也是 政策的问题。


一个稍微复杂一点的视图是将键对说明为 角色。您可以拥有许多密钥对,因此可以驻留许多角色。私钥验证您的角色。

Github 将关键字映射部署到项目中,指出一个角色永远不能包含多个任务,这是不现实的。

当然,这些都没有改变 github 允许的内容。

我知道你不是在寻找一个解决方案,但我想很多用户登陆这个页面,也想要一个简单的解决方案。你周围的工作发布了一个链接类似于什么是 在 Github 文件里。如果手动完成,这个过程很容易出错。

仅供参考,Bitbucket. org 没有这个限制。你可以 对多个回购协议使用相同的只读访问密钥。这使得使用具有多个回购协议的单个生产服务器非常容易

如果你坚持使用 Github,这里有一个我编写的 剧本,它允许你通过运行 ./generateDeployKey.sh repo_owner_name repo_name简单地传递你的回购所有者的名字和存储库的名字,它为你做所有的事情,并输出你可能需要复制的任何东西。

将以下内容保存到名为 generateDeployKey.sh的新文件中

#!/bin/sh
# This script generates a ssh key for a single repository
# and adds a custom configuration to the users (not global) ssh config file,
# and outputs the public key for you to copy and paste as the repo deploy key
# and outputs the url for you to clone the repo on the machine.
# Github docs ref:
# https://docs.github.com/en/developers/overview/managing-deploy-keys#using-multiple-repositories-on-one-server
#
# 1. Add the script to the user account of the machine. The home directory is fine.
# 2. Make the script executable by running the following command as the user:
# chmod u+x generateDeployKey.sh
# 3. Run script like `./generateDeployKey.sh REPO_OWNER_NAME REPO_NAME` Note the space between owner and repo name. Example:
# ./generateDeployKey.sh yourname hello_world
# If you make a mistake with what you pass in, you can remove change from your ~/.ssh/config file
# by deleting the most recent "New Key Generated on...." and deleting the related .pub and private keys




# Check if user passed in both parameters
if [ -z "$1" ] || [ -z "$2" ]
then
echo "Make sure to pass in both parameters REPO_OWNER_NAME and REPO_NAME. Example:"
echo "./generateDeployKey.sh yourname hello_world"
else
REPO_OWNER_NAME=$1
REPO_NAME=$2
KEY_PATH=~/.ssh/id_rsa.$REPO_NAME
echo "Generating ssh key At ${KEY_PATH}"
ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa.${REPO_NAME}
echo "Your ssh deploy key is:"
PUB_KEY_PATH=$KEY_PATH".pub"
cat $PUB_KEY_PATH
echo ""
# Will create config if it does not exist
echo "Updating ~/.ssh/config"
DATE_TIME=$(date +"%Y-%m-%d at %r")
echo "
# New Key Generated on $DATE_TIME
Host github.com-$REPO_NAME
HostName github.com
User git
IdentityFile $KEY_PATH" >> ~/.ssh/config
echo ""
echo "Here is your hostname's alias to interact with the repository using SSH:"
echo "git clone git@github.com-$REPO_NAME:$REPO_OWNER_NAME/$REPO_NAME.git"
fi

官方的解决方案是 https://docs.github.com/en/developers/overview/managing-deploy-keys#using-multiple-repositories-on-one-server
这基本上就是这个问题的解决方案,为每个存储库创建一个带有假域的密钥

他们这样做是为了强制支付更多具有部署只读访问权限的用户吗?