Gitfed
bastien-mrq/gitfed / docs / HOW_IT_WORKS.md
HOW_IT_WORKS.md Code Preview

Langues : Français · English

Comment fonctionne gitfed

Ce document explique le mécanisme central de gitfed : comment deux instances qui ne se connaissent pas peuvent laisser leurs utilisateurs collaborer sans qu'aucun compte ne soit jamais partagé entre elles. Pour le contexte plus large (fichiers, code, déploiement), voir le README ; pour le détail de chaque paquet Go, voir ARCHITECTURE.md ; pour le mode d'emploi pratique (mettre en place une vraie collaboration fédérée étape par étape), voir ../FEDERATION.md.


1. Le problème que ça résout

Sur GitHub ou GitLab, collaborer avec quelqu'un suppose soit que vous ayez tous les deux un compte sur la même plateforme, soit que l'un des deux migre. gitfed part d'un principe différent, plus proche du mail ou d'ActivityPub : chaque personne a un compte sur une seule instance — la sienne — et cette instance peut prouver son identité auprès de n'importe quelle autre instance qui accepte de lui faire confiance.

Concrètement : alice a un compte sur chez-moi.fr. Bob a un compte sur ailleurs.net. Bob peut pousser du code sur un dépôt d'alice sans jamais créer de compte chez elle — à condition que l'instance d'alice ait choisi de faire confiance à l'instance de Bob.

2. L'identité : un certificat plutôt qu'un mot de passe partagé

Chaque instance gitfed génère, à sa création, sa propre autorité de certification (une paire de clés ed25519, stockée sur le volume de données). C'est le socle de tout le modèle :

  1. Un utilisateur local enregistre une clé SSH publique auprès de son instance (via gitfed-tui pour le tout premier compte, ou en autonomie ensuite dans Paramètres → Clés SSH).
  2. Quand il en a besoin, il demande à son instance un certificat (ssh git@instance gitfed-cert, ou via l'outil gitfed-renew-cert en tâche planifiée). L'instance vérifie que la clé lui appartient bien, puis signe un certificat SSH au format OpenSSH.
  3. Ce certificat embarque un principal — bob@ailleurs.net, jamais un simple nom d'utilisateur seul — et une durée de validité courte, 24 heures par défaut.
  4. Quand Bob se connecte à l'instance d'alice, il présente ce certificat au lieu de sa clé nue. L'instance d'alice vérifie deux choses : que la signature du certificat correspond bien à une autorité en laquelle elle a confiance, et que ce certificat n'a pas été révoqué (§6).

Aucune de ces deux instances n'a besoin de contacter l'autre en direct pour cette vérification — la signature suffit, un peu comme un passeport n'a pas besoin d'un appel téléphonique au pays émetteur pour être vérifié à la frontière, tant qu'on connaît la clé publique de l'autorité qui l'a délivré.

3. La confiance entre instances : le magasin de confiance

Faire confiance à une autorité, ça se construit. La première fois que l'instance d'alice croise le domaine ailleurs.net (typiquement parce qu'alice a accordé un accès à bob@ailleurs.net sur un de ses dépôts), elle déclenche une découverte fédérée :

  1. Elle récupère https://ailleurs.net/.well-known/gitfed.json, un document public qui contient la clé publique de l'autorité de certification de cette instance.
  2. Elle vérifie que ce document est cohérent (le domaine déclaré correspond bien, une clé est présente) et que la requête ne pointe pas vers une adresse interne ou privée (protection anti-SSRF : IP littérales, 127.0.0.0/8, 10.0.0.0/8, 169.254.0.0/16/métadonnées cloud, etc. sont toutes refusées, y compris après résolution DNS).
  3. Selon la politique configurée sur l'instance d'alice :
    • liste blanche (par défaut) — le domaine est enregistré comme en attente ; un administrateur doit l'approuver explicitement dans Administration → Confiance fédérée avant que le moindre accès ne soit accordé.
    • auto-confiance (TOFU — "trust on first use") — le domaine est approuvé immédiatement à la première découverte, à activer uniquement si on accepte ce niveau de risque.
  4. La découverte est limitée à 10 nouveaux domaines par minute pour toute l'instance, pour empêcher qu'un compte compromis ne s'en serve comme sonde réseau à grande échelle.

Une fois un domaine approuvé, la vérification d'un certificat qui en provient est entièrement locale : aucune requête réseau n'est refaite à chaque git push.

4. L'autorisation : qui peut faire quoi sur quel dépôt

L'identité fédérée dit qui on est ; elle ne dit rien de ce qu'on a le droit de faire. Ça, c'est le rôle du modèle d'ACL, entièrement local à chaque dépôt :

  • Chaque dépôt a un propriétaire (toujours admin) et, optionnellement, des collaborateurs, chacun avec un rôle explicite : lecture, écriture, ou admin.
  • Un dépôt est en plus public ou privé. Un dépôt public accorde la lecture à n'importe quel principal authentifié, de n'importe quelle instance de confiance, sans qu'il soit besoin de l'ajouter comme collaborateur. L'écriture n'est en revanche jamais implicite — même sur un dépôt public, il faut un rôle explicite pour pousser du code.
  • Octroyer un accès à un principal sur un domaine encore inconnu de l'instance est justement ce qui déclenche la découverte fédérée décrite au §3.

5. Le cycle complet, étape par étape

Reprenons l'exemple : alice veut donner à Bob un accès en écriture sur alice/mon-projet.

  1. Sur l'instance d'alice — alice va dans les paramètres du dépôt et accorde le rôle écriture à bob@ailleurs.net.
  2. Si ailleurs.net est un domaine encore inconnu, l'instance d'alice déclenche la découverte (§3) et le domaine reste en attente tant qu'un admin ne l'a pas approuvé.
  3. Sur l'instance de Bob — Bob demande un certificat à sa propre instance (gitfed-cert ou renouvellement automatique). Son instance signe un certificat portant le principal bob@ailleurs.net.
  4. Bob exécute git push ssh://git@chez-moi.fr:2222/alice/mon-projet.git, en s'authentifiant avec son certificat.
  5. L'instance d'alice vérifie la signature du certificat contre la clé d'autorité qu'elle a approuvée pour ailleurs.net, vérifie qu'il n'est pas révoqué, puis vérifie dans son ACL locale que bob@ailleurs.net a bien le rôle écriture sur alice/mon-projet.
  6. Si tout est en ordre, git-receive-pack s'exécute normalement, exactement comme pour un utilisateur local.

À aucun moment Bob n'a eu besoin d'un compte, d'un mot de passe ou d'une clé enregistrée chez alice.

6. Expiration et révocation

Un certificat de 24 h qui traîne après la suppression d'un compte reste, en théorie, un accès résiduel. gitfed traite ça de deux façons complémentaires :

  • Le TTL est court (24 h par défaut, configurable) — la fenêtre d'exposition d'une clé compromise est bornée même sans action de l'administrateur.
  • La révocation est immédiate. Supprimer un utilisateur ou retirer une de ses clés SSH enregistre la révocation correspondante (par principal et/ou par empreinte de clé) ; chaque authentification SSH consulte cette liste avant d'accepter un certificat, même s'il est encore cryptographiquement valide.

7. Ce qui n'est pas fédéré

Pour être clair sur les limites du modèle : un dépôt vit sur une seule instance. Il n'y a ni réplication, ni miroir automatique entre instances. La fédération ne concerne que l'identité — qui a le droit de pousser ou de lire — jamais les données elles-mêmes. Si l'instance d'alice tombe, son dépôt n'est disponible nulle part ailleurs tant qu'il n'a pas été cloné en dehors.

8. Cas particulier : cloner un dépôt public sans compte

Tout ce qui précède décrit l'accès authentifié — nécessaire pour tout dépôt privé, et pour toute écriture, même sur un dépôt public. Mais un dépôt public peut aussi être cloné en HTTPS, sans certificat, sans clé SSH, sans compte du tout :

git clone https://chez-moi.fr/alice/mon-projet.git

C'est strictement un raccourci de lecture, pas une deuxième voie d'authentification : aucune écriture n'est possible par ce chemin (il n'y a pas de route git-receive-pack en HTTP, littéralement aucune), et un dépôt qui redevient privé cesse instantanément d'être accessible ainsi. Voir ARCHITECTURE.md §7 pour le détail d'implémentation.

9. Cas particulier : fusionner une branche depuis le web

Les merge requests permettent à un collaborateur en écriture de fusionner une branche dans une autre depuis l'interface web — une « écriture » qui ne passe pas par SSH, ce qui ressemble à une deuxième exception au modèle d'identité du §2. Ça n'en est pas une : le navigateur n'envoie jamais de donnée git, il dit seulement au serveur de combiner deux branches qu'il a déjà, et chaque commit que l'une ou l'autre pointe n'est arrivé dans le dépôt que via un vrai push authentifié par SSH au départ. L'accès passe par exactement le même contrôle de rôle en écriture qu'un git push traverse déjà — le bouton web n'ouvre aucune capacité qu'un collaborateur en écriture n'aurait pas déjà en clonant, fusionnant en local, puis en repoussant. Voir ARCHITECTURE.md §8 pour comment la fusion elle-même est isolée de l'état réel d'une branche (worktree jetable, détection de conflit avant toute écriture, mise à jour de ref en compare-and-swap).