Git via HTTP avec identification sur un hébergement mutualisé

Alexandre Lacoche 9 novembre 2011 7
Git via HTTP avec identification sur un hébergement mutualisé

Git est le digne successeur de subversion, c’est indéniable, surtout à en juger par le succès de GitHub. L’une des clés de la popularisation de GitHub est certainement la simplicité de la mise en place d’un dépôt.

Certains hébergements mutualisés intègrent GIT, à l’image de 1and1. Concrètement, vous pouvez héberger sur votre espace web votre propre dépôt git. Traditionnellement, l’accès aux dépôts se fait via SSH. Les plus avertis d’entre vous voient déjà où je veux en venir : comment travailler à plusieurs si on a qu’un seul accès au dépôt ? En effet, rares (d’ailleurs en existe-t-il ?) sont les hébergeurs qui autorisent la création d’utilisateurs pour accéder à votre hébergement mutualisé via SSH, et comme vous n’êtes pas super prêteurs, vous ne souhaitez pas donnez à vos collaborateurs vos propres accès SSH. De plus, si tous vos utilisateurs utilisent votre accès vous perdez toute possibilité de suivre qui fait quoi dans le projet (on passera également l’évident problème de sécurité et autres joyeusetés de ce genre).

Donc pour résumer : un serveur avec GIT, plusieurs utilisateurs, un seul accès, dommage… Ou pas ! En effet, votre hébergement contient peut-être git-http-backend, qui permet d’exécuter les commandes GIT via HTTP. Du coup, avec un petit htaccess super bien fait (et 2 ou 3 autres choses…), vous verrez on va faire des miracles. En cerise sur la gâteau, on va même afficher vos dépôts via une interface web. Enfin, la chantilly entre le gâteau et la cerise, le tout sera accessible à la même adresse et de façon transparente pour vos utilisateurs.

Attention tout de même, il y a quelques limitations :

  1. je n’ai pas encore exploré le moyen de restreindre les accès par utilisateur et par dépôt (donc tous vos utilisateurs pourront accéder en lecture/écriture à tous vos dépôts) Mise à jour du 11/11/2011 : cette limitation n’est plus, on peut gérer simplement les accès par utilisateur, voir la dernière section
  2. pour la première limitation, on pourrait se dire « tant pis je vais mettre des noms indevinables à mes dépôts afin d’éviter qu’ils y accèdent simplement », mais malheureusement l’interface web affiche en page d’accueil la liste de tous les projets que vous lui précisez
  3. si vous faites un push avec de gros fichiers, ça ne fonctionnera pas, il doit y avoir un timeout et je n’ai pas encore cherché à résoudre ce problème (donc pour les gros fichiers, un push par ssh est obligatoire). Pour les plus avertis d’entre vous, ma config de http.lowSpeedTimeOut est pourtant vide…

Je pense que tout est dis, y a plus qu’à… Vous aurez besoin de :

  • un hébergement mutualisé avec git (ceci a été testé sur un hébergement mutualisé 1and1)
  • un nom de domaine rien que pour git, c’est plus beau (je vais utiliser par la suite git.exemple.fr, à vous de prendre soin de remplacer par votre nom de domaine)
  • un petit café

Préparatifs

  1. créez un dossier sur votre serveur qui contiendra vos dépôts et l’interface web (pour ma part je prendrai ~/git), puis allez dedans
    mkdir ~/git && cd ~/git
  2. dans l'espace d'administration de votre hébergement, faites pointer le votre nom de domaine (git.exemple.fr) sur le dossier fraîchement créé
  3. téléchargez l'interface web viewgit (notez bien qu'à l'heure ou cet article est écrit la versions de viewgit est la 0.0.5) ici : forge de viewgit, décompressez-le puis mettez dans le répertoire ~/git avec pour nom view (oui je sais avec sourceforge on ne peut pas faire de wget, c'est casse pied..)
  4. téléchargez également Geshi (afin d'avoir la coloration syntaxique dans viewgit) ici : forge de Geshi, décompressez-le puis mettez-le dans le répertoire ~/git/view/inc
  5. sur votre serveur, créez des dépôts GIT publics de test (je vous laisse vous promener dans les sites sources en bas pour plus d'explication sur les commandes suivantes) :
    mkdir test.git
    cd test.git
    git init --bare
    touch git-daemon-export-ok
    git --bare update-server-info
    cd ..
    mkdir test2.git
    cd test2.git
    git init --bare
    touch git-daemon-export-ok
    git --bare update-server-info
    cd ..

Configuration de viewgit

Maintenant que tout est prêt, nous allons configurer viewgit :

  1. préparation du fichier de config :

    cd view && touch inc/localconfig.php

  2. édition du fichier de config (attention, on utilise vi, mais vous êtes libre d'utiliser ce que vous voulez), on va seulement configurer les dépôts, vous jouerez seul avec les autres options :
    vi inc/localconfig.php

    Puis ajoutez ceci :

    <?php
    /** @file
     * Example localconfig.php. See config.php for more information.
     */
    // This is the only mandatory setting
    $conf['projects'] = array(
            'Test' => array('repo' => '../../git/test.git/'),
            'Test 2' => array('repo' => '../../git/test2.git/'),
    );
    $conf['geshi'] = true;
    $conf['geshi_path'] = 'inc/geshi/geshi.php';
    // A bit sorter datetime format: YY-MM-DD HH:MM
    $conf['datetime'] = '%d-%m-%y %H:%M';
    // Extra security
    $conf['allow_checkout'] = false;
  3. à chaque fois que vous ajouterez un dépôt, n'oubliez pas d'aller le préciser dans le fichier inc/localconfig.php

Voilà, l'interface web est maintenant prête.

Commandes GIT

Nous avons donc maintenant la partie qui va afficher nos dépôts, il nous faut maintenant pouvoir nous servir de ces dépôts via HTTP. Git intègre un binaire, gitt-http-backend, qui permet d'exécuter les commandes en utilisant une connexion via HTTP. git-http-backend utilisant certaines variables, nous devons créer un script cash qui sera appelé lors des requêtes. Créez donc le fichier ~/git/git.cgi, et mettez-y ceci dedans (attention, la variable GIT_PROJECT_ROOT doit contenir le chemin absolu vers le répertoire ~/git, pas relatif, pour le connaitre, allez dans le dossier ~/git et tapez la commande pwd) :

#!/bin/bash
# Quelques variables :
export GIT_PROJECT_ROOT=/chemin/absolu/vers/le/repertoire/git/
export GIT_HTTP_EXPORT_ALL
export REMOTE_USER=$REDIRECT_REMOTE_USER
# On exécute le backend :
/usr/lib/git-core/git-http-backend

Utilisateurs

Nos utilisateurs vont être gérés par htaccess. Nous allons donc créer un fichier .git-htpassword qui contiendra le nom de nos utilisateurs ainsi que leurs mots de passe. Ce fichier ne doit pas être dans le dossier ~/git, nous le mettrons dans le home (pour des raisons évidentes de sécurité, si votre home correspond à un espace web, ne le mettez pas là, ce fichier ne doit pas être dans un espace accessible sur le web) :

cd && touch .git-htpassword

Il ne nous reste plus qu'à ajouter nos utilisateurs :

htpasswd .git-htpassword nom_utilisateur

Je vous laisse regarder dans le man de htpasswd pour modifier et supprimer vos utilisateurs.

Bonnes routes

Donc on récapitule : on a l'interface web, le script à appeler pour les requêtes GIT et nos utilisateurs, il ne reste plus qu'à renvoyer les bonnes requêtes au bon endroit (car je vous le rappelle, tout va circuler via HTTP, donc pour le moment il ne se passe pas grand chose : si vous faites un clone ça ne fonctionne pas, et en vous rendant sur git.exemple.fr, il ne se passe pas grand chose non plus...).

Pour que la magie opère, il suffit de mettre un fichier .htaccess avec les bonnes règles dedans. Créez donc le fichier .htaccess dans ~/git/ et mettez-lui ceci dedans (attention mettez bien le chemin absolu vers le fichier .git-htpassword dans AuthUserFile, pas le relatif) :

# On precise l'execution des CGI, on acceptes les connexions :
Options +ExecCgi +FollowSymLinks
Order allow,deny
Allow from all
# On gere l'autentification
AuthType Basic
AuthName "Mes depots GIT"
AuthUserFile /chemin/absolu/vers/.git-htpassword
Require valid-user
# On active l'URL rewriting
RewriteEngine On
RewriteBase /
# On redirige les commandes git sur git.cgi :
RewriteRule ^([a-zA-Z0-9._]+\.git/.*)$ /git.cgi/$1 [L]
# Ou pour les plus pointilleux :
#RewriteRule ^([a-zA-Z0-9._]+\.git/(HEAD|info/refs|objects/(info/[^/]+|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\.(pack|idx))|git-(upload|receive)-pack))$ /git.cgi/$1 [L]
# Le reste sur view :
RewriteCond %{REQUEST_URI} !^.+\.git
RewriteCond %{REQUEST_URI} !^/view/
RewriteRule .* /view/ [L,R=301]

Gérer les utilisateurs par projet

Voici la petite mise à jour de 11/11/11, afin de restreindre l'accès par utilisateur. Malheureusement cette petite avancée ne change pas le fonctionnement de viewgit, celui-ci affichera tous les projets quoi qu'il arrive. Donc si vous avez plusieurs utilisateurs, le plus simple est pour l'instant de ne pas permettre l'affichage via viewgit.

Je vais considérer que vous avez créé trois utilisateurs dans le .git-htpassword : ut1, ut2 et ut3.

Les groupes

Pour une gestion simple des utilisateurs, on va les regrouper. Créez le fichier .git-htgroup (comme le fichier .git-htpassword, vous pouvez le mettre où vous voulez mais évitez de le mettre dans un dossier accessible depuis internet) :

cd && touch .git-htgroup

Le contenu des fichiers htgroup est assez simple : sur chaque ligne vous inscrivez le nom du groupe, ": ", et le nom des utilisateurs séparés par un espace. Voici pour notre exemple :

groupe1: ut1 ut2
groupe1-readonly: ut3
groupe2: ut1 ut3

Voilà, notre fichier groupe est maintenant créé avec les utilisateurs dans les groupes que l'on désir. Il faut maintenant préciser que c'est ce fichier là que l'on va utiliser dans le dossier ~/git pour gérer nos utilisateurs. Changez-donc le fichier ~/git/.htaccess pour qu'il ressemble à ceci :

# On precise l'execution des CGI, on acceptes les connexions :
Options +ExecCgi +FollowSymLinks
Order allow,deny
Allow from all
# On gere l'autentification
AuthType Basic
AuthName "Mes depots GIT"
AuthUserFile /chemin/absolu/vers/.git-htpassword
AuthGroupFile /chemin/absolu/vers/.git-htgroup
Require valid-user
# On active l'URL rewriting
RewriteEngine On
RewriteBase /
# On redirige les commandes git sur git.cgi :
RewriteRule ^([a-zA-Z0-9._]+\.git/.*)$ /git.cgi/$1 [L]
# Ou pour les plus pointilleux :
#RewriteRule ^([a-zA-Z0-9._]+\.git/(HEAD|info/refs|objects/(info/[^/]+|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\.(pack|idx))|git-(upload|receive)-pack))$ /git.cgi/$1 [L]
# Le reste sur view :
RewriteCond %{REQUEST_URI} !^.+\.git
RewriteCond %{REQUEST_URI} !^/view/
RewriteRule .* /view/ [L,R=301]

Voilà tout est prêt, il ne reste plus qu'à limiter l'accès à nos dépôts aux groupes.

Limiter l'accès aux dépôts

Pour limiter l'accès dans chaque dépôt, il suffit d'ajouter un fichier .htaccess très simple dans chacun des dépôts. Vous savez (si si je vous l'assure) qu'Apache lit les .htaccess de façon descendante, donc que les règles de ~/git/.htacess seront encore valable dans ~/git/test.git. Ainsi, nulle besoin de repréciser tous les liens vers .git-htpassword etc dans le dossier ~/git/test.git. Donc au final, pour limiter l'accès aux personnes de groupe1 à test.git, créez le fichier ~/git/test.git/.htaccess mettez ceci dedans :

<Limit GET PUT POST DELETE PROPPATCH MKCOL COPY MOVE LOCK UNLOCK>
     Require group groupe1
</Limit>

Et voilà, vous pouvez tester et vous apercevoir que ut3 ne peut pas cloner (ou toute autre opération) test.git.

Et si finalement vous voulez que ut3 puisse juste cloner et puller test.git, mettez ceci dans le .htaccess de test.git :

<Limit GET>
     Require group groupe1-readonly
</Limit>
<Limit GET PUT POST DELETE PROPPATCH MKCOL COPY MOVE LOCK UNLOCK>
     Require group groupe1
</Limit>

Le mot de la fin

Voilà, tout est maintenant fin prêt : vous pouvez aller consulter vos dépôts en vous rendant sur http://git.exemple.fr dans votre navigateur, mais également faire des clone/push et autres joyeusetés gitesques via http://git.exemple.fr, le tout en étant identifié. Vous pouvez par exemple taper ceci sur votre machine et constater que tout fonctionne bien (du moins je l'espère) :

git clone http://git.exemple.fr/test.git
cd test
touch README
git add README
git commit -m "Pour un test"
git push
cd ..
rm -rf test/

Je vous laisse supprimer les 2 dépôts test et test 2, après avoir fait vos tests avec (sans oublier de modifier le fichier localconfig.php de viewgit).

Have fnu coding!

Références

7 Commentaires »

  1. Darlot 4 janvier 2012 au 0 h 26 min - Reply

    Cool ton post, il faudra que j’essaie.
    Pour ton problème de gros fichier est lié la configuration de ton server HTTP. Même si le protocole HTTP ne limite pas la taille de transfert d’un fichier, la plupart des serveurs http ont une limite par défaut.
    Pour plus d’info voir : http://stackoverflow.com/questions/461282/what-is-the-maximum-file-size-i-can-transfer-using-http-and-using-ftp

    • Pierre CLÉMENT 5 janvier 2012 au 11 h 10 min - Reply

      Merci ;)
      Merci aussi pour l’info, je dois avouer que je me doutais de quelque chose dans le genre, mais ce n’était que des suspicions sans preuves à l’appuie et je n’ai pas vraiment eu le temps (et la présence d’esprit) de m’y pencher :D
      Je trouve ça quand même dommage que git ne découpe pas l’envoi en petits morceaux qu’il enverrait au serveur (à l’image de plupload, qui n’a rien à voir certes, mais qui découpe les fichiers en chunks et les envois au serveur).

  2. Gui 20 août 2012 au 21 h 36 min - Reply

    Post très cool :)

    Cependant ça ne fonctionne pas chez moi… j’ai soit une erreur « 500 while accessing http://monurl.com/test.git/info/refs« , soit un « Invalid Hash » quand j’essaye depuis la console

    J’aurais oublié quelquechose (je suis chez 1and1 aussi)

    • aegar 4 octobre 2012 au 21 h 56 min - Reply

      Très pratique comme tuto, ça marche pour moi.
      J’ai eu la même erreur 500 que j’ai résolue en changeant les permissions de git.cgi sur 711.

  3. vince 4 octobre 2012 au 18 h 37 min - Reply

    Il y a un petit bug de balise je pense ^^

  4. Rémy 6 février 2013 au 17 h 18 min - Reply

    Salut,
    Quelqu’un a t-il trouvé une solution concernant le problème de hash et d’erreur 500 ?
    Merci ;)

  5. Fred 24 octobre 2013 au 0 h 15 min - Reply

    Bonsoir,
    Merci pour ce super tuto, j’ai maintenant mon repository GIT sur 1and1.
    j’ai du faire un chmod sur le répertoire git pour éviter les erreurs 500

    Je n’ai pas eu de soucis de hash..

    Pour le test de push final il faut plus de paramètres :
    git push origin master

    Et tout roule…

Laissez un message »