Organizzazione dell'accesso multiutente al server GIT

Durante l'installazione e la configurazione di un server Git sorge la domanda sull'organizzazione dell'accesso di più utenti a più progetti. Ho approfondito il problema e ho trovato una soluzione che soddisfaceva tutte le mie esigenze: semplice, sicura, affidabile.

I miei desideri sono:

  • ogni utente si connette con il proprio account
  • Diversi utenti possono lavorare su un progetto
  • lo stesso utente può lavorare su più progetti
  • ogni utente ha accesso solo ai progetti su cui lavora
  • Dovrebbe essere possibile connettersi tramite la riga di comando e non solo tramite una sorta di interfaccia web

Sarebbe anche fantastico:

  • concedere autorizzazioni di sola lettura alle persone che controllano
  • Gestisci comodamente i diritti di accesso degli utenti in Git

Panoramica delle possibili opzioni per l'accesso al server GIT

Prima di tutto devi sapere tra cosa scegliere, quindi ecco una rapida panoramica dei protocolli Git.

  • ssh: per accedere al server viene utilizzato un account utente appositamente creato.
    • È strano che Git non escluda dalle sue raccomandazioni l'utilizzo di un account per accedere a tutti i repository. Questo non soddisfa affatto le mie esigenze.
    • Puoi utilizzare più account, ma come puoi limitare l'accesso degli utenti solo a determinate directory?
      • La chiusura nella directory home non è adatta, perché lì è difficile organizzare l'accesso in scrittura per altri utenti
      • Anche usare i collegamenti simbolici dalla tua home directory è difficile perché Git non li interpreta come collegamenti
      • È possibile limitare l'accesso all'interprete, ma non vi è alcuna garanzia completa che funzioni sempre
        • In genere è possibile collegare il proprio interprete dei comandi per tali utenti, ma
          • in primo luogo, questa è già una sorta di decisione difficile,
          • e in secondo luogo, questo può essere aggirato.

    Ma forse non è un problema che l'utente possa eseguire qualsiasi comando?.. In generale, questo metodo non può essere escluso se si capisce esattamente come usarlo. Torneremo su questo metodo più avanti, ma per ora consideriamo brevemente le altre alternative, forse ci sarà qualcosa di più semplice.

  • Il protocollo locale git può essere utilizzato in combinazione con sshfs, è possibile utilizzare più utenti, ma essenzialmente è uguale al caso precedente
  • http - sola lettura
  • git è di sola lettura
  • https - difficile da installare, è necessario software aggiuntivo, una sorta di pannello di controllo per organizzare l'accesso degli utenti... sembra fattibile, ma in qualche modo è tutto complicato.

Utilizzo del protocollo ssh per organizzare l'accesso multiutente al server Git

Torniamo al protocollo ssh.

Poiché utilizzi l'accesso ssh per git, devi garantire la sicurezza dei dati del server. L'utente che si connette tramite ssh utilizza il proprio login sul server Linux, quindi può connettersi tramite il client ssh e accedere alla riga di comando del server.
Non esiste una protezione completa contro tale accesso.

Ma l'utente non dovrebbe essere interessato ai file Linux. Le informazioni significative sono archiviate solo nel repository git. È quindi possibile non limitare l'accesso tramite riga di comando, ma utilizzando gli strumenti Linux per vietare all'utente di visualizzare i progetti, escludendo quelli a cui partecipa.
La scelta ovvia è utilizzare il sistema di permessi di Linux.

Come già accennato, è possibile utilizzare un solo account per l'accesso ssh. Questa configurazione non è sicura per molti utenti, sebbene sia inclusa nell'elenco delle opzioni git consigliate.

Per attuare quanto prescritto ad inizio articolo viene creata la seguente struttura di directory con assegnazione di diritti e proprietari:

1) directory del progetto

dir1(prog1:proj1,0770)
dir2(prog2:proj2,0770)
dir3(prog3:proj3,0770)
...
dove
dir1, dir2, dir3 - directory del progetto: progetto 1, progetto 2, progetto 3.

proj1:proj1, proj2:proj2, proj3:proj3 sono utenti Linux appositamente creati a cui vengono assegnati come proprietari delle directory di progetto corrispondenti.

i permessi per tutte le directory sono impostati su 0770: accesso completo per il proprietario e il suo gruppo e divieto totale per tutti gli altri.

2) account sviluppatore

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

Il punto chiave è che agli sviluppatori viene assegnato un gruppo aggiuntivo di utenti di sistema proprietari del progetto corrispondente. Questo viene fatto dall'amministratore del server Linux con un comando.

In questo esempio, "Sviluppatore 1" sta lavorando sui progetti proj1 e proj2 e "Sviluppatore 2" sta lavorando sui progetti proj2 e proj3.

Se uno qualsiasi degli sviluppatori si connette tramite ssh tramite la riga di comando, i suoi diritti non saranno sufficienti nemmeno per visualizzare il contenuto delle directory del progetto a cui non partecipa. Non può cambiarlo da solo.

Poiché la base di questo principio è la sicurezza di base dei diritti di Linux, questo schema è affidabile. Inoltre, lo schema è molto semplice da amministrare.

Passiamo alla pratica.

Creazione di repository Git su un server Linux

Controlliamo.

[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

Sono stanco di scriverlo a mano...

[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

Siamo convinti che sia impossibile accedere ai repository di altri dalla riga di comando e persino visualizzarne il contenuto.

[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

Collabora con più sviluppatori sullo stesso progetto in Git

Resta una domanda: se uno sviluppatore introduce un nuovo file, gli altri sviluppatori non potranno modificarlo, perché lui stesso ne è il proprietario (ad esempio dev1) e non l'utente proprietario del progetto (ad esempio proj1). Dato che disponiamo di un repository lato server, dobbiamo prima di tutto sapere come è strutturata la directory “.git” e se vengono creati nuovi file.

Creazione di un repository Git locale e invio al server Git

Passiamo alla macchina client.

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>

Allo stesso tempo, sul server vengono creati nuovi file che appartengono all'utente che ha eseguito il 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]$

Quando carichi modifiche sul server Git, vengono creati file e directory aggiuntivi e il loro proprietario è effettivamente l'utente che effettua il caricamento. Ma poi il gruppo di questi file e directory corrisponde anche al gruppo principale di questo utente, ovvero il gruppo dev1 per l'utente dev1 e il gruppo dev2 per l'utente dev2 (cambiare il gruppo principale dell'utente sviluppatore non aiuterà, perché allora come puoi lavorare su più progetti?). In questo caso, l'utente dev2 non sarà in grado di modificare i file creati dall'utente dev1, il che potrebbe portare a un'interruzione della funzionalità.

Chown Linux: modifica del proprietario di un file da parte di un utente normale

Il proprietario di un file non può modificarne la proprietà. Ma può cambiare il gruppo di un file che gli appartiene, e poi questo file potrà essere modificato da altri utenti che si trovano nello stesso gruppo. Questo è ciò di cui abbiamo bisogno.

Utilizzo dell'hook Git

La directory di lavoro per hook è la directory root del progetto. hook è un eseguibile che viene eseguito sotto l'utente che esegue il push. Sapendo questo, possiamo attuare i nostri piani.

[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

o semplicemente

vi hooks/post-update

Torniamo alla macchina client.

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

Sul server Git, controlliamo il funzionamento dello script hook post-aggiornamento dopo il commit

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

- vuoto, va tutto bene.

Collegamento di un secondo sviluppatore in Git

Simuliamo il lavoro del secondo sviluppatore.

Sul cliente

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

E allo stesso tempo, sul server...

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

— di nuovo vuoto, tutto funziona.

Eliminazione di un progetto Git e download del progetto dal server Git

Bene, puoi assicurarti ancora una volta che tutte le modifiche siano state salvate.

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

— per eliminare un progetto Git, cancella semplicemente completamente la directory. Sopportiamo l'errore che viene generato, poiché è impossibile eliminare la directory corrente utilizzando questo comando, ma questo è esattamente il comportamento di cui abbiamo bisogno.

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"

Condivisione dell'accesso in Git

Adesso assicuriamoci che anche tramite Git il secondo sviluppatore non possa accedere al progetto Proj1, sul quale non sta lavorando.

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.

Ora consentiamo l'accesso

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

e dopo funziona tutto.

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

Per ulteriori informazioni,

Inoltre, se si verifica un problema con le autorizzazioni predefinite durante la creazione di file e directory, in CentOS è possibile utilizzare il comando

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

Inoltre nell'articolo potresti imbatterti in piccole cose utili:

  • come costruire un albero di directory in Linux
  • come passare un intervallo di indirizzi in sed da una determinata riga alla fine del file, ovvero effettuare una sostituzione in sed in tutte le righe tranne la prima riga
  • Come invertire una condizione di ricerca nella ricerca di Linux
  • Come passare più righe in un ciclo utilizzando una riga singola nella shell Linux
  • Come sfuggire alle virgolette singole in bash
  • come eliminare una directory con tutto il suo contenuto nella riga di comando di Windows
  • Come usare bash mv per rinominare un file senza riscriverlo di nuovo

Grazie per la vostra attenzione.

Fonte: habr.com

Aggiungi un commento