对于使用 git 部署到服务器的生产 Web 服务器,设置用户和权限的最佳方法是什么?
背景
运行 Ubuntu 12.04,我让 apache 在 下提供文件服务/var/www
。www-data
我在根用户目录下还有一个裸 git repo,它将/var/www/example.com
在 post-receive 钩子中签出。
这工作得很好,但考虑到它是一台生产服务器,我想加强一些安全性,并从根用户中删除存储库。所以我创建了一个 git 用户并在 下设置了存储库/home/git
。但现在我遇到了权限问题,因为一个用户拥有存储库,而另一个用户拥有 Web 根目录。
我在网上看过很多论坛和教程。大多数似乎只使用 root 用户,其他的似乎有更严重的安全问题(例如授予www-data
对存储库的读取权限)。我正在寻找来自现实世界经验的见解,因为有很多方法可以做到这一点。
需要注意的是,post-receive 钩子的作用不只是检查。它还执行一些构建过程,例如运行 Composer 和一些其他 php 脚本,这可能需要几分钟。
我尝试过几种解决方案:
我尝试将 git 用户添加到www-data group
,然后在钩子末尾将 Web 根目录改回www-data
。这有两个问题。首先,我必须修改 sudoers 文件,而我得到的结果时好时坏。其次,在钩子运行的那几分钟内,签出的文件归 git 所有,而不是www-data
,因此网站上的用户可能会收到读取错误。
我尝试将 post-receive 的内容放在另一个文件中,然后使用 sudo 执行它。同样,这需要编辑 sudoers 文件,以便 git 用户无需密码即可使用 sudo。
或者可能是将 repo 留在 root 用户下是两害相权取其轻,而我所做的一切都是徒劳的。
有没有我还没尝试过的更好的解决方案?
答案1
创建一个新组,并将git
和www-data
用户添加到其中。然后设置您的裸 Git 存储库,使其始终使用您创建的组作为存储库文件的 gid。使用新的裸存储库,您可以使用 执行此操作git init --shared=group
。(参考)这将允许该www-data
帐户读取存储库。
更新您的 sudoers 以允许该帐户无需密码git
即可运行命令。www-data
# file: /etc/sudoers.d/gitpush
# permissions should be 0440
# git user is allowed to basically do anything as the www-data user
git ALL=(www-data) NOPASSWD: ALL
然后只需将执行检查/修复所需的所有命令写入post-receive
脚本即可。sudo -u www-data
答案2
我认为有更好的方法来处理这种情况。
首先,我会从简单的切换git
到具有某种基于角色的访问控制 (RBAC) 的东西,例如gitolite
。
我也建议阅读这文章描述了与您需要的工作流程非常相似的工作流程。
为了满足您的要求,实施解决方案的步骤如下:
- 使用 RSA 密钥授予 RBAC
gitolite
- 配置并使用上面链接的文章中描述的钩子来确保所有者、组和权限的正确性。
在我看来,它的优点有很多:
- 你不需要向任何人授予文件的直接访问权限
- 你可以通过
post-update
钩子脚本触发任何事 - 与已发布内容的每次交互都通过
git
存储库进行,因此审计成为一项简单的任务(git log
并且git blame
) - 你不需要使用 ACL 或混合组权限 (DAC)
- 您可以透明地使用强制访问控制 (MAC) 安全性
答案3
在标准 mod_php 上,/var/www/example.com 可能归 git 用户所有,并且任何需要由 php 写入的文件/文件夹都需要归 www-data 所有(或具有 666/777 权限)。在这种情况下,一个虚拟主机可以写入其他虚拟主机文件。
或者:如果您正在运行 mod_php,您可以将 mod_ruid2 添加到 Apache,然后使用自己的 uid 运行每个虚拟主机。在本例中,uid 为 git 用户。或者,如果您喜欢类似 fastcgi 的设置,并且每个虚拟主机都有自己的 php-fpm 池,则可以使用 php-fpm。这样,每个虚拟主机都可以写入自己的文件,但不能写入来自其他虚拟主机的文件。
取决于你喜欢哪种方式。
答案4
在研究这个问题一段时间后,我发现默认情况下,/var/www/*
创建的所有者是 root,这就是为什么尝试修改除此以外的任何内容su
都会失败,所以基于这个答案我发现这样做更容易:
sudo chown -R git:group /var/www/*
此后,我就能git <anything>
进入该/www
文件夹了。