Organización del acceso multiusuario en el servidor GIT

Al instalar y configurar el servidor Git, surge la cuestión de cómo organizar el acceso de varios usuarios a varios proyectos. He investigado el tema y encontré una solución que cumple con todos mis requisitos: simple, segura y confiable.

Mis deseos son los siguientes:

  • cada usuario se conecta con su propia cuenta
  • varios usuarios pueden trabajar en un mismo proyecto
  • el mismo usuario puede trabajar en varios proyectos
  • cada usuario tiene acceso solo a los proyectos en los que está trabajando
  • debe haber opción de conexión a través de la línea de comandos, no solo a través de alguna interfaz web

También sería genial:

  • proporcionar derechos solo de lectura para las personas de control
  • administrar fácilmente los derechos de acceso de los usuarios en Git

Resumen de las posibles opciones de acceso al servidor GIT

Primero que nada, es necesario saber de qué elegir, por lo que aquí hay un breve resumen de los protocolos Git.

  • ssh: se utiliza una cuenta de usuario especialmente creada para acceder al servidor.
    • Es extraño que Git no excluya de sus recomendaciones el uso de una sola cuenta para acceder a todos los repositorios. Esto no satisface mis requisitos.
    • se pueden usar varias cuentas, pero ¿cómo limitar el acceso de un usuario solo a ciertos directorios?
      • Restringir a la carpeta principal no es adecuado porque es complicado organizar el acceso de escritura para otros usuarios allí.
      • Usar enlaces simbólicos desde la carpeta principal también es complicado ya que Git no los interpreta como enlaces.
      • Limitar el acceso al intérprete es posible, pero no hay garantía total de que esto funcione siempre.
        • Se podría conectar un intérprete de comandos propio para esos usuarios, pero,
          • en primer lugar, esta es una solución algo complicada,
          • y en segundo lugar, esto puede ser esquivado.

    Pero, tal vez no sea un problema que el usuario pueda ejecutar cualquier comando . . . En general, no se puede descartar este método, si se logra pensar en cómo usarlo. Volveremos a esta metodología más tarde, pero por ahora, consideremos brevemente las demás alternativas, tal vez haya algo más simple.

  • El protocolo git local puede ser utilizado en combinación con sshfs, se pueden usar múltiples usuarios, pero en esencia, es lo mismo que el caso anterior.
  • http — solo lectura.
  • git — solo lectura.
  • https — es difícil de configurar, necesita software adicional, de alguna manera. panel de control Para organizar el acceso de usuarios... parece factible, pero todo es algo complicado.

Uso del protocolo ssh para organizar el acceso multiusuario al servidor Git.

Volvamos al protocolo ssh.

Dado que se usa acceso por ssh para git, es necesario asegurar la seguridad de los datos del servidor. El usuario que se conecta por ssh utiliza su propio inicio de sesión en. servidor Linux, por lo que puede conectarse a través del cliente ssh y acceder a la línea de comandos del servidor.
No hay protección total contra la obtención de dicho acceso.

Pero para el usuario no deberían interesarle los archivos de Linux. La información significativa se almacena solo en el repositorio git. Por lo tanto, no es necesario restringir el acceso a través de la línea de comandos, pero mediante Linux, se debe prohibir al usuario ver proyectos, excluyendo aquellos en los que participa.
Es obvio utilizar un sistema de permisos de acceso de Linux.

Como ya se mencionó, es posible usar solo una cuenta para el acceso ssh. Esta configuración es insegura para múltiples usuarios, aunque este método esté incluido en la lista de opciones recomendadas por git.

Para cumplir con los requisitos mencionados al principio del artículo, se crea la siguiente estructura de directorios con asignación de permisos y propietarios:

1) directorios de proyectos.

dir1(proj1:proj1,0770)
dir2(proj2:proj2,0770)
dir3(proj3:proj3,0770)
…
donde
dir1, dir2, dir3 — directorios de proyectos: proyecto 1, proyecto 2, proyecto 3.

proj1:proj1, proj2:proj2, proj3:proj3 — usuarios de Linux creados específicamente, que son designados como propietarios de los directorios de los proyectos correspondientes.

Los permisos para todos los directorios se establecen en 0770 — acceso completo para el propietario y su grupo y prohibición total para todos los demás.

2) cuentas de desarrolladores.

Desarrollador 1: dev1:dev1,proj1,proj2.
Desarrollador 2: dev2:dev2,proj2,proj3.

El punto clave es que a los desarrolladores se les asigna un grupo adicional del usuario del sistema propietario del proyecto correspondiente. Esto lo realiza el administrador del servidor Linux con un solo comando.

En este ejemplo, 'Desarrollador 1' trabaja en el proyecto proj1 y proj2, mientras que 'Desarrollador 2' trabaja en los proyectos proj2 y proj3.

Si cualquiera de los Desarrolladores se conecta por ssh a través de la línea de comandos, sus permisos serán insuficientes incluso para ver el contenido de los directorios de los proyectos en los que no participa. No podrá cambiar esto por sí mismo.

Dado que la base de este principio es la seguridad básica de los permisos de Linux, este esquema es confiable. Además, el esquema es muy fácil de administrar.

Pasemos a la práctica.

Creación de repositorios Git en un servidor Linux

Verificando.

[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

estoy cansado de escribir 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

Nos aseguramos de que desde la línea de comandos no se pueda acceder a los repositorios ajenos ni siquiera ver su contenido.

[dev1@server ~]$ cd /var/gitservertest/proj3
-bash: cd: /var/gitservertest/proj3: Permiso denegado
[dev1@server ~]$ ls /var/gitservertest/proj3
ls: no se puede abrir el directorio /var/gitservertest/proj3: Permiso denegado

Colaboración en Git de varios desarrolladores en un mismo proyecto

Queda una pregunta: si un desarrollador añade un nuevo archivo, los demás desarrolladores no pueden modificarlo, porque él mismo es su propietario (por ejemplo, dev1), y no el usuario propietario del proyecto (por ejemplo, proj1). Dado que tenemos un repositorio en el servidor, es fundamental entender cómo está estructurado el directorio '.git' y si se crean nuevos archivos.

Creación de un repositorio Git local y push a un servidor Git

Pasemos a la máquina cliente.

Microsoft Windows [Version 6.1.7601]
(c) Corporación Microsoft, 2009. Todos los derechos reservados.

C:gittest>git init .
Repositorio Git vacío inicializado en C: /gittest / .git / 

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

C:gittest>git add .

C:gittest>git status
En la rama master
No hay commits aún
Cambios para ser confirmados:
  (usa "git rm --cached <archivo>..." para deshacer el staging)
        nuevo archivo:   test1.txt

C:gittest>git commit -am "nuevo archivo de prueba agregado"
[master (root-commit) a7ac614] nuevo archivo de prueba agregado
 1 archivo cambiado, 1 inserción(+)
 modo de creación 100644 test1.txt
 
C:gittest>git remote add origin "ssh://dev1@10.1.1.11/var/gitservertest/proj2"

C:gittest>git push origin master
dev1:dev1@10.1.1.11's password:
Contando objetos: 3, completo.
Escribiendo objetos: 100% (3/3), 243 bytes | 243.00 KiB/s, completo.
Total 3 (delta 0), reutilizado 0 (delta 0)
Para ssh://10.1.1.11/var/gitservertest/proj2
 * [nueva rama]      master -> master

C:gittest>

Al mismo tiempo, se crean nuevos archivos en el servidor, y pertenecen al usuario que realizó el 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 directorios, 18 archivos
[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]$

Al subir cambios al servidor, Git crea archivos y directorios adicionales, y su propietario es efectivamente el usuario que realiza la carga. Sin embargo, el grupo de esos archivos y directorios también corresponde al grupo principal de ese usuario, es decir, el grupo dev1 para el usuario dev1 y el grupo dev2 para el usuario dev2 (cambiar el grupo principal del usuario desarrollador no ayudará, ya que ¿cómo podrá trabajar en varios proyectos?). En este caso, el usuario dev2 no podrá modificar los archivos creados por el usuario dev1, lo que podría causar problemas de funcionalidad.

Linux chown — cambiar el propietario del archivo como usuario normal.

El propietario del archivo no puede cambiar su pertenencia. Pero puede cambiar el grupo del archivo al que pertenece, y entonces ese archivo puede ser accesible para la modificación por otros usuarios que estén en el mismo grupo. Eso es lo que necesitamos.

Uso de Git hook

El directorio de trabajo para el hook es el directorio raíz del proyecto. El hook es un archivo ejecutable que se ejecuta bajo el usuario que realiza el push. Sabiendo esto, podemos llevar a cabo lo planeado.

[dev1@server proj2]$ mv hooks/post-update{.sample,}
[dev1@server proj2]$ sed -i '2,$ s/^/#/' hooks/post-update
[dev1@server proj2]$ cat <<> hooks/post-update

o simplemente

vi hooks/post-update

Volvamos a la máquina del cliente.

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:dev1@10.1.1.11's password:
   d22c66e..b045e22  master -> master

En el servidor Git, comprobamos el funcionamiento del script hook post-update después del commit.

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

— vacío, todo está bien.

Conexión del segundo desarrollador en Git

Simularemos el trabajo del segundo desarrollador.

En el cliente

C:gittest>git remote remove origin

C:gittest>git remote add origin "ssh://dev2@10.1.1.11/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
dev2@10.1.1.11's password:
   b045e22..55d49a6  master -> master

Y al mismo tiempo, en el servidor...

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

— otra vez vacío, todo funciona.

Eliminación de un proyecto Git y carga del proyecto desde el servidor Git

Bueno, podemos verificar una vez más que todos los cambios se han guardado.

C:gittest>rd /S /Q .
El proceso no puede acceder al archivo porque este archivo está ocupado por otro proceso.

— para eliminar el proyecto Git, simplemente limpiamos completamente el directorio. Aceptamos el error dado, ya que no se puede eliminar el directorio actual con este comando, pero precisamente eso es el comportamiento que necesitamos.

C:gittest>dir
 Contenido de la carpeta C:gittest

21.06.2019  08:43              .
21.06.2019  08:43              ..

C:gittest>git clone ssh://dev2@10.1.1.11/var/gitservertest/proj2
Clonando en 'proj2'...
dev2@10.1.1.11's password:

C:gittest>cd proj2

C:gittestproj2>dir
 Contenido de la carpeta C:gittestproj2

21.06.2019  08:46              .
21.06.2019  08:46              ..
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"

División de acceso en Git

Ahora nos aseguraremos de que, incluso a través de Git, el segundo desarrollador no pueda acceder al proyecto Proj1, sobre el cual no está trabajando.

C:gittestproj2>git remote remove origin

C:gittestproj2>git remote add origin "ssh://dev2@10.1.1.11/var/gitservertest/proj1"

C:gittestproj2>git push origin master
dev2@10.1.1.11's password:
fatal: '/var/gitservertest/proj1' no parece ser un repositorio git
fatal: No se pudo leer del repositorio remoto.

Por favor, asegúrese de tener los derechos de acceso correctos
y de que el repositorio existe.

Ahora permitimos el acceso

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

y después de eso todo funciona.

C:gittestproj2>git push origin master
dev2@10.1.1.11's password:
Para ssh://10.1.1.11/var/gitservertest/proj1
 * [nueva rama]      master -> master

Información adicional

Además, si hay un problema con los derechos predeterminados al crear archivos y directorios, en CentOS se puede utilizar el comando

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

También en el artículo puedes encontrar pequeñas cosas útiles:

  • cómo construir un árbol de directorios en Linux
  • cómo en sed pasar un rango de direcciones desde una línea específica hasta el final del archivo, es decir, hacer en sed un reemplazo en todas las líneas excepto en la primera línea
  • Cómo invertir la condición de búsqueda en find de Linux
  • cómo pasar varias líneas a un bucle en el shell de Linux a través de una línea única
  • cómo escapar comillas simples en bash
  • cómo eliminar un directorio con todo su contenido desde la línea de comandos de Windows
  • Cómo renombrar un archivo con mv en bash sin sobrescribirlo

Gracias por su atención.

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster