Організація розрахованого на багато користувачів доступу на сервер 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) директорії проектів

dir1(proj1:proj1,0770)
dir2(proj2:proj2,0770)
dir3(proj3:proj3,0770)
...
де
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, ця схема є надійною. Окрім цього, схема дуже легко адмініструється.

Перейдемо до практики.

Створення Git репозиторіїв на сервері Linux

Перевіряємо.

[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 репозиторію та push на 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>

У цей же час на сервері утворюються нові файли, і вони належать користувачу, який провів push

[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 (зміна основної групи користувача-розробника не допоможе, оскільки як працювати над кількома проектами?). У такому випадку, користувач dev2 не зможе змінювати файли, створені користувачем dev1, а це може призвести до порушення функціональності.

Linux chown - Зміна власника файлу звичайним користувачем

Власник файлу не може змінювати його належність. Але він може змінити групу файлу, який йому належить, і тоді цей файл може бути доступним для зміни іншим користувачам, які знаходяться у цій групі. Це те що нам потрібно.

Використання Git hook

Робочою директорією для hook є коренева директорія проекту. hook є файлом, який виконується під користувачем, який робить push. знаючи це, ми можемо здійснити задумане.

[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 find інвертувати умову пошуку
  • як у Linux shell передати в цикл кілька рядків через однострочник
  • як у bash екранувати поодинокі лапки
  • як у командному рядку windows видалити директорію з усім вмістом
  • Як за допомогою bash mv перейменувати файл, не переписуючи його заново

Дякую за увагу.

Джерело: habr.com

Додати коментар або відгук