121

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

请注意,Github 不允许重复使用帐户级别密钥这一事实是有道理的(两个用户不应共享密钥)。我质疑的只是对部署密钥的限制。

需要明确的是,我不是在寻找解决方法(创建一个虚拟用户,使用多个密钥,...),而只是为了对 Deploy Keys 的这种限制进行合理的解释。

相关话题:

4

4 回答 4

24

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

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

相反,github 强制将项目 1:N 映射到基于密钥对的身份。现实世界的模拟是,有一扇门可以让许多不同的人打开该项目的访问权限。但是一旦他们中的任何一个人拿到了门钥匙,他们就再也拿不到其他门的钥匙了。

如果密钥被泄露,从遏制违规的角度来看,不要经常重复使用密钥是有意义的。但这只是一个好的管理政策原则上防止密钥被多次使用没有多大意义。有些门的钥匙永远不会重复使用,嗯,这又取决于政策


稍微复杂一点的视图是将密钥对说明为角色。您可以拥有许多密钥对,因此担任许多角色。私钥对您进行角色身份验证。

Github 对项目的部署键映射表明一个角色永远不能包含多个任务。这很少是现实的。

当然,这些都不会改变 github 允许的内容。

于 2018-03-19T21:09:20.043 回答
22

您引用的解决方法(创建单个“构建”用户,或在id_rsa.REPONAME.pub每个仓库共享相同用户)说明的唯一原因是:

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

即使您的情况并非如此(构建多个项目),但允许重用相同的 ssh 密钥将为两个不同的用户共享相同的 ssh 密钥提供可能性,这将破坏身份验证目的。

身份验证意味着:
“使用某个 ssh 密钥应该意味着您应该知道谁在使用它”。


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

  • SSH 代理转发:当您通过 SSH 连接到服务器并运行 git 命令时,代理转发使用已在本地开发机器上设置的 SSH 密钥。
    您可以有选择地让远程服务器访问您的本地 ssh-agent,就好像它在服务器上运行一样。
    因此无需在服务器上复制您的私钥。

  • 机器用户:(这是“虚拟帐户”策略)将密钥附加到用户帐户。由于此帐户不会被人类使用,因此称为机器用户。
    你会像对待人类一样对待这个用户,将密钥附加到机器用户帐户,就好像它是一个普通帐户一样。
    授予帐户协作者或团队访问其需要访问的存储库的权限。
    因此,一个私钥关联到一个“机器用户”,每个服务器一个。

DHa在评论中指出了部署密钥限制数,以及您只能拥有一个机器用户帐户的事实)

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

这一次,ssh 密钥没有附加到用户(您可以授予对多个存储库的访问权限),而是附加到一个存储库。
授予多个repo 的 ssh 访问权限相当于“机器用户”。

认证方面:

  • 当用户完成时,对多个存储库使用相同的密钥是可以的(已经说过与他/她的帐户相关联的密钥)
  • 当密钥由存储库附加时,对多个存储库使用相同的密钥是不行的,因为您根本不知道访问了什么。
    这与“机器用户”不同,其中“用户”被声明为许多 repo 的协作者。
    在这里(部署密钥),没有“合作者”,只是授予 repo 的直接 ssh 访问权限。

Yusuf Bhabhrawala在评论中进一步说明了这种模型限制:

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

目前无法使用部署密钥或帐户密钥(这会暴露太多其他存储库)来部署这个非常简单的用例。

Chris Stenkamp指出“如何发现 ' pip install git+ssh://...' 在哪里搜索 ssh 密钥? ”,其中涉及设置 GIT_SSH_COMMAND环境变量。

于 2012-11-05T07:01:18.537 回答
3

我花了很多心思来合理化这些影响并想出了这个场景。

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

这听起来像是一个好处,但是一旦考虑到人为因素,这种多对一的关系实际上本质上是不安全的。这是因为如果不检查每个存储库并单独比较每个公钥,如果您忘记了实际分配的位置,您无法确定是否真的撤销了所有访问权限。

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

于 2017-11-08T23:40:22.363 回答
2

我意识到您不是在寻找解决方法,但我想很多用户登陆此页面并且也想要一个简单的解决方案。您周围的工作发布了一个链接,类似于github docs中的内容。如果手动完成,该过程很容易出错。

仅供参考,Bitbucket.org 没有此限制。您可以在多个 repos 上使用相同的只读访问密钥。这使得使用具有多个存储库的单个生产服务器变得超级容易

如果您坚持使用 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
于 2021-08-09T02:25:07.570 回答