Pro Git - Pro Git 4.7 服务器上的 Git 权限管理器 Gitosis

Pro Git

This is an in-progress translation.
To help translate the book, please fork the book at GitHub and push your contributions.

权限管理器 Gitosis

把所有用户的公钥保存在 authorized_keys 文件的做法只能暂时奏效。当用户数量到了几百人的时候,它会变成一种痛苦。每一次都必须进入服务器的 shell,而且缺少对连接的限制——文件里的每个人都对所有项目拥有读写权限。

现在,是时候向广泛使用的软件 Gitosis 求救了。Gitosis 简单的说就是一套用来管理 authorized_keys 文件和实现简单连接限制的脚本。最有意思的是,该软件用来添加用户和设定权限的界面不是网页,而是一个特殊的 Git 仓库。你只需要设定好某个项目;然后推送,Gitosis 就会随之改变服务器设定,酷吧?

Gitosis 的安装算不上傻瓜化,不过也不算太难。用 Linux 服务器架设起来最简单——以下例子中的服务器使用 Ubuntu 8.10 系统。

Gitosis 需要使用部分 Python 工具,所以首先要安装 Python 的 setuptools 包,在 Ubuntu 中名为 python-setuptools:

$ apt-get install python-setuptools

接下来,从项目主页克隆和安装 Gitosis:

$ git clone git://eagain.net/gitosis.git
$ cd gitosis
$ sudo python setup.py install

这会安装几个 Gitosis 用的可执行文件。现在,Gitosis 想把它的仓库放在 /home/git,倒也可以。不过我们的仓库已经建立在 /opt/git 了,这时可以创建一个文件连接,而不用从头开始重新配置:

$ ln -s /opt/git /home/git/repositories

Gitosis 将为我们管理公钥,所以当前的文件需要删除,以后再重新添加公钥,并且让 Gitosis 自动控制 authorized_keys 文件。现在,把 authorized_keys文件移走:

$ mv /home/git/.ssh/authorized_keys /home/git/.ssh/ak.bak

然后恢复 ‘git’ 用户的 shell,假设之前把它改成了 git-shell 命令。其他人仍然不能通过它来登录系统,不过这次有 Gitosis 帮我们实现。所以现在把 /etc/passwd 文件的这一行

git:x:1000:1000::/home/git:/usr/bin/git-shell

恢复成:

git:x:1000:1000::/home/git:/bin/sh

现在就可以初始化 Gitosis 了。需要通过自己的公钥来运行 gitosis-init。如果公钥不在服务器上,则必须复制一份:

$ sudo -H -u git gitosis-init < /tmp/id_dsa.pub
Initialized empty Git repository in /opt/git/gitosis-admin.git/
Reinitialized existing Git repository in /opt/git/gitosis-admin.git/

这样该公钥的拥有者就能修改包含着 Gitosis 设置的那个 Git 仓库了。然后手动将这个新的控制仓库中的 post-update 脚本加上执行权限。

$ sudo chmod 755 /opt/git/gitosis-admin.git/hooks/post-update

万事俱备了。如果设定过程没出什么差错,现在可以试一下用初始化 Gitosis 公钥的拥有者身份 SSH 进服务器。看到的结果应该和下面类似:

$ ssh git@gitserver
PTY allocation request failed on channel 0
fatal: unrecognized command 'gitosis-serve schacon@quaternion'
  Connection to gitserver closed.

说明 Gitosis 认出了该用户的身份,但由于没有运行任何 Git 命令所以它切断了连接。所以,现在运行一个确切的 Git 命令——克隆 Gitosis 的控制仓库:

# 在自己的电脑上
$ git clone git@gitserver:gitosis-admin.git

得到一个名为 gitosis-admin 的目录,主要由两部分组成:

$ cd gitosis-admin
$ find .
./gitosis.conf
./keydir
./keydir/scott.pub

gitosis.conf 文件是用来设置用户、仓库和权限的控制文件。keydir 目录则是保存所有具有访问权限用户公钥的地方——每人一个。你 keydir 中的文件名(前例中的 scott.pub)应该有所不同—— Gitosis 从使用 gitosis-init 脚本导入的公钥尾部的描述中获取该名。

看一下 gitosis.conf 的内容,它应该只包含与刚刚克隆的 gitosis-admin 相关的信息:

$ cat gitosis.conf 
[gitosis]

[group gitosis-admin]
writable = gitosis-admin
members = scott

它显示用户 scott ——初始化 Gitosis 公钥的拥有者——是唯一能访问 gitosis-admin 项目的人。

现在我们添加一个新的项目。我们将添加一个名为 mobile 的新节段,在这里罗列手机开发团队的开发者以及他们需要访问权限的项目。由于 ‘scott’ 是系统中的唯一用户,我们把它加成唯一的用户,从创建一个叫做 iphone_project 的新项目开始:

[group mobile]
writable = iphone_project
members = scott

一旦修改了 gitosis-admin 项目的内容,只有提交并推送至服务器才能使之生效:

$ git commit -am 'add iphone_project and mobile group'
[master]: created 8962da8: "changed name"
 1 files changed, 4 insertions(+), 0 deletions(-)
$ git push
Counting objects: 5, done.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 272 bytes, done.
Total 3 (delta 1), reused 0 (delta 0)
To git@gitserver:/opt/git/gitosis-admin.git
   fb27aec..8962da8  master -> master

第一次向新工程 iphone_project 的推送需要在本地的版本中把服务器添加为一个 remote 然后推送。从此手动为新项目在服务器上创建纯仓库的麻烦就是历史了—— Gitosis 会在第一次遇到推送的时候自动创建它们:

$ git remote add origin git@gitserver:iphone_project.git
$ git push origin master
Initialized empty Git repository in /opt/git/iphone_project.git/
Counting objects: 3, done.
Writing objects: 100% (3/3), 230 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@gitserver:iphone_project.git
 * [new branch]      master -> master

注意到路径被忽略了(加上它反而没用),只有一个冒号加项目的名字—— Gitosis 会为你找到项目的位置。

要和朋友们共同在一个项目上共同工作,就得重新添加他们的公钥。不过这次不用在服务器上一个一个手动添加到 ~/.ssh/authorized_keys 文件末端,而是在 keydir 目录为每一个公钥添加一个文件。文件的命名将决定在 gitosis.conf 文件中用户的称呼。现在我们为 John,Josie 和 Jessica 添加公钥:

$ cp /tmp/id_rsa.john.pub keydir/john.pub
$ cp /tmp/id_rsa.josie.pub keydir/josie.pub
$ cp /tmp/id_rsa.jessica.pub keydir/jessica.pub

然后把他们都加进 ‘mobile’ 团队,让他们对 iphone_project 具有读写权限:

[group mobile]
writable = iphone_project
members = scott john josie jessica

如果你提交并推送这个修改,四个用户将同时具有该项目的读写权限。

Gitosis 也具有简单的访问控制功能。如果想让 John 只有读权限,可以这样做:

[group mobile]
writable = iphone_project
members = scott josie jessica

[group mobile_ro]
readonly = iphone_project
members = john

现在 John 可以克隆和获取更新,但 Gitosis 不会允许他向项目推送任何内容。这样的组可以有尽可能有随意多个,每一个包含不同的用户和项目。甚至可以指定某个组为成员,来继承它所有的成员。

如果出现了什么问题,把 loglevel=DEBUG 加入到 [gitosis] 部分或许有帮助(译注:把日志设置到调试级别,记录更详细的信息)。如果你一不小心搞错了配置,失去了推送权限,可以手动修改服务器上的 /home/git/.gitosis 文件—— Gitosis 从该文件读取信息。一次推送会把 gitosis.conf 保存在服务器上。如果你手动编辑该文件,它将在你下次向 gitosis-admin 推送之前它将保持原样。