使用gitolite做git的权限管理

Posted by jintang on 2016-09-10

使用git我们有这样一个场景:

master分支不允许开发人员提交,只允许负责人提交
develop分支允许开发人员提交

git没有做权限控制,这样的权限分配怎么实现呢?这里就要提到gitolite了。

create user git and create ssh-key

1
2
3
4
5
> useradd git
> passwd git
> su - git
> ssh-keygen -t rsa -C git.pub
> # 一直回车,生成的git.pub在~/.ssh/里面

install gitolite

1
2
3
4
5
6
7
8
9
10
11
12
13
> su - git
> mkdir -p ~/bin
> git clone https://github.com/sitaramc/gitolite
# 此时$HOME目录下有一个gitolite文件夹
> gitolite/install -ln ~/bin # please use absolute path here

> cp ~/.ssh/jay.pub /tmp/jay.pub

> ~/bin/gitolite setup -pk /tmp/jay.pub
# 此时会在$HOME下创建了一个repositories文件夹
# 里面有gitolite-admin.git 和 testing.git

# 安装完毕

gitolite管理员配置

添加用户

1
2
3
4
5
6
7
8
9
10
11
12
13
14
> cd ~
> git clone git@localhost:gitolite-admin.git

# 此处克隆了gitolite-admin项目下来,进入gitolite-admin目录
# 有两个文件夹conf和keydir,通过吧.pub文件加入keydir目录里,然后提交,push就可以了
# 添加user jay
> useradd jay && passwd jay
> su - jay
> ssh-keygen -t rsa -C jay.pub
> su - git
> cp /home/jay/.ssh/jay.pub ~/gitolite-admin/keydir
> git add -A
> git commit -m 'add user jay'
> git push origin master

版本库及权限管理

一个范例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
下面我们看一个不那么简单的授权文件:

1 @admin = jiangxin wangsheng
2
3 repo gitolite-admin
4 RW+ = jiangxin
5
6 repo ossxp/.+
7 C = @admin
8 RW = @all
9
10 repo testing
11 RW+ = @admin
12 RW master = junio
13 RW+ pu = junio
14 RW cogito$ = pasky
15 RW bw/ = linus
16 - = somebody
17 RW tmp/ = @all
18 RW refs/tags/v[0-9] = junio
  1. 在上面的示例中,我们演示了很多授权指令。
  2. 第1行,定义了用户组 @admin,包含两个用户 jiangxin 和 wangsheng。
  3. 第3-4行,定义了版本库 gitolite-admin。并指定只有用户 jiangxin 才能够访问,并拥有读(R)写(W)和强制更新(+)的权限。
  4. 第6行,通过正则表达式定义了一组版本库,即在 ossxp/ 目录下的所有版本库。
  5. 第7行,用户组 @admin 中的用户,可以在 ossxp/ 目录下创建版本库。创建版本库的用户,具有对版本库操作的所有权限。
  6. 第8行,所有用户都可以读写 ossxp 目录下的版本库,但不能强制更新。
  7. 第9行开始,定义的 testing 版本库授权使用了引用授权语法。
  8. 第11行,用户组 @admin 对所有的分支和里程碑拥有读写、重置、添加和删除的授权。
  9. 第12行,用户 junio 可以读写 master 分支。(还包括名字以 master 开头的其他分支,如果有的话)。
  10. 第13行,用户 junio 可以读写、强制更新、创建以及删除 pu 开头的分支。
  11. 第14行,用户 pasky 可以读写 cogito 分支。 (仅此分支,精确匹配)。

踩过的坑

当我们搭建好gitolite后,是需要添加用户进去,但是如果我们不添加用户,直接把.pub文件内容放到git的.ssh/authorized_keys里面。如:

1
> ssh-copy-id [-p 22898] git@gitserver

此时也能直接免密码使用gitolite版本库repositories中的仓库。

我们git clone命令将会是这样的:

1
2
> #假设repositiories目录所在地位:/home/git/repositories
> git clone ssh://git@gitserver:/home/git/repositories/testing.git

这样是能正常克隆项目下来,但是当执行push操作的时候,会报如下错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@izwz994ghq89x8naebwhg1z gitolite-admin]# git push origin master
git@localhost's password:
Counting objects: 6, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 350 bytes | 0 bytes/s, done.
Total 4 (delta 0), reused 0 (delta 0)
remote: Empty compile time value given to use lib at hooks/update line 6.
remote: Use of uninitialized value in require at hooks/update line 7.
remote: Can't locate Gitolite/Hooks/Update.pm in @INC (@INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .) at hooks/update line 7.
remote: BEGIN failed--compilation aborted at hooks/update line 7.
remote: error: hook declined to update refs/heads/master
To ssh://git@localhost:22898/home/git/repositories/gitolite-admin.git
! [remote rejected] master -> master (hook declined)
error: failed to push some refs to 'ssh://git@localhost:/home/git/repositories/gitolite-admin.git'

这个问题在网上很少有人解决了。在此记录一下解决方法

注意事项:
  1. 当添加用户后,gitolite会自动在创建者(如git)的主目录下的.ssh/authorized_keys里面,添加如下一段代码:

    1
    2
    3
    4
    # gitolite start
    command="/home/git/bin/gitolite-shell git",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDYz9J0faTZljmvBqJLcYkQKQ4o6RqdmMBitqrwcq6Q2yEy+7eTZe9znw9Ck58lqWGSSBSJtntnxIpTW2dH8bxmyjTwap/HVkyJb+B/WYMh7IsNuldlZPHNUzD1v8KfrmZ121jrIs+8BL3g+G18sUy7dfvtNx0gBZxHN7zBetMvtL9uH6YIZVcZKu4NKBFT8Y+cOmZJH0/9K5yyI4ZKnqfBzUo5Iyp+j8m25GNoMeYZVa1Uc8YfPtJhPeuzyDPbipd82FNeJ6TOHOQGhVsaGGtOny/5wQsTOrr+J3+FojtbUkDcQijxunFXImChze9Y+gQ80zSJZsSOL3vOnXiLb6cp git@localhost.localdomain
    command="/home/git/bin/gitolite-shell jay",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC2Iw4uv8l+WCRX47GzJOCzR9ZkppvqfhPaRSfIaDxC5cSukJ7zZ7oNwl+WPX6rDIBlO7KBBsZzXzWDB46H3VzM484/OSK3tRDaWFgQYwcBDtxtl0DkvMl9eitOiLTqacc9WMjyAiNsXj4iklul2GU3bw/aIdinMKNKcwJPsPenVElVhLyynVumKDnlJ0Hz8CfiMbbJazb/BIzrD7aISLwVBzibjbb9n2Oryc6n8VlNmsxSbUVSC+/LU46sfNT54z2SgYE6gysEOr8tVG6mjzF7tIzAnptbeeqFiTv1hJ78JK5AYoMmh38Ronf7t2GqYAm+TgxMLDi8ggbxDuTpndcP jay@jay-PC
    # gitolite end
  2. 只有添加到gitolite的用户才能实施权限的配置

  3. 添加到gitolite的用户,可以是用简约的远端目录地址,如:
    1
    2
    3
    4
    5
    > # 原来的ssh://的完整地址
    > git clone ssh://git@gitserver:/home/git/repositories/testing.git
    > # 简约地址
    > git clone git@gitserver:testing.git
    > # 其实就是用户添加进去了,访问的时候就会把repositories当作默认目录
分析原因:

出现此错误,主要是我们的没有把自己添加用户到gitolite-admin/keydir里面,而remote远端地址使用完整目录home/git/repositories/gitolite-admin.git,导致hook脚本执行的时候找不到环境路径

解决方法:

把你添加到gitolite用户里面,修改远端地址为简约地址

步骤如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
> #本地生成id_rsa.pub文件
> ssh-keygen -t rsa -C jay
>
> # 然后一直回车,生成的id_rsa.pub文件在~/.ssh/里面,拷贝到服务器的gitolite-admin/keydir里面
>
> # 服务器操作
> cd ~/gitolite-admin
> git add .
> git commit -m '添加用户jay'
> git push origin master
> #添加用户完毕
>
> #回到本地目录,修改远端地址
> git remote set-url origin git@gitserver:testing.git

解决完毕

小技巧

使用git配置的host方式

当如果我们的git服务器不是以22为默认端口,此时远端地址必须带上端口号,如:

ssh协议的远端地址:

1
> git clone ssh://git@gitserver:22898/home/git/repositories/testing.git

如果使用gitolite简约地址,是无法识别端口号的,错误示例如下:

1
> git clone git@gitserver:22898:testing.git

解决此问题可以使用git的host方式, 步骤:

首先,配置~/.ssh/config

1
2
3
4
5
6
7
> su - git
> vim ~/.ssh/config
> #内容如下
> host gtls
> hostname localhost
> port 22898
> wq

修改remote url:

1
2
3
> cd ~/gitolite-admin
> git remote set-url origin git@gtls:gitolite-admin.git
> git push origin master

gitolite的版本库位置

当我们搭建好gitolite后,会生成repositories目录,此目录是gitolite可以管控的仓库目录,目前我为发现可以修改此目录的方法。所以我们只能把所用开发仓库都放在此目录下进行管控,但是如果我们已经有gitcode目录了,移动过去也不方便,会导致开发人员修改本地的远端地址,麻烦。

此时我们可以使用linux的软链接来帮助我们。

1
2
3
> # 假设我们有项目仓库地址:/data/gitcode/test.git
> cd ~/repositories
> ln -s /data/gitcode/test.git test.git