La couche invisible : comment on protège le secret professionnel face aux LLM

La couche invisible : comment on protège le secret professionnel face aux LLM

Le pipeline de masquage, la matrice de carve-outs, et la discipline opérationnelle qui rend la chose tenable.*


Pourquoi ce sujet est le plus structurant

Dans une fiduciaire, la confidentialité n'est pas un argument commercial. C'est un devoir contractuel issu du mandat (Art 398 CO, devoir de fidélité et de diligence du mandataire), renforcé par les clauses de confidentialité signées avec chaque mandant. C'est aussi une exigence légale (nLPD pour la Suisse avec une responsabilité de sous-traitant, RGPD pour les clients européens), une obligation d'archivage et de traçabilité (Art 958f CO sur la conservation des pièces comptables), et une condition de confiance commerciale. Plusieurs de nos clients sont par ailleurs régulés par la FINMA : sans être nous-mêmes sous régulation directe, nous devons concevoir notre traitement de la donnée pour répondre aux exigences de gouvernance des sous-traitants que la régulation impose à nos clients. Ces couches se cumulent.

Quand nous avons décidé d'introduire des LLM dans nos flux, la question n'était pas « est-ce qu'on peut le faire » mais « comment on le fait sans remettre en cause aucune de ces quatre couches ». L'article #3 a expliqué pourquoi nous avons choisi une infrastructure interne. Cet article décrit ce que cette infrastructure fait concrètement pour qu'un fournisseur de modèle, même utilisé en exception encadrée, ne puisse jamais voir une donnée nominative.

Nous appelons cette discipline en interne « la couche invisible ». Invisible au comptable qui invoque les agents. Invisible au client qui consulte ses bilans. Mais structurellement présente dans chaque appel, chaque log, chaque écriture.

Le principe : masquer avant d'envoyer

La règle par défaut tient en une phrase. Toute donnée qui sort de la frontière de confiance Synergix vers un fournisseur LLM tiers passe par un pipeline de masquage. Sans exception, sans dérogation tacite.

Le masqueur s'appelle GLiNER. C'est un détecteur d'entités nommées multilingue, déployé en local sur notre infrastructure, qui sait reconnaître les signaux PII (Personally Identifiable Information) en français, allemand et anglais, les trois langues que nous traitons. Il identifie les noms de personnes physiques, les identifiants nationaux (numéro AVS, numéro de passeport), les adresses postales, les IBAN personnels, les dates de naissance, les numéros de téléphone, et toute autre catégorie ajoutée à notre politique interne.

Pour chaque entité détectée, le masqueur substitue un jeton anonyme. Un nom devient PERSON_07, un IBAN devient IBAN_03, une date de naissance devient DOB_01. Le mapping de substitution reste exclusivement en mémoire processus, jamais persisté, jamais loggé. La requête masquée part vers le LLM. La réponse, démasquée côté Synergix, est consommée par le service appelant.

En cas d'échec du masqueur, la règle est intransigeante. La requête échoue plutôt que de partir non masquée. C'est le principe du fail-closed. Une exception silencieuse aurait été pire qu'un appel qui échoue : elle aurait laissé partir une donnée qu'elle n'aurait pas dû. Nous préférons un service qui retourne une erreur explicite à un service qui réussit en violant la confidentialité.

La matrice de carve-outs

Tous les usages ne se valent pas. Une demande de reformulation d'email interne par un comptable n'a pas le même profil de sensibilité qu'une analyse fine d'un bilan client. Pour graduer la circulation des données, nous maintenons une matrice de carve-outs.

Cette matrice croise deux axes : la nature du traitement demandé (extraction, résumé, classification, génération, raisonnement, traduction) et la nature de la donnée concernée (publique, interne, client non sensible, client sensible, client soumis à secret renforcé). À chaque case correspond une décision : autorisé en local sans masquage, autorisé en local avec masquage léger, autorisé en cloud avec masquage complet, ou interdit.

La matrice est ratifiée au niveau direction. Toute évolution requiert une revue. Toute exception ponctuelle nécessite une approbation explicite et est journalisée. La matrice n'est pas un document figé : elle évolue à mesure que les usages s'étendent et que les fournisseurs LLM modifient leurs garanties contractuelles. Mais à un instant donné, elle est unique, lisible, opposable.

L'effet pratique de cette matrice est de rendre les décisions de routage explicites. Quand un agent envoie une requête, la couche d'orchestration (article #4) consulte la matrice pour décider du routage. Une requête d'extraction sur une facture client sensible : route locale obligatoire. Une demande de reformulation d'un courrier sortant déjà rédigé : route cloud avec masquage. Une recherche dans la base de connaissance interne (publique côté Synergix) : route locale par défaut, route cloud autorisée si charge locale saturée. La matrice transforme un jugement humain au cas par cas en une règle déterministe.

Audit renforcé : trois mécanismes complémentaires

Masquer ne suffit pas. Il faut être en mesure de prouver, à un auditeur ou à un client, que le masquage a effectivement eu lieu sur une période donnée. Trois mécanismes complémentaires assurent cette traçabilité.

Empreintes SHA-256. Pour chaque appel sortant vers un LLM, nous calculons l'empreinte cryptographique du payload masqué effectivement envoyé. Cette empreinte est stockée dans Langfuse avec les métadonnées de l'appel (date, agent appelant, modèle cible, latence, tokens). Si une question est posée plus tard sur ce qui a été envoyé, l'empreinte permet de vérifier qu'aucune modification n'a eu lieu en aval, et que le contenu envoyé correspond bien au payload masqué journalisé. C'est la même logique qu'une signature électronique : on ne stocke pas le payload (qui contiendrait des jetons réversibles localement), mais on stocke une preuve d'intégrité.

Échantillonnage 1 %. Sur 1 % des appels sortants, sélectionnés aléatoirement, nous conservons en clair (côté Synergix uniquement, dans un store chiffré et accessible seulement à la direction conformité) le payload masqué et la réponse reçue. Cet échantillon sert aux revues de qualité du masquage : on inspecte manuellement que les jetons substitués correspondent bien à ce qu'ils devraient cacher, qu'aucune entité PII n'est passée à travers les mailles. L'échantillon n'est jamais partagé hors de la cellule conformité, et est purgé après six mois.

Alertes de dérive. Une dérive du masqueur (par exemple, un changement de modèle GLiNER qui détecterait moins bien une catégorie d'entité) peut passer inaperçue si on ne la cherche pas. Nous suivons en continu le ratio entité-détectée / volume de tokens entrant, par catégorie d'entité et par langue. Une variation supérieure à un seuil (ajusté par catégorie) déclenche une alerte opérationnelle. La calibration de ces seuils est elle-même un travail continu.

Ces trois mécanismes sont indissociables. L'empreinte prouve l'intégrité d'un appel donné. L'échantillonnage prouve la qualité du masquage sur un volume. Les alertes détectent les dérives avant qu'elles ne deviennent systémiques.

Isolation par client à chaque couche

Le masquage protège la sortie. L'isolation protège l'intérieur.

Une donnée client A ne doit jamais, en interne, être lue par un agent dans le contexte d'un client B. Cette règle paraît évidente, mais elle se durcit quand on multiplie les stores et les agents. Une faille dans une seule couche compromettrait tout l'édifice.

L'isolation par client est posée à chaque couche de stockage.

Dans Supabase / PostgreSQL, c'est la Row-Level Security (RLS) qui assure l'isolation. Chaque table contient une colonne client_id. Une politique RLS interdit toute requête qui ne précise pas explicitement le client_id cible, et le client_id est vérifié par rapport au contexte d'authentification de l'appelant. Un agent qui interrogerait toutes les factures sans filtre recevrait un résultat vide, pas la base entière. La RLS n'est pas une fonctionnalité applicative qu'on peut oublier d'invoquer. C'est une politique au niveau de la base, contrôlée par PostgreSQL lui-même.

Dans Qdrant, l'isolation passe par le payload filter. Chaque vecteur stocké est associé à un payload qui contient le client_id. Toute requête de similarité doit obligatoirement contenir un filtre client_id = X. Une revue automatisée vérifie que toutes les requêtes émises depuis nos services contiennent bien ce filtre. Une requête sans filtre est rejetée par notre wrapper applicatif avant d'atteindre Qdrant.

Dans Neo4j, l'isolation se fait par labels et par requêtes Cypher contraintes. Les nœuds sont étiquetés avec leur appartenance client, et les patterns Cypher générés par nos services préfixent systématiquement le scope client. Un parcours de graphe qui sortirait du périmètre déclaré déclencherait une exception applicative.

Dans MinIO, chaque client a son propre bucket. Les politiques d'accès sont gérées par IAM, et l'attribution d'un bucket à un client est immuable.

Cette isolation à quatre niveaux se vérifie à chaque release. Une suite de tests d'intrusion internes simule des accès cross-client et vérifie que chaque tentative est bien rejetée. Les tests passent en intégration continue à chaque modification d'un service touchant aux stores.

Hardening containers : la défense en profondeur

L'isolation logique repose sur les politiques applicatives. Mais une politique se prouve par son comportement face à un attaquant. Notre approche du runtime est celle de la défense en profondeur : on suppose qu'un service peut être compromis, et on conçoit pour limiter l'impact.

Tous nos services tournent dans des containers avec hardening systématique. Trois mesures structurantes.

cap_drop ALL : tous les capabilities Linux sont retirés au démarrage du container. Si un service en a besoin d'un, il doit être réajouté explicitement. La grande majorité de nos containers tournent sans aucun capability, ce qui réduit massivement la surface d'attaque en cas de compromission.

no-new-privileges : un processus ne peut pas obtenir de nouveaux privilèges après son démarrage, même via setuid. Une élévation classique devient impossible.

Filesystem read-only : la racine du filesystem container est montée en lecture seule. Seuls les volumes explicitement déclarés sont écrivables. Un attaquant qui obtiendrait l'exécution dans un container ne pourrait pas y déposer un binaire malveillant pour persister.

À ces trois mesures s'ajoutent un user non-root par défaut, l'absence de shell dans les images de production, et un network policy strict qui interdit tout trafic non listé explicitement.

Aucune de ces mesures ne change ce que fait le service en fonctionnement nominal. Mais ensemble, elles changent radicalement le coût d'une attaque réussie, ce qui est l'enjeu réel.

Procédure d'effacement multi-stores

Le RGPD et la nLPD posent un droit à l'effacement. Pour une fiduciaire, cette obligation se croise avec une autre : l'obligation de conservation des pièces comptables (10 ans en Suisse, OR art. 958f). L'effacement n'est donc pas total mais sélectif : on supprime ce qui peut l'être (PII non liée à la conservation comptable), on conserve ce qui doit l'être (pièces comptables anonymisées si nécessaire).

Notre procédure d'effacement opère sur les quatre stores en cohérence.

Dans Supabase, une requête supprime ou anonymise les colonnes PII des tables concernées. Dans Qdrant, les vecteurs associés au sujet (identifiés par filtre payload) sont supprimés. Dans Neo4j, les nœuds et les relations correspondants sont retirés ou pseudonymisés selon la politique. Dans MinIO, les objets sources sont supprimés des buckets actifs et purgés des sauvegardes après le délai légal.

L'opération est journalisée intégralement. La durée totale est mesurée. Un certificat d'effacement est généré, avec horodatage, scope, opérateur et numéro de ticket. Ce certificat peut être présenté à un client qui en ferait la demande.

Une revue trimestrielle vérifie que le délai entre la demande d'effacement et la réalisation effective reste sous notre engagement contractuel.

Ancrages réglementaires

La discipline décrite ci-dessus ne se justifie pas par elle-même. Elle se justifie par référence à un cadre.

Art 398 CO (devoir de fidélité et de diligence du mandataire) : le mandat fiduciaire engage une obligation de fidélité du mandataire vis-à-vis du mandant. Ce devoir est renforcé par les clauses de confidentialité signées avec chaque mandant. Notre architecture est conçue pour rendre ce devoir techniquement infrangible, pas seulement contractuellement protégé.

nLPD (Suisse, en vigueur depuis 2023) : finalité explicite, transparence, portabilité, droit à l'effacement, transferts internationaux encadrés, responsabilité de sous-traitant. Notre matrice de carve-outs documente la finalité de chaque circulation. Notre journalisation Langfuse documente la traçabilité.

RGPD : applicable à nos clients européens. Mêmes principes que la nLPD avec quelques précisions supplémentaires (DPIA pour les traitements à haut risque, registre des traitements). Notre registre est tenu à jour et audité annuellement.

Art 958f CO : obligation de conservation des pièces comptables (10 ans) avec garantie d'intégrité et de restitution. Notre procédure d'effacement compose avec cette obligation : on supprime ce qui peut l'être (PII non liée à la conservation), on conserve ce qui doit l'être.

Exigences de gouvernance des clients régulés FINMA : plusieurs de nos clients sont régulés par la FINMA (notamment au titre de la circulaire 2023/1 sur les risques opérationnels). La régulation impose à ces clients des exigences sur leurs sous-traitants : contrat formel, droit d'audit, plan de réversibilité, traçabilité. Nous appliquons ces exigences à nos LLM cloud, parce que cela rend notre prestation acceptable pour ces clients. Sans être nous-mêmes sous régulation directe.

OWASP LLM Top 10 : référentiel des risques spécifiques aux applications LLM. Nous nous y référons pour les revues de sécurité, en particulier sur les attaques par prompt injection et les fuites par modèle.

Ces ancrages ne sont pas des cases à cocher. Ce sont les contraintes réelles de notre métier, transcrites en exigences architecturales.

Ce que ça change pour le dirigeant et pour le comptable

Pour un dirigeant client de Synergix, la couche invisible change la conversation. La question « est-ce que mes données passent dans ChatGPT » a une réponse précise. Oui, sur 8 % du volume environ, dans des conditions documentées, après masquage de toute information nominative, avec des engagements contractuels zero-data-retention vérifiés. Non sur les 92 % restants, qui sont traités exclusivement sur notre infrastructure interne. Cette précision est plus rassurante qu'un « non, jamais » qui serait faux ou qu'un « oui, mais c'est sûr » qui serait creux.

Pour un comptable Synergix, la couche invisible change la quotidienneté. Quand il invoque un agent, il ne pense pas au masquage. Le masquage est intégré, par défaut, sans qu'il ait à le déclencher. La discipline est portée par l'architecture, pas par sa vigilance. Cela libère son attention pour ce qui compte : la qualité du jugement comptable.

Le sujet sur lequel on ne fait pas d'économie

S'il y a un sujet sur lequel nous n'arbitrons pas, c'est celui-ci. Tous les autres aspects de la stack sont objet d'optimisation continue : performance, coût, expérience développeur. La couche invisible, elle, est un absolu. Elle peut s'enrichir. Elle ne peut pas se relâcher.

Cette posture n'est pas dogmatique. Elle est arithmétique. Le coût d'une fuite, même mineure, dépasserait l'addition de tous les bénéfices opérationnels que la stack apporte. Aucune optimisation ne mérite d'entamer cette couche.

L'article suivant (#7) propose un cadre concret pour décider, pour un usage donné, s'il faut un workflow déterministe, un RAG ou un agent.

Lire la suite