Il y a plusieurs raisons pour vouloir disposer d’un hébergement Git. Les trois principales sont :
- disposer d’un backup distant de son travail,
- mettre son travail à la disposition d’autrui,
- collaborer avec d’autres sur un projet.
Hébergement public ou privé ?
Lorsque le projet est libre, ou qu’en tout cas son contenu est public, le plus simple consiste à exploiter un bon service d’hébergement Git qui serait gratuit pour les dépôts publics. Dans ce domaine, l’acteur désormais incontournable (et particulièrement bien foutu) est le célèbre GitHub.
En revanche, pour les dépôts privés, soit on reste sur GitHub, mais dès lors, c’est payant (pas cher ceci dit : à partir de $9/mois, ce qui permet de bénéficier de l’infrastructure massive du service, notamment en termes de fiabilité de stockage). Soit on crée son propre hébergement Git, ce qui a notamment l’intérêt éventuel de le rendre interne à sa société (et donc, potentiellement, très rapide d’accès sur un réseau local performant).
Ce billet vise à explorer en détail l’option technique favorite pour héberger son propre serveur Git : Gitosis.
Quand on connaît la procédure, récupérer, installer et configurer Git, qu’on soit sur OSX ou Linux, est l’affaire de 10 à 15 minutes. En lisant ce billet et les explications, ce sera naturellement un peu plus long. Mais ça reste rapide et facile !
Principes de fonctionnement de Gitosis
Comme GitHub, Gitosis base sa gestion d’accès sur le protocole SSH et des clés asymétriques.
Chaque utilisateur reconnu par le système est identifié au moyen d’une paire de clés asymétriques dont le serveur connaît la partie publique : côté client, il faut donc disposer de la clé privée correspondante dans son « portefeuille de clés » SSH. Un même utilisateur logique dans Gitosis peut être associé à un nombre quelconque de clés (par exemple une depuis sa machine au boulot, une depuis son laptop, une par compte sur un serveur où du code est déployé…).
C’est à mon sens une excellente façon de procéder. En effet, révoquer l’accès peut se faire de façon très granulaire si on utilise une clé par couple Utilisateur + Machine : il devient alors possible de révoquer les accès depuis une machine quelconque, ou pour un utilisateur à travers toutes les machines, ou pour un cas Utilisateur + Machine précis.
Un autre aspect de Gitosis que j’aime particulièrement est que toute sa configuration est dans un… dépôt Git, ce qui fait qu’on la met à jour avec un git push. C’est délicieusement récursif, j’adore !
Installer le serveur
Allez, c’est parti, on va se coller un p’tit Gitosis perso.
Récupérer les dépendances éventuelles
Déjà, il vous faut Git. Mais si vous lisez ce blog, je suppose que vous l’avez déjà…
Il faut aussi Python et son module setup-tools. Sur OSX on a déjà l’équivalent, mais sur un Linux il faudra installer le paquet correspondant. Par exemple, sur Debian/Ubuntu :
1
| |
À partir de là, on récupère Gitosis depuis son dépôt et procéder à l’installation :
1 2 3 4 | |
Cette installation nous fournit une série de binaires (programmes) pour Gitosis, au premier rang desquels gitosis-serve, qui va servir de « shell » à l’utilisateur système git que nous allons créer. Ce binaire fournit toutes les fonctions du serveur Git, ainsi que le mécanisme d’authentification, de gestion des droits, etc.
Créer et configurer l’utilisateur « git »
Vous avez sans doute déjà remarqué que les URLs « lecture-écriture » d’un dépôt distant Git sont généralement de la forme git@le-serveur.tld:le-depot.git (ou plus rarement ssh://git@le-serveur.tld:le-depot.git, ce qui revient au même). La convention veut en effet qu’on configure un utilisateur système git sur le serveur, seul moyen d’accéder au serveur Git.
Cet utilisateur n’a pas de mot de passe, mais au lieu de fournir un shell classique (ce qui, vu le manque de mot de passe frontal, serait assez dangereux…), il exécute uniquement votre serveur Git, lequel se charge alors de l’authentification.
En revanche, le home directory (répertoire personnel) de ce compte constituera le dossier racine de vos dépôts Git sur le serveur. Du coup, plutôt que d’utiliser la convention usuelle (/home/login sur Linux, /Users/login sur OSX), on aura tendance à préciser un dossier plus conforme à ce type d’usage, typiquement /var/lib/git. Vous pouvez en fait mettre ce que vous voulez, mais je précise le raisonnement ici histoire que vous ne soyez pas surpris dans les lignes de commande qui vont suivre.
Il nous faut donc configurer cet utilisateur. C’est là que la procédure diverge entre les Linux (qui ont tous les binaires système adduser et/ou useradd) et OSX (dont la gestion des utilisateurs repose directement sur son mécanisme d’annuaire, c’est-à-dire sa couche LDAP).
Commençons par la version Linux. Selon la commande que vous voulez employer, les options ne sont pas exactement les mêmes. Voici les deux variantes :
1 2 | |
ou
1 2 | |
Passons rapidement en revue la signification de ces arguments :
--systemprécise qu’il s’agit d’un utilisateur système : entre autres choses, son home directory ne sera pas initialisé avec les squelettes (fichiers initiaux d’un compte, présents en général dans/etc/skel).--shellprécise le shell par défaut de l’utilisateur. Vu que l’accès SSH sur ce compte ne l’exploitera pas, ce n’est pas une source de danger, en revanche il peut être pratique de disposer d’un shell pour une authentification locale (avecsuousudo -i) histoire de triturer le compte sous son identité directe en cas de besoin majeur.--gecosou--commentfournissent le descriptif utilisateur qui sera associé dans l’annuaire des comptes locaux.--groupou--user-groupspécifie que le seul groupe qui doit être associé à l’utilisateur est son groupe propre : il ne fera partie d’aucun des groupes utilisateurs par défaut qui pourraient être configurés sur le système, et n’aura donc pas d’accès indû à certains programmes ou emplacements du système de fichiers.--disabled-passwordindique que le compte n’a pas de mot de passe associé (vu qu’il n’est pas conçu pour faire l’objet d’une authentification). Dansuseradd, qui n’est pas une commande interactive, le simple fait de ne pas passer de mot de passe dans les arguments a le même effet.--homeou--home-dirfournit le home directory du compte.- On termine avec le nom du compte :
git
La commande crée automatiquement le home directory et lui affecte les bons propriétaire et groupe. Ce ne sera pas le cas sous OSX, où on se contente de manipuler l’annuaire, ce qui n’impacte jamais le reste du système de fichiers. Voyons justement comment procéder :
1 2 3 4 5 6 7 8 | |
Le binaire dscl (Directory Services Command Line) est l’interface en ligne de commande fournie par OSX pour manipuler son annuaire interne. Il nous faut d’abord créer le groupe, puis l’utilisateur à proprement parler. Attention, vous ne pouvez pas regrouper les dscl . create dans une seule et même commande, comme on pourrait être tenté de le déduire de la documentation pour cette commande : il est impératif que chaque couple clé+valeur ait sa propre commande.
Notez comme on termine en créant explicitement le home directory et en calant son propriétaire et son groupe.
Sur un OSX classique, les identifiants groupe et utilisateur 405 sont normalement libres. Vous pouvez toutefois le vérifier en amont avec les commandes suivantes, et si besoin prendre d’autres IDs qui, eux, seraient libres (ils n’ont pas besoin d’être identiques, mais c’est plus conventionnel) :
1 2 | |
Un petit détour au pays des clés…
Il nous faut à présenter définir comment cet utilisateur va se comporter en cas de connexion SSH utilisant son compte. Le boulot correspondant, ainsi que l’initialisation finale de Gitosis, sont fait par la même commande. Celle-ci a toutefois besoin de votre clé publique SSH afin de vous autoriser, notamment, à manipuler le serveur et le compte Git à votre guise.
Peut-être n’avez-vous pas de clé pour le moment ? Vérifiez avec la commande suivante :
1
| |
Si vous voyez que le répertoire n’existe pas, ou que vous n’y voyez pas de paire de fichiers id_dsa/id_dsa.pub (ou id_rsa/id_rsa.pub), vous n’avez pas encore de clé. Et d’ailleurs, même si vous en avez déjà une, vous voulez peut-être en créer une seconde, spécifique pour votre exploitation de Git.
Pour générer une paire de clés asymétriques, on utilise la commande ssh-keygen. Je vous conseille d’exploiter l’algorithme DSA plutôt que le RSA, utilisé par défaut, qui est un peu moins sécurisé. Le chemin proposé par défaut pour votre clé sera ~/.ssh/id_dsa ; si vous avez déjà une telle clé mais en voulez une supplémentaire, pensez à changer le nom vers quelque chose de plus spécifique (par exemple ~/.ssh/id_dsa_git) pour ne pas écraser la clé existante.
Voici ce que ça donne sur mon OSX Snow Leopard :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | |
turellement, vous n’aurez pas la même empreinte (fingerprint) et donc pas le même randomart ; c’est normal, le contraire serait d’ailleurs inquiétant.)
Utilisez ce que vous voulez comme passphrase pour la clé, mais évitez un truc bateau, encore plus du vide. Inutile de rendre votre clé utilisable par tout le monde…
Une fois la génération terminée, vous devriez voir deux nouvelles clés, la privée et la publique (celle dont le nom finit en .pub) dans votre dossier SSH :
1 2 3 4 5 6 7 8 9 | |
Installer Gitosis à proprement parler
OK, cette parenthèse refermée, nous pouvons lancer la commande d’initialisation de Gitosis :
1
| |
(Si vous voulez utiliser une autre clé publique, ajustez simplement le chemin indiqué)
L’option -H s’assure que la commande gitosis-init (installée tout à l’heure par notre python setup.py install) s’exécutera depuis le home directory de l’utilisateur indiqué par -u git, et non depuis le répertoire courant.
La commande gitosis-init requiert sur son entrée standard la clé publique de l’utilisateur susceptible de triturer le compte manuellement.
Sur OSX, il va aussi nous falloir contourner un problème de PATH (liste des endroits où le système cherche les binaires qu’on lui demande d’exécuter), en ajoutant la commande suivante :
1
| |
De cette façon, on est certain que l’utilisateur git, pour exécuter ses binaires, aura bien tous les bons chemins sous la main. Encore une fois, pas besoin de ça sous Linux : juste OSX.
Ultime étape de l’installation : activer le post-update hook de Gitosis afin que toute mise à jour de configuration soit bien prise en compte :
1
| |
Les serveurs Git proposent en effet tous un mécanisme de hooks (points d’ancrage) qui permet de faire exécuter au serveur une ou plusieurs tâches, de façon automatique, à divers moments. Le post-update hook, équivalent du commit hook de Subversion, est le plus employé, puisqu’il se déclenche après toute mise à jour d’un dépôt sur le serveur, et permet donc, par exemple, de déclencher la suite de tests dans le cadre d’une démarche d’intégration continue, ou encore de signaler le push sur divers canaux (e-mail, messagerie instantanée, IRC…).
Dans le cadre de Gitosis, le post-update hook du dépôt de configuration (gitosis-admin) s’emploie à refléter les changements du dépôt dans la configuration concrète du serveur (notamment en ce qui concerne les utilisateurs, leurs clés, et les dépôts reconnus).
Ce qui nous fait une excellente transition vers la section suivante…
Configurer Gitosis… avec Git
Eh oui, Gitosis se configure en accédant au dépôt pré-installé gitosis-admin. On le récupère comme suit :
1 2 3 | |
(Si vous avez installé Gitosis sur une autre machine que celle où vous faites le git clone, remplacez localhost par le nom ou l’IP du serveur).
Le dépôt est constitué principalement de deux choses :
- Un fichier de configuration
gitosis.conf, qui définit les dépôts, comptes utilisateurs, groupes d’utilisateurs et droits d’accès aux dépôts. - Un répertoire
keydir/contenant, pour chaque nom d’utilisateur présent dansgitosis.conf, un fichier avec le même nom et l’extension.pub, qui liste les clés publiques associées à cet utilisateur.
Définir les utilisateurs
Le fichier de configuration gitosis.conf a une syntaxe très simple, similaire aux bons vieux fichiers .ini. Voici le début de mon gitosis.conf pour la première session des Ateliers Git Attitude :
1 2 3 4 5 6 7 8 9 | |
Notez qu’on peut aussi fournir un accès en lecture seule dans un groupe, en utilisant la clé readonly au lieu de la clé writable. Toutefois, on passe quand même par le protocole SSH, pas par un accès anonyme de type git:// voire http://. Pour ces types d’accès, le mieux est d’utiliser git-daemon, qui est fourni avec Git lui-même. J’en parlerai un de ces jours…
Il existe de multiples façons de définir les dépôts, groupes, utilisateurs et droits. Ma préférence personnelle va au choix qu’on retrouve ci-dessus :
- Définir un
[group]par « groupe de projets » (le nom du groupe est sans importance mais doit être unique) - Y placer le ou les noms des dépôts accessibles en lecture/écriture dans la clé
writable - Y placer le ou les noms des dépôts accessibles en lecture dans la clé
readonly - Y placer le ou les noms des utilisateurs concernés dans la clé
members
Il existe d’autres manières de procéder, mais quoi qu’on fasse, les noms des utilisateurs sont à votre convenance. En effet, ils ne seront jamais utilisés par l’extérieur (notamment dans les URLs de dépôts distants), ce sont des « noms logiques » internes à Gitosis. La seule contrainte, c’est que le fichier recensant les clés publiques associées à un utilisateur soit nommé keydir/nom-logique-utilisateur.pub.
Ainsi, mon dossier keydir/ a l’aspect suivant :
1 2 3 4 5 6 7 8 9 10 11 12 | |
Chaque fichier recense la ou les clés publiques associées au compte, à raison d’une par ligne. Par exemple, keydir/tdd.pub contient la clé publique de mon compte sur mon laptop (je l’ai découpée ici en plusieurs lignes pour qu’elle soit lisible d’entrée sur le blog, mais encore une fois, en temps normal tout serait sur une seule ligne) :
1 2 3 4 5 6 7 8 9 10 | |
Si vous utilisez une clé RSA, vous aurez quelque chose d’un peu plus court, et démarrant par ssh-rsa au lieu de ssh-dss, comme c’est par exemple le cas de Mauriz :
1 2 3 4 5 6 7 | |
Définir des dépôts
Les dépôts sont définis par la simple présence de leur nom dans une clé readonly ou writable. Toutefois, un dépôt qui ne serait présent dans aucun writable ne pourra être rempli par personne et, du coup, ne servirait pas à grand chose…
Test : votre premier dépôt sur Gitosis
OK, calons ensemble le nécessaire à votre premier dépôt distant.
Paramétrer Gitosis
Primo, définissons l’accès. Supposons que votre nom d’utilisateur au sein de Gitosis sera the-boss, et votre dépôt hot-project. Ajoutez les éléments suivants à votre gitosis.conf :
1 2 3 | |
Ensuite, puisque Gitosis ne connaît pas encore votre compte, copiez votre clé publique au bon endroit et ajoutez-la dans l’index :
1 2 | |
Il ne vous reste plus qu’à faire un commit puis un push vers Gitosis :
1 2 3 4 5 6 7 8 9 10 11 12 | |
Le post-update hook fait alors son travail, et votre configuration SSH pour l’utilisateur git est mise à jour. En effet, si vous êtes curieux, vous pouvez jetez un œil au fichier .ssh/authorized_keys de ce compte, et vous y verrez votre utilisateur the-boss et ses réglages dédiés (j’ai ajouté quelques passages à la ligne, et tronqué la clé publique, pour la lisibilité de cet article) :
1 2 3 4 5 | |
C’est grâce à ces lignes que Gitosis sait automatiquement, sur la base des clés privées dont vous disposez et qui correspondent à ses clés publiques recensées, quel utilisateur logique vous êtes et quels traitements SSH vous autoriser. La main passe immédiatement à gitosis-serve (dans un contexte très contrôlé), qui exploite la configuration Gitosis pour les droits d’accès.
Tester le dépôt
Comme toujours avec un dépôt distant, il existe deux cas de figure :
- Vous avez déjà des travaux locaux, qu’il s’agit alors d’envoyer sur le dépôt distant. Dans ce cas, nous allons simplement ajouter un remote et faire un premier push explicite (ainsi qu’une configuration pour pouvoir, par la suite, utiliser des pulls implicites).
- Vous n’avez pas encore de travaux locaux, auquel cas le plus simple est de démarrer avec un clone histoire de paramétrer d’un seul coup le remote, le push et le pull.
Voyons déjà le second cas, qui est le plus simple.
Rien dans les poches : on démarre avec git clone
Il vous suffit en effet de vous placer dans le dossier parent de votre futur dossier projet, et de faire un git clone, exactement comme si vous récupériez un projet existant ; la seule différence, c’est que là, le projet sera vide :
1 2 3 4 5 | |
Notez les deux dernières lignes…
« Initialized empty Git repository in /private/var/lib/git/repositories/hot-project.git/ » (le chemin initial ne sera pas forcément le même, ça dépend du home directory que vous aurez donné à l’utilisateur système git, et sur OSX /var est en fait /private/var) indique que le serveur distant a bien connaissance de ce projet mais n’avait pas encore la moindre donnée pour lui : il a donc initialisé le dépôt distant (pour les curieux, il a juste créé le dossier et y a fait un git init --bare).
Sur la dernière ligne, avec « warning: You appear to have cloned an empty repository. », Git vous prévient que vous venez de cloner un dépôt vide, ce qui n’est pas en soi un problème mais reste une situation suffisamment atypique pour être signalée.
L’avantage de cette méthode, lorsque vous n’avez encore aucun travail local existant, est qu’elle configure d’entrée de jeu le remote et les éléments nécessaires pour faire des git push et git pull implicites (c’est-à-dire n’ayant pas besoin de préciser le remote et la branche). Pour vous en convaincre, jetez un œil à la configuration du projet ainsi clôné :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
Notez la section [remote "origin"], qui définit le remote, et [branch "master"], qui définit la configuration distante de la branche master locale. Grâce à cette dernière section notamment, nous n’avons pas besoin de préciser quel remote et quelle branche distante exploiter pour un push ou un pull : on dit que la branche locale master est configurée pour tracker la branche distante origin/master.
Déjà du boulot en local : remote + push initial explicite + tracking
Bon, ça, c’était le cas simple. Imaginons maintenant que vous aviez déjà du boulot en cours. Simulons ça avec un dépôt local créé vite fait :
1 2 3 4 5 6 7 8 9 10 11 | |
Il nous faut maintenant définir notre premier (et généralement notre seul) remote explicitement. Nous allons garder le nom conventionnel pour le remote principal : origin.
1
| |
À présent, il faut faire un premier push. Faute d’info de tracking résultant d’un clone ou d’une configuration manuelle, nous devons préciser le remote et la branche distante. Il n’y a pas de raison ici (et la plupart du temps) de nommer la distante autrement que la locale, donc on l’appellera aussi master.
1 2 3 4 5 6 | |
On y est presque (et manifestement Gitosis marche très bien). En effet, le tracking n’est pas défini automatiquement par notre push explicite tel que nous l’avons fait :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
Une première approche consisterait à ajouter la configuration correspondante à la main :
1 2 3 4 | |
Je vous montre ça pour des pushes que vous pourriez déjà avoir fait, et où ces réglages pourraient s’avérer utiles. Mais en fait, la meilleure manière dans ces cas-là est d’ajouter une petite option au push explicite : -u (ou sa version longue, --set-upstream). Cette option va réaliser nos configurations pour nous. Essayons en virant le remote et en le rajoutant :
1 2 3 4 5 6 7 | |
Bon, vu qu’on avait déjà fait un push de notre travail local tout-à-l’heure, naturellement au nouveau push, « Everything up-to-date ». En revanche, notez le message « Branch master set up to track remote branch master from origin. », qui montre bien que Git a configuré pour nous le tracking entre branches locale et distante. Et de fait, un pull implicite juste après trouve ses petits.
En conclusion
Voilà, je crois que vous avez désormais toutes les billes pour mettre en place votre propre hébergement Git (et peut-être avez-vous appris au passage une ou deux choses sur la gestion des dépôts distants).
Il est vrai que nous n’avons pas vu comment installer un serveur Git sous Windows, mais au risque de troller, un serveur sous Windows… Soyons sérieux deux minutes ! Plus pragmatiquement, cela est principalement dû au fait que les serveurs Git reposent fortement sur SSH et des configurations avancées d’utilisateurs, toutes choses qui sont ardues à transposer sous Windows, et quand bien même on y arriverait finalement, seraient fortement ralenties par la nécessaire couche intermédiaire basée Cygwin. Sans parler des problématiques de correspondance d’attributs, de gestion de casse MAJ/min et d’horodatage des fichiers entre les univers Linux, OSX et Windows. Du coup, rendez-vous service et si vous hébergez du Git, faites-le sur Linux ou OSX. D’où ce billet.
Les commentaires sont ouverts, aussi n’hésitez pas à me faire part de vos retours, questions et suggestions.
Bon hébergement Git à tous !