组织多用户访问GIT服务器

安装和配置 Git 服务器时,会出现有关组织多个用户对多个项目的访问的问题。 我研究了这个问题并找到了一个满足我所有要求的解决方案:简单、安全、可靠。

我的愿望是:

  • 每个用户都连接自己的帐户
  • 多个用户可以处理一个项目
  • 同一用户可以处理多个项目
  • 每个用户只能访问他所从事的项目
  • 应该可以通过命令行连接,而不仅仅是通过某种网络界面

这也很棒:

  • 向控制人员授予只读权限
  • 方便地管理Git中的用户访问权限

访问 GIT 服务器的可能选项概述

首先,您需要知道要选择什么,因此这里是 Git 协议的快速概述。

  • ssh - 专门创建的用户帐户用于访问服务器。
    • 奇怪的是,Git 并没有将使用一个帐户访问所有存储库的建议排除在外。 这根本不符合我的要求。
    • 您可以使用多个帐户,但如何限制用户只能访问某些目录?
      • 关闭主目录是不合适的,因为很难为其他用户组织写访问
      • 使用主目录中的符号链接也很困难,因为 Git 不会将它们解释为链接
      • 可以限制对解释器的访问,但不能完全保证它始终有效
        • 您通常可以为此类用户连接自己的命令解释器,但是
          • 首先,这已经是一个艰难的决定,
          • 其次,这是可以规避的。

    但也许用户能够执行任何命令都不是问题?.. 一般来说,如果你弄清楚如何使用它,就不能排除这种方法。 我们稍后会回到这个方法,但现在我们将简要考虑其他替代方案,也许会有更简单的方法。

  • git local协议可以和sshfs结合使用,可以使用多个用户,但本质上和前面的情况是一样的
  • http - 只读
  • git 是只读的
  • https - 很难安装,你需要额外的软件,某种控制面板来组织用户访问......它看起来可行,但不知何故一切都很复杂。

使用ssh协议组织多用户访问Git服务器

让我们回到 ssh 协议。

由于你使用ssh访问git,所以需要保证服务器数据的安全。 通过 ssh 连接的用户在 Linux 服务器上使用自己的登录名,因此他们可以通过 ssh 客户端连接并访问服务器的命令行。
没有针对此类访问的完整保护。

但用户不应该对 Linux 文件感兴趣。 重要信息仅存储在 git 存储库中。 因此,可以不通过命令行限制访问,而是使用Linux工具禁止用户查看项目,不包括他参与的项目。
显而易见的选择是使用 Linux 权限系统。

正如已经提到的,可以仅使用一个帐户进行 ssh 访问。 尽管此配置包含在推荐的 git 选项列表中,但对于某些用户来说是不安全的。

为了实现本文开头给出的要求,创建了以下目录结构并分配了权限和所有者:

1)项目目录

目录1(项目1:项目1,0770,XNUMX)
目录2(项目2:项目2,0770,XNUMX)
目录3(项目3:项目3,0770,XNUMX)
...
哪里
dir1、dir2、dir3 - 项目目录:项目 1、项目 2、项目 3。

proj1:proj1、proj2:proj2、proj3:proj3 是专门创建的 Linux 用户,他们被指定为相应项目目录的所有者。

所有目录的权限都设置为 0770 - 所有者及其组的完全访问权限,以及其他所有人的完全禁止权限。

2)开发者账户

Разработчик 1: dev1:dev1,proj1,proj2
Разработчик 2: dev2:dev2,proj2,proj3

关键是开发人员被分配了一个额外的组,即相应项目的系统用户所有者。 这是由 Linux 服务器管理员通过一个命令完成的。

在此示例中,“开发人员 1”正在处理项目 proj1 和 proj2,“开发人员 2”正在处理项目 proj2 和 proj3。

如果任何开发人员通过命令行通过 ssh 连接,那么他们的权限甚至不足以查看他们不参与的项目目录的内容。 他自己无法改变这一点。

由于这一原则的基础是Linux权限的基本安全,因此该方案是可靠的。 此外,该计划非常易于管理。

让我们继续练习吧。

在 Linux 服务器上创建 Git 存储库

我们检查。

[root@server ~]# cd /var/
[root@server var]# useradd gitowner
[root@server var]# mkdir gitservertest
[root@server var]# chown gitowner:gitowner gitservertest
[root@server var]# adduser proj1
[root@server var]# adduser proj2
[root@server var]# adduser proj3
[root@server var]# adduser dev1
[root@server var]# adduser dev2
[root@server var]# passwd dev1
[root@server var]# passwd dev2

我厌倦了用手打字...

[root@server gitservertest]# sed "s/ /n/g" <<< "proj1 proj2 proj3" | while read u; do mkdir $u; chown $u:$u $u; chmod 0770 $u; done

[root@server gitservertest]# usermod -aG proj1 dev1
[root@server gitservertest]# usermod -aG proj2 dev1
[root@server gitservertest]# usermod -aG proj2 dev2
[root@server gitservertest]# usermod -aG proj3 dev2

我们确信从命令行访问其他人的存储库甚至查看其内容是不可能的。

[dev1@server ~]$ cd /var/gitservertest/proj3
-bash: cd: /var/gitservertest/proj3: Permission denied
[dev1@server ~]$ ls /var/gitservertest/proj3
ls: cannot open directory /var/gitservertest/proj3: Permission denied

在 Git 中与同一项目的多个开发人员协作

仍然存在一个问题,如果一个开发人员引入了一个新文件,那么其他开发人员无法更改它,因为他本人是该文件的所有者(例如 dev1),而不是该项目的用户所有者(例如 proj1)。 由于我们有服务器端存储库,首先我们需要知道“.git”目录是如何构造的以及是否创建了新文件。

创建本地Git仓库并推送到Git服务器

让我们继续讨论客户端计算机。

Microsoft Windows [Version 6.1.7601]
(c) Корпорация Майкрософт (Microsoft Corp.), 2009. Все права защищены.

C:gittest>git init .
Initialized empty Git repository in C:/gittest/.git/

C:gittest>echo "test dev1 to proj2" > test1.txt

C:gittest>git add .

C:gittest>git status
On branch master
No commits yet
Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   test1.txt

C:gittest>git commit -am "new test file added"
[master (root-commit) a7ac614] new test file added
 1 file changed, 1 insertion(+)
 create mode 100644 test1.txt
 
C:gittest>git remote add origin "ssh://[email protected]/var/gitservertest/proj2"

C:gittest>git push origin master
dev1:[email protected]'s password:
Counting objects: 3, done.
Writing objects: 100% (3/3), 243 bytes | 243.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To ssh://10.1.1.11/var/gitservertest/proj2
 * [new branch]      master -> master

C:gittest>

同时,服务器上会创建新文件,这些文件属于执行推送的用户

[dev1@server proj2]$ tree
.
├── 1.txt
├── branches
├── config
├── description
├── HEAD
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── prepare-commit-msg.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   └── update.sample
├── info
│   └── exclude
├── objects
│   ├── 75
│   │   └── dcd269e04852ce2f683b9eb41ecd6030c8c841
│   ├── a7
│   │   └── ac6148611e69b9a074f59a80f356e1e0c8be67
│   ├── f0
│   │   └── 82ea1186a491cd063925d0c2c4f1c056e32ac3
│   ├── info
│   └── pack
└── refs
    ├── heads
    │   └── master
    └── tags

12 directories, 18 files
[dev1@server proj2]$ ls -l objects/75/dcd269e04852ce2f683b9eb41ecd6030c8c841
-r--r--r--. 1 dev1 dev1 54 Jun 20 14:34 objects/75/dcd269e04852ce2f683b9eb41ecd6030c8c841
[dev1@server proj2]$

当您将更改上传到 Git 服务器时,会创建其他文件和目录,它们的所有者实际上是进行上传的用户。 但那么这些文件和目录的组也对应了这个用户的主组,即dev1用户的dev1组和dev2用户的dev2组(更改developer用户的主组没有帮助,因为那么你怎么能同时进行多个项目呢?)。 在这种情况下,用户 dev2 将无法更改用户 dev1 创建的文件,这可能会导致功能崩溃。

Linux chown - 由普通用户更改文件的所有者

文件的所有者无法更改其所有权。 但他可以更改属于他的文件的组,然后该文件可以被同一组中的其他用户修改。 这就是我们所需要的。

使用 Git 挂钩

hook的工作目录是项目的根目录。 hook 是一个可执行文件,在执行推送的用户下运行。 知道了这一点,我们就可以实施我们的计划。

[dev1@server proj2]$ mv hooks/post-update{.sample,}
[dev1@server proj2]$ sed -i '2,$ s/^/#/' hooks/post-update
[dev1@server proj2]$ cat <<< 'find . -group $(whoami) -exec chgrp proj2 '"'"'{}'"'"' ;' >> hooks/post-update

要么只是

vi hooks/post-update

让我们回到客户端机器。

C:gittest>echo "dev1 3rd line" >> test1.txt

C:gittest>git commit -am "3rd from dev1, testing server hook"
[master b045e22] 3rd from dev1, testing server hook
 1 file changed, 1 insertion(+)

C:gittest>git push origin master
dev1:[email protected]'s password:
   d22c66e..b045e22  master -> master

在Git服务器上,我们检查提交后hook post-update脚本的运行情况

[dev1@server proj2]$ find . ! -group proj2

——空空如也,一切都好。

在 Git 中连接第二个开发人员

让我们模拟第二个开发人员的工作。

在客户端上

C:gittest>git remote remove origin

C:gittest>git remote add origin "ssh://[email protected]/var/gitservertest/proj2"

C:gittest>echo "!!! dev2 added this" >> test1.txt

C:gittest>echo "!!! dev2 wrote" > test2.txt

C:gittest>git add test2.txt

C:gittest>git commit -am "dev2 added to test1 and created test2"
[master 55d49a6] dev2 added to test1 and created test2
 2 files changed, 2 insertions(+)
 create mode 100644 test2.txt

C:gittest>git push origin master
[email protected]'s password:
   b045e22..55d49a6  master -> master

而与此同时,服务器上……

[dev1@server proj2]$ find . ! -group proj2

——又空了,一切正常。

删除Git项目并从Git服务器下载项目

好吧,您可以再次确保所有更改均已保存。

C:gittest>rd /S /Q .
Процесс не может получить доступ к файлу, так как этот файл занят другим процессом.

— 要删除 Git 项目,只需完全清除目录即可。 让我们忍受生成的错误,因为不可能使用此命令删除当前目录,但这正是我们需要的行为。

C:gittest>dir
 Содержимое папки C:gittest

21.06.2019  08:43    <DIR>          .
21.06.2019  08:43    <DIR>          ..

C:gittest>git clone ssh://[email protected]/var/gitservertest/proj2
Cloning into 'proj2'...
[email protected]'s password:

C:gittest>cd proj2

C:gittestproj2>dir
 Содержимое папки C:gittestproj2

21.06.2019  08:46    <DIR>          .
21.06.2019  08:46    <DIR>          ..
21.06.2019  08:46               114 test1.txt
21.06.2019  08:46                19 test2.txt
C:gittestproj2>type test1.txt
"test dev1 to proj2"
"dev1 added some omre"
"dev1 3rd line"
"!!! dev2 added this"

C:gittestproj2>type test2.txt
"!!! dev2 wrote"

在 Git 中共享访问

现在让我们确保即使通过 Git,第二个开发人员也无法访问他没有参与的 Proj1 项目。

C:gittestproj2>git remote remove origin

C:gittestproj2>git remote add origin "ssh://[email protected]/var/gitservertest/proj1"

C:gittestproj2>git push origin master
[email protected]'s password:
fatal: '/var/gitservertest/proj1' does not appear to be a git repository
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

现在我们允许访问

[root@server ~]# usermod -aG proj1 dev2

之后一切正常。

C:gittestproj2>git push origin master
[email protected]'s password:
To ssh://10.1.1.11/var/gitservertest/proj1
 * [new branch]      master -> master

欲了解更多信息,

另外,如果创建文件和目录时默认权限出现问题,在CentOS中可以使用命令

setfacl -Rd -m o::5 -m g::7 /var/gitservertest

另外,在本文中,您可能会偶然发现一些有用的小东西:

  • 如何在Linux中建立目录树
  • 如何在sed中传递从某一行到文件末尾的一系列地址,即在sed中除第一行之外的所有行中进行替换
  • 如何在 Linux 查找中反转搜索条件
  • 如何在 Linux shell 中使用单行将多行传递到循环中
  • 如何在 bash 中转义单引号
  • 如何在Windows命令行中删除目录及其所有内容
  • 如何使用 bash mv 重命名文件而不需要再次重写

感谢您的关注。

来源: habr.com

添加评论