Le rôle de la passerelle
Un assistant de code pourrait appeler le fournisseur de modèles directement
depuis le poste du développeur. C’est le chemin le plus court, et Lemniscate ne
le prend pas : les requêtes passent par llm-gateway, un service que vous
déployez dans votre périmètre.
Ce détour coûte un composant à exploiter. Voici ce qu’il achète.
Le poste ne détient pas la clé du fournisseur
Section intitulée « Le poste ne détient pas la clé du fournisseur »C’est la raison principale, et elle est structurelle.
Un appel direct suppose que la clé du fournisseur soit posée sur chaque poste : dans un fichier de configuration, une variable d’environnement, un trousseau. À partir de là, elle est copiable, elle part avec le portable, et elle survit au départ de la personne. La révoquer veut dire la révoquer partout à la fois.
Avec la passerelle, le développeur détient une clé qui lui est propre et qui
ne vaut que contre votre passerelle. Au moment de relayer, la passerelle retire
les crédentiels de l’appelant des en-têtes — authorization et x-api-key —
puis pose à la place la clé du fournisseur, lue dans son propre environnement.
Le poste ne voit jamais cette clé, et rien de ce qui part du poste ne permet de
la reconstituer.
La clé du fournisseur n’est pas non plus en base. La base enregistre le nom de la variable d’environnement qui la porte et l’en-tête HTTP dans lequel la déposer ; la valeur reste dans l’environnement du processus. Une copie de la base ne livre donc aucune clé de fournisseur — et une variable absente produit une erreur 500 qui nomme la variable manquante, plutôt qu’un échec opaque.
Côté comptes, la base ne garde qu’un condensat SHA-256 de la clé, plus un fragment affichable qui permet de reconnaître une clé sans pouvoir la relire.
Retirer un accès est une opération, pas une campagne
Section intitulée « Retirer un accès est une opération, pas une campagne »Comme chaque personne a sa propre clé, la console d’administration peut agir sur une seule d’entre elles :
- rotation — la clé est remplacée, le compte et son historique d’usage sont conservés, l’ancienne clé cesse de fonctionner ;
- désactivation — un compte dont des appels sont journalisés ne se supprime pas, il se désactive, ce qui préserve l’attribution des appels déjà facturés ;
- retrait du plan — un compte sans plan est refusé, ce qui bloque sans effacer.
Aucune de ces opérations ne touche les autres postes, et aucune ne demande de redéployer la passerelle : celle-ci relit la base à chaque requête, sans cache.
Les plafonds sont appliqués là où passe la dépense
Section intitulée « Les plafonds sont appliqués là où passe la dépense »Un plafond posé côté client est une convention. Un plafond posé sur le chemin de la requête est une contrainte.
Chaque compte porte un plan, et chaque plan porte un plafond mensuel en euros. À
chaque requête relayée, la passerelle recalcule la dépense du mois en cours en
agrégeant request_logs avec les prix par token des modèles, sur une fenêtre qui
commence au premier jour du mois. Au-delà du plafond, la requête est refusée avec
un statut 402.
Trois états, à ne pas confondre :
| État du compte | Comportement |
|---|---|
| aucun plan rattaché | refusé, statut 403 |
| plan avec un plafond | refusé au-delà, statut 402 |
| plan sans plafond | jamais refusé pour cause de dépense |
Le piège vaut d’être connu : après jointure, « aucun plan » et « plan illimité » produisent tous les deux un plafond vide. Seul le rattachement au plan distingue les deux, et ce sont des résultats opposés.
Un seul point de sortie à ouvrir, et à auditer
Section intitulée « Un seul point de sortie à ouvrir, et à auditer »Sur un poste construit avec le profil on-premise, les appels aux modèles sont
le seul flux sortant — voir
Où passent les données. Et ce flux ne va
pas chez un fournisseur : il va chez vous.
Ce qui en découle pour l’exploitation :
- la règle de pare-feu à écrire pour les postes tient en une destination, la passerelle, au lieu d’une liste de domaines de fournisseurs à tenir à jour ;
- la sortie vers Internet, si vous en ouvrez une, part d’un seul hôte, celui que vous choisissez, dans le segment que vous choisissez ;
- un fournisseur hébergé sur site — un serveur de modèles dans votre réseau — se déclare comme n’importe quel autre fournisseur, et le poste ne change pas de configuration pour autant.
L’indirection par endpoint
Section intitulée « L’indirection par endpoint »Le client n’appelle pas un modèle, il appelle un endpoint : un nom que vous
publiez et qui désigne un modèle chez un fournisseur. La passerelle écrase le
champ model du corps par celui de l’endpoint.
Rediriger un endpoint vers un autre modèle est donc une modification faite dans la console, qui prend effet sur la requête suivante, sans qu’aucun poste soit reconfiguré. Changer de fournisseur pour cause de prix, de disponibilité ou de politique interne cesse d’être une opération de parc.
Ce que la passerelle ne fait pas
Section intitulée « Ce que la passerelle ne fait pas »Une explication honnête doit aussi dire où s’arrête le composant.
- Elle ne termine pas TLS. Elle écoute en HTTP. La terminaison TLS est à la charge de l’infrastructure qui l’accueille — ingress, répartiteur de charge, proxy inverse. Ce n’est pas un détail de déploiement : sans elle, les clés des comptes circulent en clair sur votre réseau.
request_logsest un fait de facturation, pas un journal d’audit. La table porte l’horodatage, le compte, l’endpoint, le modèle, la latence et les tokens — de quoi calculer un coût et appliquer un plafond. Elle ne porte ni contrôle d’intégrité, ni politique de rétention, et ses clés étrangères restent modifiables. Une supervision de sécurité se construit à côté, pas dessus.- Elle n’expose pas de route de santé ni de version. Sa seule route est la route de relais.
Ces limites sont des propriétés du composant, pas des surprises : elles définissent ce que l’infrastructure d’accueil doit apporter.
Pourquoi trois services et pas un
Section intitulée « Pourquoi trois services et pas un »llm-gateway, gateway-db et gateway-admin sont séparés parce qu’ils ne
courent pas les mêmes risques.
La passerelle est sur le chemin de chaque requête : elle doit rester petite, et elle détient les clés des fournisseurs. La console est un outil d’exploitation consulté quelques fois par semaine, et elle n’a aucune raison de connaître ces clés — elle ne parle qu’à la base. La base, elle, est le seul état durable, donc le seul objet à sauvegarder.
Le découpage se lit dans les flux : la console n’appelle jamais la passerelle, la passerelle n’appelle jamais la console. Elles se rencontrent dans la base. Le schéma d’ensemble est dans Architecture.