Ma vie sans GitHub - partie 1: Gitolite🔗

Posted by Médéric Ribreux 🗓 In blog/ Code/

#debian #security #sysadmin #git #code #dev

Introduction

Il y a quelque temps, j'ai décidé de quitter Github, en fermant mon compte. Après tout, ça va dans le sens de mes convictions. Pour l'instant, ça me va très bien, mais je reconnais que ce n'est pas très pratique pour travailler sur des projets de logiciels libres.

L'acquisition de Github par Microsoft et le fait qu'on trouve maintenant des millions de projets de logiciels libres, tous centralisés sur Github pose clairement la question du risque de tout mettre ses yeux dans le même panier. Que se passe-t-il si Github devient trop puissant et impose ses conditions ?

Néanmoins, nous sommes en 2018 et ne pas utiliser des outils modernes pour partager du code impose de revenir en arrière et d'exclure certaines bonnes pratiques. Aussi, je me devais de trouver un système adapté à mes moyens et à mes ambitions pour partager le code source libre qu'il m'arrive de produire.

Cet article tente d'améliorer l'aspect partage des choses en présentant une installation de gitolite, un logiciel de référence pour gérer les droits d'accès à des dépôts Git.

Principes de Gitolite

Avant d'utiliser un logiciel, c'est bien de savoir comment il fonctionne, du moins dans ses grandes lignes.

Installation de gitolite sous Debian

Vous devez disposer d'une clef publique SSH pour le compte "administrateur" de gitolite. Pour ma part, j'y fous ma clef publique de GNUPG au format ssh-rsa que j'obtiens avec la commande gpg (voir ci-dessous).

Ensuite, vous pouvez installer le paquet Debian gitolite3. Ce dernier vous demandera où placer le répertoire spécifique à gitolite. Pour ma part, je le place dans /var/local/gitolite.

$ gpg --export-ssh-key mon_compte_gpg > medspx.pub
$ scp medspx.pub compte@srv.example.org:/tmp/
# apt install gitolite3
- clef SSH de l'administrateur: `/tmp/medspx.pub`
# mv /var/lib/gitolite3 /var/local/gitolite
# usermod --home /var/local/gitolite gitolite3

Voilà, c'est fait…

Après installation du paquet, debconf créé un utilisateur dédié. Il se nomme gitolite3 et a pour HOME le répertoire d'installation de gitolite que vous avez renseigné en amont.

Ce répertoire contient tout ce que j'ai expliqué dans les principes de gitolite sous la forme suivante:

Utiliser gitolite

Maintenant que gitolite est installé, il convient de l'utiliser et de commencer à le configurer correctement.

Tout commence par le clonage du dépôt gitolite-admin. Vous pouvez le cloner en utilisant le compte dédié gitolite (donc gitolite3 sous Debian). Comme vous avez renseigné votre clef SSH, vous avez le droit d'y avoir accès. Un simple clone via SSH donne la commande suivante:

git clone gitolite3@srv.example.org:gitolite-admin

Le dépôt contient deux répertoires:

Ajouter un utilisateur est assez simple: il suffit de récupérer sa clef publique dans un fichier avec le nom du compte suffixé avec l'extension .pub dans le répertoire keydir, de commiter le dépôt et de pousser la modification pour que la clef soit ajustée.

Pour gérer les droits des dépôts, il suffit de modifier le fichier de configuration: conf/gitolite.conf. Sa syntaxe est assez simple à comprendre même si elle peut se complexifier avec des includes et d'autres éléments.

Néanmoins, il y a un élément que vous devez bien noter ! Vous devez toujours utiliser le compte SSH de l'utilisateur gitolite (donc gitolite3 sous Debian). En effet, SSH n'est pas automagique: il ne va pas créer un compte utilisateur POSIX à la volée pour vous permettre de vous connecter. Au contraire, c'est l'utilisateur gitolite3 qui, avec son shell spécial (le binaire de gitolite), va s'occuper de faire la gestion des droits. C'est bien noté ?

Import de dépôts existants

Pour ma part, j'ai beaucoup de dépôts sur mon serveur et il convient de les référencer/importer sous Gitolite. La doc sur le sujet est assez bien faîte:

# cd /var/local/gitolite/repositories
# rm -r testing.git
# cp -r ../..git/*.git .
# chown -R gitolite3:gitolite3 *.git
# su gitolite3
$ gitolite compile
$ gitolite setup --hooks-only
$ gitolite trigger POST_COMPILE

Ensuite, il reste à ajouter les dépôts dans le fichier de conf et le tour est joué.

Mise en place de l'accès via HTTP

Ok, maintenant, vous avez un accès à des dépôts git via SSH, de manière sécurisée pour l'authentification et le contrôle d'accès (qui sont deux choses différentes).

Mais bon, vous êtes ambitieux et vous voulez faire cool comme github et utiliser un service en HTTPS ! Et là, c'est le drame: gitolite ne gère pas super bien l'accès HTTP. En effet, gitolite ne gère pas du tout l'authentification mais uniquement le contrôle d'accès. Dans ce que nous avons vu, c'est SSH qui gère l'authentification, gitolite s'occupe du reste.

Pour la partie HTTP, c'est donc Apache qui va s'occuper de l'authentification et transférer ce qui va bien à gitolite. Mais, nous avons un problème majeur: Apache ne sait pas authentifier avec une clef SSH. Ce n'est pas prévu pour, ce n'est pas fait pour ! Il faut donc broder et c'est que nous propose la documentation de gitolite sur le sujet. Je vous invite aussi à lire cet article que j'ai finalement utilisé.

Comme on doit broder, autant le faire intelligemment, c'est à dire en comprenant ce qu'on fait. Nous devons faire les choses suivantes:

D'un point de vue administration système, j'ai choisi d'utiliser au maximum ce qui est fourni par la distribution Debian. Ainsi, tout le système gitolite est géré par l'utilisateur gitolite3. J'aurais pu installer une version indépendante de gitolite, en plus du paquet Debian. C'est ce qui est recommendé dans la documentation sur l'accès HTTPS.

Le fait d'utiliser l'utilisateur gitolite3 via Apache implique d'utiliser le module suexec de ce dernier. Ceci n'est pas sans conséquence pour certains déploiements de sites web car pour le virtualhost, l'utilisateur qui lancera tous les scripts CGI sera maintenant gitolite3 et non www-data. Si vous utilisez cgit, vous serez impacté.

Mise en place du socle HTTP de base

Pour ma part, voici ce que j'ai fait:

# apt install apache2-suexec-pristine
# e2enmod suexec
# mkdir /var/www/bin
# chown gitolite3:gitolite3 bin
#!/bin/bash
#
# Suexec wrapper for gitolite-shell
#

export GIT_PROJECT_ROOT="/var/local/gitolite/repositories"
export GITOLITE_HTTP_HOME="/var/local/gitolite"

exec /usr/share/gitolite3/gitolite-shell
# chown gitolite3:gitolite3 /var/www/bin/gitolite-suexec.sh
# chmod 0700 /var/www/bin/gitolite-suexec.sh
SuexecUserGroup gitolite3 gitolite3
SetEnv GIT_PROJECT_ROOT "/var/local/gitolite/repositories"
ScriptAlias /git/ /var/www/bin/gitolite-suexec.sh/
SetEnv GITOLITE_HTTP_HOME "/var/local/gitolite"
SetEnv GIT_HTTP_EXPORT_ALL
<Location /git>
  AuthType Basic
  AuthBasicProvider file
  AuthName "Git depots Access"
  AuthUserFile /var/local/gitolite/gitolite-http-authuserfile
  Require valid-user
</Location>

Une fois votre serveur Apache redémarré, vous devriez pouvoir accéder à vos dépôts en suivant les règles d'accès de gitolite.

Gestion des mots de passe par les utilisateurs

Dans tous les cas, retenez que vous allez devoir gérer des mots de passe Apache pour vos utilisateurs externes, en plus de leur clef SSH. Bon, je vous rassure, GitHub le fait aussi: vous créez un compte Github puis vous uploadez vos clefs SSH.

A notre niveau, gitolite est plutôt fait pour créer des comptes à partir d'une clef SSH publique. Le processus est plutôt inversé par rapport à Github. Mais pourquoi pas !

Néanmoins, une fois que vos utilisateurs ont une clef SSH référencée dans le système gitolite que vous avez mis en place, ils ont la liberté d'utiliser le binaire gitolite-shell qui fait un peu plus que de servit du git. En effet, gitolite-shell permet de lancer quelques commandes de gestion. Parmi celles-ci, il y en a une qui est très intéressante car elle se nomme htpasswd et sa fonction est de gérer un mot de passe HTTPS pour Apache. Avec un peu de configuration, on peut tout à fait permettre aux utilisateurs de lancer cette commande.

Avant de commencer, il convient de modifier le fichier de configuration globale de gitolite. Ce dernier est situé dans /etc/gitolite3/gitolite.rc.

Vous devez ajouter 'htpasswd' à la liste des commandes autorisées (ENABLED). Ensuite, définissez la variable HTPASSWD_FILE avec le bon nom de fichier associé:

HTPASSWD_FILE => '/var/local/gitolite/gitolite-http-authuserfile',

Voilà, c'est fait.

Pour que vos utilisateurs puissent modifier leur mot de passe HTTP, il leur suffit de faire:

$ ssh gitolite3@sr.example.org htpasswd
Please type in your new htpasswd at the prompt.  You only have to type it once.

NOTE THAT THE PASSWORD WILL BE ECHOED, so please make sure no one is
shoulder-surfing, and make sure you clear your screen as well as
scrollback history after you're done (or close your terminal instance).

new htpasswd:

Et le tour est joué. Retenez bien que vous devrez maintenir deux choses:

Mais, c'est déjà ce que vous faites si vous êtes sous Github !

Accès non authentifiés via HTTP

Pour l'instant, nous n'avons fait que gérer les accès authentifiés via Apache. Il nous reste à permettre l'accès anonyme, sans authentification. Mais je ne vais pas traiter cet accès dans cet article car plein de solutions s'offrent à vous, d'un répertoire distinct pour les dépôts publics à l'utilisation d'un autre logiciel qui réalise l'accès HTTP pour vous (cgit peut le faire par exemple).

Conclusions

Pour résumer, si la mise en place de l'accès SSH via gitolite est assez simple, l'accès via HTTPS se révèle un poil plus complexe et source de compromis. Mais dans l'ensemble ça fonctionne correctement.

Le seul point négatif de gitolite, c'est le fait qu'il soit codé en Perl. Je sais par avance que jamais je ne pourrais me plonger dans le code interne de Gitolite à cause de ce facteur. En dehors de ce point qui m'oblige à faire confiance au développeur de ce logiciel, je dois dire que Gitolite est simple, plutôt robuste et qu'il ne consomme pas beaucoup de ressources.

Néanmoins, la partie HTTP est un poil complexe à gérer et je pense qu'il existe une marge de progrès dans l'application sur ce point. Après tout, l'accès par HTTPS est pratiquement un pré-requis de nos jours si on souhaite favoriser les échanges (surtout derrière des firewalls nazis).