Pro Git 4.7 權限管理器 Gitosis

出自DILA Wiki

把所有用戶的公開金鑰保存在 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 的新節段(section),在這裡羅列手機開發團隊的開發者以及他們需要存取權限的專案。由於 ‘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 不會允許他向專案推送任何內容。這樣的群組你想要建立多少個就可以建立多少個,每一個群組包含不同的用戶和專案。甚至可以指定某個群組為成員(使用 @ 當做 prefix),,來自動繼承它所有的成員。

[group mobile_committers]
members = scott josie jessica

[group mobile]
writable  = iphone_project
members   = @mobile_committers

[group mobile_2]
writable  = another_iphone_project
members   = @mobile_committers john

如果出現了什麼問題,把 loglevel=DEBUG 加入到 [gitosis] 部分或許有幫助(譯注:把日誌設置到調試級別,記錄更詳細的資訊)。如果你一不小心搞錯了配置,失去了推送許可權,可以手動修改伺服器上的 /home/git/.gitosis 檔—— Gitosis 從該檔讀取資訊。一次推送會把 gitosis.conf 保存在伺服器上。如果你手動編輯該檔,它將維持原樣,直到你下次成功向 gitosis-admin 推送資料。