Translate

lundi 2 mars 2026

PRESIDIO avec LiteLLM + SIEM

LiteLLM : QQOQCC.



LiteLLM, dans sa version Proxy Server, sert essentiellement à centraliser, sécuriser et simplifier l’accès à tous les modèles d’IA derrière une seule API compatible OpenAI. Il sera un pivot dans cette architecture. Je positionne cette configuration sur Docker car ensuite, il sera possible de la migrer vers Kubernetes et avoir des fermes en pré production, puis production. 

Représentation du projet d'architecture sécurisée et IA P2DS.


LiteLLM, dans sa version Proxy Server, sert essentiellement à centraliser, sécuriser et simplifier l’accès à tous les modèles d’IA derrière une seule API compatible OpenAI.

Voici une explication simple et structurée, basée sur le blog.stephane-robert.info.


🧩 Ce que fait LiteLLM (en version simple)

LiteLLM joue le rôle de passerelle unique entre vos applications et des dizaines de fournisseurs de modèles IA (OpenAI, Anthropic, Azure, Bedrock, Hugging Face…).
Au lieu de gérer plusieurs API, formats, clés et règles, vous passez toujours par LiteLLM, qui s’occupe du reste.


⚙️ Les fonctions essentielles (explication simple)

1) Accès unifié à 100+ modèles

  • Vous appelez toujours la même API (format OpenAI).
  • LiteLLM traduit automatiquement vers le bon fournisseur.
  • Vous pouvez changer de modèle sans changer votre code.

2) Compatibilité totale OpenAI

  • Endpoints /chat/completions, /embeddings, /batches.
  • Vos outils existants fonctionnent sans modification.

3) Clés virtuelles pour utilisateurs/équipes

  • Vous créez des API keys internes pour vos équipes.
  • Vous contrôlez qui utilise quoi, et combien.
  • Vous évitez de distribuer vos vraies clés OpenAI/Anthropic.

4) Suivi des coûts

  • LiteLLM calcule automatiquement les dépenses :
    • par modèle
    • par utilisateur
    • par équipe
  • Très utile pour éviter les mauvaises surprises.

5) Budgets et limites

  • Vous fixez des quotas :
    ex : 20€ par mois pour l’équipe marketing, 1000 requêtes/jour pour un service.

6) Interface d’administration

  • Une UI web pour gérer :
    • utilisateurs
    • équipes
    • clés
    • modèles
    • budgets
    • logs

7) Fallbacks et load balancing

  • Si un modèle tombe en panne, LiteLLM bascule vers un autre.
  • Vous pouvez répartir la charge entre plusieurs fournisseurs.

8) Cache Redis

  • Réduit les coûts et accélère les réponses.
  • Très utile pour les prompts répétitifs.

9) Alertes

  • Notifications Slack / Teams / Email quand :
    • un budget est dépassé
    • un incident survient

Fonctions avancées (version Enterprise)

Toujours en explication simple :

Authentification avancée

  • SSO, OIDC, Azure AD, Keycloak.
  • Gestion automatique des tokens temporaires.

Gestion d’organisations

  • Structure hiérarchique : organisations → équipes → utilisateurs.
  • Admins délégués.
  • Modèles privés par équipe.

Observabilité avancée

  • Métriques Prometheus.
  • Logging vers Datadog, S3, GCS, Azure Data Lake.

Sécurité renforcée

  • Guardrails (politiques de contenu).
  • Rotation automatique des clés.

Comment ça fonctionne (simplement)

LiteLLM est un reverse proxy intelligent :

  1. Votre application envoie une requête au format OpenAI.
  2. LiteLLM la reçoit et regarde quel modèle utiliser.
  3. Il transforme la requête pour le fournisseur choisi.
  4. Il renvoie la réponse au format OpenAI.

Vous n’avez donc jamais à gérer les différences entre fournisseurs.


Pourquoi les entreprises l’utilisent

  • Pour centraliser l’accès aux IA.
  • Pour sécuriser les clés et les accès.
  • Pour maîtriser les coûts.
  • Pour éviter le shadow IT.
  • Pour changer de fournisseur facilement (multi-sourcing).
  • Pour industrialiser l’usage des LLM.
  • Pour ma part créer une architecture plus renforcée

Architecture D2S – Version RSSI (DMZ, Double Firewall, Flux contrôlés).

L’ajout d’un SIEM dans mon architecture :

c’est une exigence DSI/DPO/RSSI dès qu’on manipule des données sensibles, qu’on expose des API internes/externes, et qu’on introduit des briques comme LiteLLM, Presidio, Open WebUI ou des modèles IA.

L’idée clé : le SIEM n’est pas là pour l’IA, il est là pour la sécurité du SI dans lequel l’IA s’insère.

Pourquoi un SIEM dans cette architecture

1) Détection d’incidents de sécurité

Les flux IA (LiteLLM, Open WebUI, API Gateway, Presidio) deviennent de nouveaux vecteurs d’attaque :

  • tentatives d’accès non autorisé

  • exfiltration de données via prompts

  • appels massifs anormaux (DoS applicatif)

  • utilisation frauduleuse de clés virtuelles

  • contournement des règles DPO (ex : envoi de PII vers un modèle cloud)

Le SIEM permet de corréler ces événements avec le reste du SI.

2) Traçabilité réglementaire (DPO / RSSI)

Dans un contexte RGPD, santé, OIV ou souveraineté, il faut pouvoir répondre à :

  • Qui a accédé à quoi ?

  • Quand ?

  • Depuis où ?

  • Avec quel modèle ?

  • Sur quelles données ?

LiteLLM génère des logs riches (requêtes, modèles, coûts, utilisateurs). Presidio génère des logs de détection PII. Open WebUI génère des logs d’accès.

Le SIEM centralise et conserve ces traces pour audit.

3) Supervision de la chaîne IA (DSI)

L’IA devient une chaîne de production :

  • API Gateway

  • Presidio

  • LiteLLM

  • Providers (Cloud / On‑Prem / Ollama)

  • Open WebUI

  • Grafana / Prometheus

Le SIEM permet de détecter :

  • un modèle qui répond trop lentement

  • un provider qui tombe

  • un pic de consommation anormal

  • un comportement utilisateur suspect

C’est la vision transverse que Grafana seul ne fournit pas.

4) Conformité et souveraineté

Pour un DPO/RSSI, le SIEM est indispensable pour :

  • prouver que les données sensibles n’ont pas quitté le périmètre autorisé

  • tracer les appels vers les modèles cloud

  • détecter les violations de politiques (ex : modèle non autorisé)

  • conserver les logs pour les audits CNIL / internes

Sans SIEM, tu n’as aucune preuve en cas d’incident.

5) Corrélation avec les autres couches du SI

L’IA n’est qu’un composant du SI, le SIEM permet de corréler :

  • logs réseau

  • logs firewall

  • logs IAM / SSO

  • logs applicatifs

  • logs LiteLLM / Presidio / WebUI

Exemple :

Un utilisateur se connecte via SSO → appelle Open WebUI → envoie un prompt suspect → Presidio détecte des PII → LiteLLM bloque → SIEM corrèle → alerte RSSI.

Comment le SIEM s’intègre dans mon schéma

Dans mon architecture, la brique Supervision & Audit inclut :

  • Grafana (métriques)

  • Logs (Loki / Elastic)

  • SIEM (corrélation + sécurité)

Le SIEM il est obligatoire dès que vous avez :

  • des données sensibles (santé, RH, finance)

  • des flux externes

  • des API exposées

  • des modèles IA (risque d’exfiltration)

  • des obligations réglementaires (RGPD, HDS, OIV)

Synthèse en une phrase

Le SIEM est indispensable pour détecter, corréler, tracer et auditer tous les événements de sécurité liés à la chaîne IA, et pour garantir la conformité DPO/RSSI dans un environnement où les modèles peuvent devenir des vecteurs d’attaque ou de fuite de données.

PRESIDIO → LiteLLM

Fiche d'Intégration Opérationnelle — Architecture IA Souveraine UGAIA

 

Version

1.0 — Mars 2026

Statut

Appliquer dès Phase 2 (J+30)

Classification

Données N3/N4 — Confidentiel

Prérequis

Ollama + Phi-4 installés, LiteLLM Gateway opérationnel

Objectif

Anonymisation PII obligatoire avant tout flux vers le modèle d'inférence

 

🎯  Contexte UGAIA

Presidio s'intègre comme middleware dans LiteLLM Proxy, garantissant qu'aucune donnée personnelle (PII) ne transite en clair vers Ollama/Phi-4. Les journaux produits sont « audit-ready » dès leur création — conformité RGPD Art. 5, règle des 48h CNIL, et assurabilité cyber.

 

1. Architecture de la chaîne d'anonymisation

Le schéma suivant représente le flux Zero Trust IA avec Presidio en position de garde-frontière :

 

  Utilisateur

      |  (prompt brut — peut contenir PII N3/N4)

      v

  Open WebUI

      |

      v

  [ PRESIDIO — Anonymisation PII ]  <===  MIDDLEWARE LiteLLM

      |  (prompt anonymisé : <NOM_PERSONNE>, <EMAIL>, <NIR>...)

      v

  LiteLLM Proxy (Gateway)

      |  (corrélation : mlflow_run_id injecté)

      v

  Ollama / Phi-4  (inférence locale — zéro dépendance cloud)

      |

      v

  OpenTelemetry Collector

      |

      +----> ELK Stack  (journaux anonymisés — preuves forensiques)

      |

      +----> Langfuse   (observabilité LLM — traçabilité prompt/réponse)

      |

      +----> MLflow     (registre modèle — version + run_id)

 

⚠️  Règle d'or — Audit-by-Design

Aucune donnée nominative ne doit figurer dans les journaux d'audit. Presidio filtre le flux en mémoire vive avant tout écrit dans ELK ou Langfuse.

 

2. Installation de Presidio (Python)

Prérequis système : Python 3.9+, pip, accès Docker optionnel. Déploiement recommandé en on-premise.

 

2.1 Installation des packages

# Installation des composants Presidio

pip install presidio-analyzer presidio-anonymizer

 

# Modèle NLP français (support N3/N4 textes RH, santé, finance)

python -m spacy download fr_core_news_lg

 

# Optionnel : modèle anglais pour documents bilingues

python -m spacy download en_core_web_lg

 

2.2 Test de validation post-install

from presidio_analyzer import AnalyzerEngine

from presidio_anonymizer import AnonymizerEngine

 

analyzer  = AnalyzerEngine()

anonymizer = AnonymizerEngine()

 

test_text = "Jean Dupont, né le 15/03/1982, NIR : 1 82 03 75 108 045 28"

results   = analyzer.analyze(text=test_text, language='fr')

output    = anonymizer.anonymize(text=test_text, analyzer_results=results)

 

print(output.text)

# Attendu : <PERSON>, né le <DATE_TIME>, NIR : <FR_NIR>

 

✅  Cible de détection

Taux de détection cible : > 95% sur jeu de données représentatif métier. Valider impérativement avant mise en production N3/N4.

 

3. Configuration du middleware LiteLLM

Presidio s'intègre comme hook de pré-traitement (pre-call hook) dans LiteLLM. Les données sont filtrées en mémoire avant routage vers Ollama.

 

3.1 Classe middleware Presidio

# presidio_middleware.py

from presidio_analyzer import AnalyzerEngine

from presidio_anonymizer import AnonymizerEngine

from presidio_anonymizer.entities import OperatorConfig

import litellm

 

class PresidioMiddleware:

    def __init__(self):

        self.analyzer  = AnalyzerEngine()

        self.anonymizer = AnonymizerEngine()

 

    def anonymize(self, text: str, level: str = 'N3') -> dict:

        """

        Anonymise le texte et retourne le texte filtré

        + la liste des entités détectées pour journalisation.

        """

        results = self.analyzer.analyze(

            text=text,

            language='fr',

            entities=[

                'PERSON', 'EMAIL_ADDRESS', 'PHONE_NUMBER',

                'IBAN_CODE', 'CREDIT_CARD', 'DATE_TIME',

                'LOCATION', 'IP_ADDRESS', 'NRP',

                'FR_NIR',   # Numéro de sécurité sociale FR

                'MEDICAL_LICENSE',

            ]

        )

 

        # Stratégie de masquage selon niveau de classification

        operators = {

            'PERSON':        OperatorConfig('replace', {'new_value': '<NOM_PERSONNE>'}),

            'EMAIL_ADDRESS': OperatorConfig('replace', {'new_value': '<EMAIL>'}),

            'PHONE_NUMBER':  OperatorConfig('replace', {'new_value': '<TEL>'}),

            'IBAN_CODE':     OperatorConfig('hash',    {'hash_type': 'sha256'}),

            'CREDIT_CARD':   OperatorConfig('mask',    {'masking_char': '*', 'chars_to_mask': 12}),

            'FR_NIR':        OperatorConfig('hash',    {'hash_type': 'sha256'}),

            'DATE_TIME':     OperatorConfig('replace', {'new_value': '<DATE>'}),

            'LOCATION':      OperatorConfig('replace', {'new_value': '<LOCALISATION>'}),

            'IP_ADDRESS':    OperatorConfig('replace', {'new_value': '<IP>'}),

        }

 

        anonymized = self.anonymizer.anonymize(

            text=text,

            analyzer_results=results,

            operators=operators

        )

 

        return {

            'anonymized_text': anonymized.text,

            'detected_entities': [r.entity_type for r in results],

            'pii_detected': len(results) > 0,

        }

 

3.2 Hook LiteLLM — pré-traitement du prompt

# litellm_config.py

import litellm

import mlflow

import json

from presidio_middleware import PresidioMiddleware

from datetime import datetime

 

presidio = PresidioMiddleware()

 

def pre_call_hook(kwargs, result, start_time, end_time):

    """

    Hook exécuté avant chaque appel LiteLLM.

    Anonymise le prompt et journalise les métadonnées d'audit.

    """

    messages = kwargs.get('messages', [])

    run_id = mlflow.active_run().info.run_id if mlflow.active_run() else 'no_run'

 

    for msg in messages:

        if msg.get('role') == 'user':

            raw_text = msg['content']

            result   = presidio.anonymize(raw_text)

 

            # Remplacement du contenu par la version anonymisée

            msg['content'] = result['anonymized_text']

 

            # Journalisation des métadonnées uniquement (jamais le texte brut)

            audit_meta = {

                'mlflow_run_id':     run_id,

                'timestamp':         datetime.utcnow().isoformat(),

                'pii_detected':      result['pii_detected'],

                'entities_detected': result['detected_entities'],

                'anonymized':        True,

            }

            # Envoi vers Langfuse / ELK (via OpenTelemetry)

            print(json.dumps(audit_meta))  # remplacer par otel_logger

 

litellm.pre_call_hook = pre_call_hook

 

3.3 Configuration litellm_config.yaml

# litellm_config.yaml

model_list:

  - model_name: phi4-local

    litellm_params:

      model: ollama/phi4

      api_base: http://localhost:11434

 

general_settings:

  presidio_enabled: true

  presidio_language: fr

  pii_masking: true

  log_decision_process: true    # Traçabilité audit CNIL

 

litellm_settings:

  success_callback: ["langfuse", "mlflow"]

  failure_callback: ["langfuse"]

  telemetry: true

 

4. Workflow opérationnel — 5 étapes

 

1

Réception du prompt brut

Open WebUI reçoit la requête utilisateur. Le texte peut contenir des PII N3/N4 non contrôlées.

 

2

Anonymisation Presidio (< 50ms)

Le middleware analyse le texte, détecte les entités PII, applique le masquage configuré. Le prompt anonymisé remplace le texte original en mémoire.

 

3

Injection du mlflow_run_id

Un identifiant unique est généré et injecté dans les métadonnées de la requête. Ce run_id devient l'identifiant pivot de toute la chaîne d'audit.

 

4

Inférence Ollama / Phi-4

Le modèle reçoit uniquement le prompt anonymisé. Zéro PII ne transite vers le moteur d'inférence. Conformité RGPD Art. 5 (minimisation) garantie.

 

5

Journalisation audit-ready

ELK et Langfuse reçoivent uniquement les métadonnées anonymisées + mlflow_run_id. Les logs sont immédiatement utilisables pour réponse CNIL 48h ou rapport assureur.

 

5. Validation et contrôle qualité

5.1 Suite de tests de non-régression

# test_presidio_validation.py

import pytest

from presidio_middleware import PresidioMiddleware

 

pii = PresidioMiddleware()

 

TEST_CASES = [

    # (description, texte_brut, entités_attendues)

    ('Nom complet FR',

     'Mme Marie Curie signe le contrat.',

     ['PERSON']),

    ('Email professionnel',

     'Contactez pierre.martin@entreprise.fr pour confirmation.',

     ['EMAIL_ADDRESS']),

    ('NIR sécurité sociale',

     'Mon numéro est 1 82 03 75 108 045 28.',

     ['FR_NIR']),

    ('IBAN bancaire',

     'Virement sur FR76 3000 6000 0112 3456 7890 189.',

     ['IBAN_CODE']),

    ('Donnée de santé composée',

     'Dr. Benoit, né le 12/06/1975, consultation le 03/03/2026.',

     ['PERSON', 'DATE_TIME']),

]

 

@pytest.mark.parametrize('desc, text, expected_entities', TEST_CASES)

def test_detection(desc, text, expected_entities):

    result = pii.anonymize(text)

    assert result['pii_detected'], f'Aucune PII détectée pour : {desc}'

    for entity in expected_entities:

        assert entity in result['detected_entities'], \

            f'{entity} non détecté pour : {desc}'

 

def test_no_pii_preserved():

    """Vérifie qu'aucun PII ne subsiste après anonymisation."""

    text = 'Marie Dupont, née le 01/01/1990'

    result = pii.anonymize(text)

    assert 'Marie Dupont' not in result['anonymized_text']

    assert '01/01/1990' not in result['anonymized_text']

 

5.2 Matrice de conformité RGPD

 

Exigence RGPD

Sans Presidio

Avec Presidio

Art. 5 — Minimisation des données

❌ Non conforme

✅ Conforme

Art. 25 — Privacy by Design

❌ Risque élevé

✅ Implémenté

Art. 32 — Sécurité du traitement

⚠️ Partiel

✅ Garanti

Art. 33 — Notification 72h ANSSI

❌ Impossible

✅ Prêt

Règle 48h CNIL — Dossier d'audit

❌ Manuel (jours)

✅ Automatique

Assurabilité cyber 2026

❌ < 50 pts

✅ +15 pts score

 

6. Contribution au Score de Résilience UGAIA

L'intégration de Presidio comme middleware actif contribue directement au score de résilience. Le tableau ci-dessous détaille les points acquis par composant UGAIA :

 

Composant UGAIA

Sans Presidio

Avec Presidio

C1 — Journalisation & Traçabilité

6/12

11/12

C2 — Protection des Données (RGPD)

4/15

13/15

C3 — Sécurité des Accès

6/10

8/10

C4 — Gouvernance & Conformité

5/13

11/13

C5 — Résilience Technique

8/15

12/15

TOTAL / 100

44/100 ⚠️ Non assurable

78/100 ✅ Assurable

 

🏆  Seuils d'assurabilité 2026

Score ≥ 75/100 : éligibilité assurance cyber. Score ≥ 80/100 : statut SOUVERAIN+. L'intégration de Presidio fait passer l'organisation de 44/100 (non assurable) à 78/100 (assurable).

 

7. Résolution des problèmes courants

Symptôme

Cause probable

Solution

Noms FR non détectés

Modèle spaCy EN chargé

Installer fr_core_news_lg et spécifier language='fr'

Latence > 200ms

Modèle NLP trop lourd

Utiliser fr_core_news_md ou migrer vers rs-presidio (Rust)

NIR non reconnu

Reconnaisseur FR_NIR manquant

Ajouter recognizer FR personnalisé (regex NIR)

Hook LiteLLM ignoré

Version LiteLLM < 1.30

Mettre à jour : pip install --upgrade litellm

mlflow_run_id absent

MLflow non initialisé

Appeler mlflow.start_run() avant le hook

Taux détection < 90%

Jargon métier non reconnu

Ajouter des reconnaisseurs personnalisés (contrats, IDs internes)

 

8. Checklist de mise en production

 

VALIDATION PRE-PRODUCTION N3/N4

Toutes les cases doivent être cochées avant activation

 

▶  Installation

•        ☐  presidio-analyzer et presidio-anonymizer installés (pip)

•        ☐  Modèle spaCy fr_core_news_lg téléchargé et validé

•        ☐  Test unitaire de base exécuté avec succès

 

▶  Configuration

•        ☐  PresidioMiddleware instancié et configuré (entités FR activées)

•        ☐  Hook pre_call_hook enregistré dans LiteLLM

•        ☐  litellm_config.yaml : presidio_enabled: true et log_decision_process: true

•        ☐  mlflow_run_id injecté dans les métadonnées de chaque requête

 

▶  Validation

•        ☐  Suite pytest complète : taux de détection ≥ 95% sur jeu de test métier

•        ☐  Contrôle : aucun PII en clair dans les logs ELK et Langfuse

•        ☐  Test règle 48h : dossier d'audit généré automatiquement sans donnée brute

•        ☐  Fallback testé : désactivation Presidio = rejet de la requête (pas de bypass)

 

▶  Documentation

•        ☐  Fiche de procédure archivée dans le système de gestion documentaire

•        ☐  Score de résilience UGAIA recalculé et validé (≥ 75/100)

•        ☐  Rapport d'audit CNIL préparé avec preuves d'anonymisation

 


 

Références et ressources

 

Documentation officielle

https://microsoft.github.io/presidio/ 

API Reference

https://microsoft.github.io/presidio/api-docs/api-docs.html

Démo Hugging Face

https://huggingface.co/spaces/presidio/presidio_demo

ModernBERT PII classifier

https://huggingface.co/llm-semantic-router/pii_classifier_modernbert-base_presidio_token_model

rs-presidio (Rust)

https://github.com/posidron/rs-presidio

LiteLLM Proxy docs

https://docs.litellm.ai/docs/proxy/quick_start

Blog GOUVERNANCES. — Art. 1

https://gouver2020.blogspot.com/2026/02/microsoft-presidio-est-le-framework.html

Blog GOUVERNANCES. — Art. 2

https://gouver2020.blogspot.com/2026/02/tests-installation-de-presidio.html

Blog GOUVERNANCES. — Art. 3

https://gouver2020.blogspot.com/2026/03/pii-de-identification-avec-microsoft.html

Guide UGAIA V10 — Chapitre 5

Gouv˙IA-Secu-Audit-IA_V10_2026.docx

 

📋  Intégration dans le Passeport Souveraineté UGAIA V4

Cette fiche répond directement à la Question 6 du Passeport : traçabilité complète prompt → modèle → accès → évaluation qualité. Le mlflow_run_id est l'identifiant pivot. Sa présence dans chaque enregistrement ELK, Langfuse et MLflow constitue la preuve technique d'intégrité exigée par les auditeurs et les assureurs.

 











Successfully installed PyJWT-2.11.0 apscheduler-3.11.2 azure-core-1.38.2 azure-identity-1.25.2 azure-storage-blob-12.28.0 backoff-2.2.1 boto3-1.40.76 botocore-1.40.76 cffi-2.0.0 croniter-6.0.0 cryptography-46.0.5 dnspython-2.8.0 email-validator-2.3.0 fastapi-0.132.0 fastapi-sso-0.16.0 gunicorn-23.0.0 httpx-sse-0.4.3 isodate-0.7.2 jmespath-1.1.0 litellm-enterprise-0.1.32 litellm-proxy-extras-0.4.46 mcp-1.26.0 msal-1.34.0 msal-extensions-1.3.1 oauthlib-3.3.1 orjson-3.11.7 polars-1.38.1 polars-runtime-32-1.38.1 pycparser-3.0 pydantic-settings-2.13.1 pynacl-1.6.2 python-multipart-0.0.22 pywin32-311 redis-7.2.0 rich-13.7.1 rq-2.7.0 s3transfer-0.14.0 soundfile-0.12.1 sse-starlette-3.2.0 starlette-0.52.1 tzlocal-5.3.1 websockets-15.0.1
PS C:\> litellm --model gpt-4o
INFO:     Started server process [15012]
INFO:     Waiting for application startup.

Ollama peut être utilisé à l’intérieur de LiteLLM comme un fournisseur de modèles locaux.

LiteLLM = Proxy multi‑fournisseurs + gouvernance + coûts

LiteLLM sert à :

  • unifier l’accès à tous les modèles (OpenAI, Anthropic, Azure, Bedrock, Ollama…)

  • gérer les clés virtuelles, quotas, budgets, équipes

  • suivre les coûts et les logs

  • appliquer des politiques de sécurité

  • faire du load balancing et du fallback

  • exposer une API OpenAI unique

LiteLLM n’exécute pas les modèles : il orchestrationne.


Ollama = Serveur local de modèles open‑source

Ollama sert à :

  • télécharger et exécuter des modèles localement (Llama, Mistral, Phi, Qwen…)
  • gérer le chargement en RAM, le quantization, le GPU
  • fournir une API simple pour interroger un modèle local

Ollama n’a pas :

  • de gestion d’utilisateurs
  • de quotas
  • de budgets
  • de logs avancés
  • de multi‑fournisseurs
  • de compatibilité OpenAI complète
  • de load balancing
  • de sécurité d’entreprise

Comment ils s’articulent ensemble

Le schéma réel dans les entreprises

Code
Application → LiteLLM → (OpenAI / Anthropic / Azure / Bedrock / Ollama local)

LiteLLM devient la couche de gouvernance, Ollama devient un fournisseur parmi d’autres.

Conclusion simple

  • Ollama = moteur local

  • LiteLLM = gouvernance + proxy multi‑modèles

Ollama ne remplace pas LiteLLM. Ollama complète LiteLLM.

1) Démarrer LiteLLM Proxy avec Docker, c'est fait

Autrement si tu as déjà téléchargé l’image.

Lance-la :

docker run -p 4000:4000 -e LITELLM_LOG=info docker.litellm.ai/berriai/litellm:main-latest

Cela démarre le proxy LiteLLM sur :

http://localhost:4000   voir copie écran ci-dessus

2) Tester avec l’API OpenAI (via LiteLLM)

Exemple :

curl http://localhost:4000/v1/chat/completions `
  -H "Content-Type: application/json" `
  -H "Authorization: Bearer votrecledetest" `
  -d "{""model"":""gpt-4o-mini"", ""messages"":[{""role"":""user"",""content"":""Bonjour""}]}"

3) Ajouter Ollama comme fournisseur local (si tu veux)

Si tu as Ollama installé :

ollama run mistral

Puis dans LiteLLM, tu peux appeler :

curl http://localhost:4000/v1/chat/completions `
  -H "Content-Type: application/json" `
  -d "{""model"":""ollama/mistral"", ""messages"":[{""role"":""user"",""content"":""Bonjour""}]}"

Résumé clair

  • La ligne “Application → LiteLLM → …” était un schéma, pas une commande.
  • PowerShell a essayé de l’exécuter → erreur normale.
  • Tu as bien installé LiteLLM.
  • Prochaine étape : lancer le proxy et tester une requête.

dimanche 1 mars 2026

PII De-Identification avec Microsoft Presidio démonstration anonymisation

Exemple d'utilisation de Presidio et tests.




Presidio est un framework open source personnalisable pour la détection et l'anonymisation des données personnelles.

Code | Tutoriel | Installation | FAQ | Commentaires |Utilisez cette démo pour :

Expérimenter différents modèles prêts à l'emploi et packages de traitement automatique du langage naturel (TALN). Explorer les différentes options d'anonymisation, notamment la rédaction, le masquage, le chiffrement, etc. Générer du texte synthétique avec Microsoft Presidio et OpenAI.

Configurer des listes d'autorisation et de blocage.

Ce site web de démonstration présente certaines des fonctionnalités de Presidio. Visitez notre site web pour plus d'informations, des exemples et des options de déploiement.

Exemple rendu :




Sélectionnez la manipulation à appliquer au texte après l'identification des données personnelles.

Masquer : Supprimer complètement les données personnelles.

Remplacer : Remplacer les données personnelles par une constante, par exemple <PERSON>.

Synthétiser : Remplacer par des valeurs fictives (nécessite une clé OpenAI).

Surligner : Afficher le texte original avec les données personnelles surlignées en couleur.

Masquer : Remplacer un nombre de caractères par un astérisque (ou un autre caractère de masque).

Hacher : Remplacer par le hachage des données personnelles.

Chiffrer : Remplacer par un chiffrement AES des données personnelles, permettant ainsi une restauration.

Masquer les données personnelles.

Rendu des fenêtres Presidio dans Presidio Demo - a Hugging Face Space by presidio

Détails des textes dans les fenêtres ci-dessus :

Here are a few example sentences we currently support:

Hi, my name is David Johnson and I'm originally from Liverpool.
My credit card number is 4095-2609-9393-4932 and my crypto wallet id is 16Yeky6GMjeNkAiNcBY7ZhrLoMSgg1BoyZ.

On 11/10/2024 I visited www.microsoft.com and sent an email to test@presidio.site,  from IP 192.168.0.1.

My passport: 191280342 and my phone number: (212) 555-1234.

This is a valid International Bank Account Number: IL150120690000003111111 . Can you please check the status on bank account 954567876544? 

Kate's social security number is 078-05-1126.  Her driver license? it is 1234567A.

Here are a few example sentences we currently support:

Hi, my name is <PERSON> and I'm originally from <LOCATION>.
My credit card number is <CREDIT_CARD> and my crypto wallet id is <CRYPTO>.

On 11/10/2024 I visited www.microsoft.com and sent an email to <EMAIL_ADDRESS>,  from IP <IP_ADDRESS>.

My passport: 191280342 and my phone number: (212) 555-1234.

This is a valid International Bank Account Number: <IBAN_CODE> . Can you please check the status on bank account 954567876544? 

<PERSON>'s social security number is 078-05-1126.  Her driver license? it is 1234567A.

Source  


 

Échantillons :

SujetType de donnéesRessourceExemple

PII, PHI et Microsoft Presidio, un guide complet en français.

1. Vocabulaire fondamental : PII, PHI, PCI

Trois acronymes structurent la protection des données dans les systèmes d'IA :

PII (Personally Identifiable Information) — Données à caractère personnel au sens du RGPD. Toute information permettant d'identifier directement ou indirectement une personne physique : nom, prénom, adresse email, numéro de téléphone, adresse postale, numéro de sécurité sociale, numéro de passeport, adresse IP, données de localisation, etc.

PHI (Protected Health Information) — Sous-catégorie américaine (HIPAA) des données de santé protégées. En droit européen, ces données relèvent de l'article 9 du RGPD (données sensibles à protection renforcée) : diagnostic médical, antécédents, ordonnances, résultats d'analyses, numéro de patient, etc. Leur traitement exige une base légale spécifique et des garanties techniques renforcées.

PCI-DSS (Payment Card Industry Data Security Standard) — Données de cartes de paiement : numéros de carte, CVV, dates d'expiration. Soumises à un cadre de sécurité sectoriel strict.

Ces trois catégories forment le cœur de ce que Presidio détecte et anonymise dans vos pipelines IA.


2. Microsoft Presidio — Le framework de référence

Presidio est un framework open source Microsoft conçu pour détecter, anonymiser et pseudonymiser les données sensibles dans des textes, images et documents. Il s'intègre parfaitement dans une architecture UGAIA/souveraineté car il tourne 100% en local, sans envoi vers un cloud externe.

Architecture modulaire de Presidio

Presidio se compose de quatre services principaux :

presidio-analyzer (port 5002) — Moteur de détection : il identifie les entités sensibles via des règles regex, des modèles NLP (spaCy), du machine learning et des recognizers contextuels. Il retourne un score de confiance pour chaque entité détectée (entre 0 et 1).

presidio-anonymizer (port 5001) — Moteur de transformation : il applique les opérations de protection sur le texte brut selon les résultats de l'analyzer. Il supporte plusieurs modes : mask (***), redact (suppression), replace (substitution), hash (SHA256), encrypt (AES) et FPE (format-preserving encryption).

presidio-image-redactor — Caviardage d'images via OCR + Tesseract, utile pour les documents scannés et les captures d'écran contenant des PII.

presidio-ocr — Pipeline complet pour les PDF : extraction OCR puis passage dans l'analyzer/anonymizer.

Installation Docker (testée et validée)

# Téléchargement des images officielles
docker pull mcr.microsoft.com/presidio-analyzer
docker pull mcr.microsoft.com/presidio-anonymizer
# Lancement des conteneurs
docker run -d -p 5002:3000 mcr.microsoft.com/presidio-analyzer:latest
docker run -d -p 5001:3000 mcr.microsoft.com/presidio-anonymizer:latest
# Vérification
docker ps
curl http://localhost:5002/analyze
curl http://localhost:5001/anonymize

Pour un usage professionnel DSI/DPO/RSSI, la variante recommandée fixe les versions et isole le réseau :

docker network create presidio-net
docker run -d --name presidio-analyzer \
--network presidio-net \
-p 5002:3000 \
mcr.microsoft.com/presidio-analyzer:1.0.0
docker run -d --name presidio-anonymizer \
--network presidio-net \
-p 5001:3000 \
mcr.microsoft.com/presidio-anonymizer:1.0.0

3. Intégration dans un pipeline Ollama + Presidio

L'architecture "Gouvernance augmentée" repose sur une séparation nette des rôles :

Composant Rôle Caractéristique
Presidio Détection et anonymisation PII/PHI/PCI Déterministe, traçable, RGPD-compliant
Ollama (Phi-4/Mistral) Analyse sémantique et gouvernance Contextuel, non déterministe — à encadrer
PowerShell/Python Orchestration et audit Reproductible, scriptable

Le flux en 5 étapes

Étape 1 — Ingestion : le document brut (TXT, DOCX, PDF après OCR) entre dans le pipeline.

Étape 2 — Détection Presidio : appel à l'API analyzer pour identifier toutes les entités PII/PHI/PCI avec leur position, type et score de confiance. Résultat : un JSON structuré.

Étape 3 — Anonymisation Presidio : appel à l'anonymizer avec le texte brut et les résultats de détection. Résultat : un texte propre où toutes les données sensibles sont masquées ou pseudonymisées.

Étape 4 — Analyse sémantique Ollama : le LLM local reçoit uniquement le texte anonymisé (jamais les données brutes) plus un résumé des entités détectées. Il produit une classification de sensibilité, une évaluation des risques et des recommandations de gouvernance pour DPO/RSSI/COMEX.

Étape 5 — Sortie : trois artefacts sont générés : le document anonymisé, l'audit JSON horodaté (hash SHA256, versions des modèles, entités détectées), et le rapport de gouvernance en Markdown.

Exemple d'appel Python

import requests
# Appel Presidio Analyzer
analyze_response = requests.post(
"http://localhost:5002/analyze",
json={
"text": "Jean Dupont, IBAN FR76 1234 5678, tél. 06 12 34 56 78",
"language": "fr"
}
)
entities = analyze_response.json()
# Appel Presidio Anonymizer
anonymize_response = requests.post(
"http://localhost:5001/anonymize",
json={
"text": "Jean Dupont, IBAN FR76 1234 5678, tél. 06 12 34 56 78",
"analyzer_results": entities
}
)
clean_text = anonymize_response.json()["text"]
# Résultat : "<PERSON>, IBAN <IBAN_CODE>, tél. <PHONE_NUMBER>"
# Appel Ollama (Phi-4 ou Mistral)
ollama_response = requests.post(
"http://localhost:11434/api/generate",
json={
"model": "phi4",
"prompt": f"Analyse de gouvernance du document suivant : {clean_text}\n"
f"Entités détectées : {entities}\n"
f"Fournis une classification de sensibilité et des recommandations RGPD.",
"stream": False
}
)
governance_report = ollama_response.json()["response"]

4. Matrice de criticité des entités (pour le scoring UGAIA)

Entité Criticité Réglementation Action Presidio
Email 1 RGPD art. 4 Mask
Téléphone 2 RGPD art. 4 Mask
Adresse 2 RGPD art. 4 Redact
Nom complet 3 RGPD art. 4 Pseudonymiser
NIR (sécu) 4 RGPD art. 9 Hash/Encrypt
IBAN 4 PCI-DSS Encrypt
Données santé 5 RGPD art. 9 Encrypt + accès restreint
Carte bancaire 5 PCI-DSS FPE

Ce score de criticité alimentera directement le Score de Résilience UGAIA (composante Data Classification) dans votre framework de gouvernance.


5. Avantages pour UGAIA et la souveraineté numérique

Presidio + Ollama constitue une brique essentielle du pipeline de conformité UGAIA pour plusieurs raisons : aucune donnée ne sort du périmètre maîtrisé (déploiement on-premise Docker), la traçabilité est complète avec hash SHA256 et versionnage des modèles. 

Le LLM n'accède jamais aux données brutes ce qui respecte le principe de minimisation du RGPD, et la solution est auditée et vérifiable par les DPO/RSSI sans dépendance à un fournisseur cloud externe.

C'est exactement le type d'architecture qui permet d'atteindre le niveau SOUVERAIN+ dans le scoring UGAIA (≥80 points), notamment sur les composantes "Traçabilité" et "Classification des données" (N1-N4).


Mon Blog documente une installation réussie avec détection de numéro de téléphone validée. L'étape suivante naturelle serait d'ajouter le modèle spaCy français (fr_core_news_lg) pour améliorer la détection des entités francophones, et d'intégrer des recognizers custom pour les identifiants spécifiques au contexte français (NIR, SIRET, numéros de permis).

Intégration de Grafana et Open WebUI dans l'architecture UGAIA + Presidio

Mon Architecture existante (Ollama + Presidio + Promtail + Loki) est déjà à 73/100 dans le scoring UGAIA. L'intégration correcte de Grafana et Open WebUI, avec les sécurisations nécessaires, vous permet d'atteindre ≥85/100 — niveau SOUVERAIN+, et donc l'éligibilité aux produits d'assurance UGAIA.

La règle fondamentale de cette architecture : Open WebUI est le seul point d'entrée des utilisateurs (port 3000), Grafana est réservé aux administrateurs (port 3001). 

Tous les autres ports (Ollama 11434, Loki 3100, Presidio 5001/5002) restent strictement internes au réseau Docker.

1. Architecture cible — Vue d'ensemble.

Contenu du schéma ci-dessus :

  • Zones colorées :

    • 🔴 Internet (Utilisateurs – HTTPS 443)

    • 🟠 DMZ (Reverse Proxy / WAF – TLS)

    • 🔵 Zone interne Docker ai_network

      • Open WebUI

      • Presidio (anonymisation PII)

      • Ollama (modèles locaux)

      • Promtail

      • Loki

    • 🟢 Zone Administration (Grafana – VPN)

  • Flux réseau principaux (443 / 3000 / Admin)

  • Cartouche RSSI :

    • Segmentation réseau

    • Zero Trust

    • Privacy by Design

    • Modèles non exposés

    • Journalisation souveraine

La règle fondamentale de cette architecture : 

Open WebUI est le seul point d'entrée des utilisateurs (port 3000), Grafana est réservé aux administrateurs (port 3001). Tous les autres ports (Ollama 11434, Loki 3100, Presidio 5001/5002) restent strictement internes au réseau Docker.


2. docker-compose.yml complet et sécurisé.

version: '3.8'

networks:
  ai_network:
    driver: bridge
    internal: false  # Permet l'accès internet pour les mises à jour
    ipam:
      config:
        - subnet: 172.20.0.0/16

volumes:
  ollama_data:
  loki_data:
    driver: local
    driver_opts:
      type: none
      device: /data/loki  # Monter sur un volume chiffré LUKS
      o: bind
  open_webui_data:
  grafana_data:
  presidio_data:

services:

  # ─── COUCHE L1 : INTERFACE UTILISATEUR ─────────────────────────────

  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    container_name: open-webui
    networks: [ai_network]
    ports:
      - "3000:8080"     # SEUL port exposé aux utilisateurs
    environment:
      - OLLAMA_BASE_URL=http://ollama:11434
      - WEBUI_AUTH=true               # Authentification obligatoire
      - WEBUI_SECRET_KEY=${SECRET_KEY} # À définir dans .env
      - DEFAULT_USER_ROLE=user         # RBAC : rôle minimal par défaut
      - ENABLE_SIGNUP=false            # Désactiver l'auto-inscription
      - WEBUI_NAME=UGAIA IA Souveraine
      # Intégration Presidio via pipeline
      - PRESIDIO_ANALYZER_URL=http://presidio-analyzer:3000
    volumes:
      - open_webui_data:/app/backend/data
    depends_on:
      ollama:
        condition: service_healthy
      presidio-analyzer:
        condition: service_started
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
    restart: unless-stopped

  # ─── COUCHE L2 : INFÉRENCE SOUVERAINE ──────────────────────────────

  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    networks: [ai_network]
    # CRITIQUE : PAS de port exposé vers l'hôte
    volumes:
      - ollama_data:/root/.ollama
    environment:
      - OLLAMA_KEEP_ALIVE=24h
      - OLLAMA_NUM_PARALLEL=2
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:11434/api/tags"]
      interval: 30s
      timeout: 10s
      retries: 5
    restart: unless-stopped

  # ─── COUCHE L3 : ANONYMISATION PII (Presidio) ───────────────────────

  presidio-analyzer:
    image: mcr.microsoft.com/presidio-analyzer:latest
    container_name: presidio-analyzer
    networks: [ai_network]
    # PAS de port exposé — uniquement accessible depuis Open WebUI
    restart: unless-stopped

  presidio-anonymizer:
    image: mcr.microsoft.com/presidio-anonymizer:latest
    container_name: presidio-anonymizer
    networks: [ai_network]
    restart: unless-stopped

  # ─── COUCHE L4 : COLLECTE LOGS + PII SCRUBBING ─────────────────────

  promtail:
    image: grafana/promtail:latest
    container_name: promtail
    networks: [ai_network]
    volumes:
      - /var/log:/var/log:ro
      - /var/lib/docker/containers:/docker:ro
      - ./config/promtail-config.yaml:/etc/promtail/config.yaml:ro
    depends_on: [loki]
    restart: unless-stopped

  loki:
    image: grafana/loki:latest
    container_name: loki
    networks: [ai_network]
    # CRITIQUE : PAS de port 3100 exposé vers l'hôte
    volumes:
      - loki_data:/loki
      - ./config/loki-config.yaml:/etc/loki/local-config.yaml:ro
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://localhost:3100/ready"]
      interval: 30s
      timeout: 10s
      retries: 5
    restart: unless-stopped

  # ─── COUCHE L5 : MONITORING & DASHBOARD UGAIA ──────────────────────

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    networks: [ai_network]
    ports:
      - "3001:3000"     # Accès ADMIN uniquement — restreindre par IP si possible
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD}
      - GF_SECURITY_DISABLE_GRAVATAR=true
      - GF_ANALYTICS_REPORTING_ENABLED=false  # Pas de telemetrie externe
      - GF_ANALYTICS_CHECK_FOR_UPDATES=false
      - GF_SERVER_DOMAIN=localhost
      - GF_AUTH_ANONYMOUS_ENABLED=false
      - GF_USERS_ALLOW_SIGN_UP=false
    volumes:
      - grafana_data:/var/lib/grafana
      - ./config/grafana/dashboards:/etc/grafana/provisioning/dashboards:ro
      - ./config/grafana/datasources:/etc/grafana/provisioning/datasources:ro
    depends_on:
      loki:
        condition: service_healthy
    restart: unless-stopped

3. Configuration Promtail avec PII Scrubbing (RGPD Art. 25).

C'est la pièce maîtresse de conformité. Sans ce filtre, des données personnelles transitent vers Loki en clair. Fichier config/promtail-config.yaml :

server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /tmp/positions.yaml

clients:
  - url: http://loki:3100/loki/api/v1/push

scrape_configs:
  - job_name: ollama-containers
    docker_sd_configs:
      - host: unix:///var/run/docker.sock
        refresh_interval: 5s
    relabel_configs:
      - source_labels: [__meta_docker_container_name]
        target_label: container
      - source_labels: [__meta_docker_container_image]
        target_label: image

    # ─── PIPELINE PII SCRUBBING ────────────────────────────────────
    pipeline_stages:
      # 1. Parser les logs JSON d'Ollama
      - json:
          expressions:
            prompt: prompt
            model: model
            duration: total_duration

      # 2. Masquer emails
      - replace:
          expression: '([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})'
          replace: '[EMAIL_REDACTED]'

      # 3. Masquer numéros de téléphone français
      - replace:
          expression: '(\+33|0)[1-9]([0-9]{8})'
          replace: '[PHONE_REDACTED]'

      # 4. Masquer IBAN
      - replace:
          expression: '[A-Z]{2}[0-9]{2}[A-Z0-9]{4}[0-9]{7}([A-Z0-9]?){0,16}'
          replace: '[IBAN_REDACTED]'

      # 5. Masquer NIR (numéro sécurité sociale)
      - replace:
          expression: '[12][0-9]{2}(0[1-9]|1[0-2])[0-9]{8}[0-9]{2}'
          replace: '[NIR_REDACTED]'

      # 6. Labels pour requêtes LogQL dans Grafana
      - labels:
          model:
          container:

      # 7. Timestamp
      - timestamp:
          source: time
          format: RFC3339Nano

4. Configuration Loki avec rétention RGPD.

Fichier config/loki-config.yaml :

auth_enabled: false

server:
  http_listen_port: 3100

ingester:
  lifecycler:
    ring:
      kvstore:
        store: inmemory
      replication_factor: 1

schema_config:
  configs:
    - from: 2024-01-01
      store: boltdb-shipper
      object_store: filesystem
      schema: v11
      index:
        prefix: index_
        period: 24h

storage_config:
  boltdb_shipper:
    active_index_directory: /loki/boltdb-shipper-active
    cache_location: /loki/boltdb-shipper-cache
    shared_store: filesystem
  filesystem:
    directory: /loki/chunks

# ─── RÉTENTION RGPD Art. 5e ─────────────────────────────────────────
limits_config:
  retention_period: 720h    # 30 jours maximum (adapter selon politique DPO)
  ingestion_rate_mb: 4
  max_query_series: 500

compactor:
  working_directory: /loki/compactor
  shared_store: filesystem
  retention_enabled: true   # Active la suppression automatique
  retention_delete_delay: 2h
  retention_delete_worker_count: 150

5. Datasource Grafana → Loki (auto-provisioning).

Fichier config/grafana/datasources/loki.yaml :

apiVersion: 1
datasources:
  - name: Loki
    type: loki
    access: proxy
    url: http://loki:3100
    isDefault: true
    jsonData:
      maxLines: 1000
      timeout: 60

6. Dashboard Grafana — 5 panneaux UGAIA essentiels.

Voici les requêtes LogQL à construire pour votre tableau de bord UGAIA Score en temps réel.

Panneau 1 — Volume de requêtes IA par heure

sum by (model) (
  rate({container="ollama"}[1h])
)

Indicateur de charge et d'utilisation par modèle (Phi-4 vs Mistral).

Panneau 2 — Détections PII par Presidio (taux de conformité)

sum(
  count_over_time({container="presidio-analyzer"} |= "entity_type" [1h])
) by (entity_type)

Affiche le volume et les types d'entités détectées : PERSON, EMAIL, PHONE, IBAN, NIR. Alerte si le volume dépasse un seuil (ex. >100 détections/heure = risque de fuite de données structurelle).

Panneau 3 — Latence P95 des inférences Ollama

quantile_over_time(0.95,
  {container="ollama"} | json | unwrap total_duration [5m]
) by (model)

SLA de performance : alerte si P95 > 10 secondes.

Panneau 4 — Tentatives de prompt injection détectées

count_over_time(
  {container="open-webui"} |= "injection" or |= "jailbreak" or |= "ignore previous" [1h]
)

Indicateur de sécurité critique pour le scoring UGAIA (composante "Protection contre les attaques adversariales").

Panneau 5 — Score de Résilience UGAIA (jauge 0-100)

Ce panneau central agrège les métriques en un score composite. Il se construit via un panneau de type "Stat" avec une expression qui calcule :

  • Loki actif et ingérant : +15 pts
  • Promtail PII scrubbing actif : +20 pts
  • Presidio détections > 0 (preuve d'utilisation) : +15 pts
  • Latence P95 < 10s : +10 pts
  • Zéro erreur d'authentification Open WebUI : +10 pts
  • Rétention Loki configurée ≤30j : +10 pts
  • Alertes actives configurées : +10 pts
  • Aucun port sensible exposé (Ollama/Loki) : +10 pts

7. Sécurisation Open WebUI — Configuration avancée.

Open WebUI joue un rôle clé au-delà d'une simple interface : c'est le point d'application de la politique de gouvernance pour les utilisateurs finaux.

Configuration du System Prompt de gouvernance (à définir dans Open WebUI > Settings > Models) :

Tu es un assistant IA souverain déployé par [Organisation] dans le cadre 
du dispositif UGAIA. Tu opères dans un environnement conforme RGPD.

RÈGLES ABSOLUES :
- Ne jamais demander ni stocker de données personnelles (NIR, IBAN, données médicales).
- Ne jamais transmettre d'informations vers des systèmes externes.
- Si l'utilisateur semble partager des PII, l'informer que ces données 
  sont automatiquement anonymisées avant traitement.
- Toutes tes réponses sont journalisées à des fins d'audit UGAIA.

Classification des données autorisées : N1 (public) et N2 (interne).
Pour les données N3/N4, contacter le DPO.

Pop-up de consentement au premier login : configurer via Open WebUI > Admin > Banners un message imposant l'acceptation de la charte d'usage UGAIA avant accès. Cela constitue une preuve de consentement exploitable en audit.

RBAC recommandé dans Open WebUI :

Rôle Permissions Modèles accessibles
user Chat uniquement Phi-4, Mistral (données N1/N2)
power_user RAG + fichiers + modèles spécialisés
admin Gestion complète Tous les modèles
auditor (lecture seule) Historique conversations Aucun

8. Alertes Grafana — 3 alertes critiques UGAIA.

Alerte 1 — PII non scrubées détectées dans Loki

# Si des emails passent le scrubbing → défaillance critique
count_over_time(
  {container="loki"} |~ "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}" [5m]
) > 0

Sévérité : CRITIQUE — notification immédiate DPO + RSSI.

Alerte 2 — Ollama injoignable depuis Open WebUI

absent(rate({container="ollama"}[5m])) == 1

Sévérité : HAUTE — indisponibilité de service.

Alerte 3 — Volume anormal de détections PII

sum(count_over_time({container="presidio-analyzer"} [1h])) > 500

Sévérité : MOYENNE — possible tentative de fuite de données massives.


9. Impact sur le Score UGAIA.

Composant Score avant Score après intégration complète
Open WebUI (RBAC + SSO + System Prompt) 14/20 18/20
Grafana (Dashboard UGAIA + alertes) 13/20 18/20
Promtail (PII scrubbing actif) 12/20 17/20
Loki (rétention RGPD configurée) 15/20 17/20
Ollama (métriques exposées) 16/20 17/20
Docker (réseau isolé) 13/20 16/20
SCORE TOTAL 73/100 ≥ 85/100 ✅ SOUVERAIN+

10. Plan d'implémentation en 3 sprints.

Sprint 1 (Semaine 1-2) — Fondation sécurisée
Déployer le docker-compose.yml avec réseau isolé + activer PII scrubbing Promtail + configurer la rétention Loki 30j + activer RBAC Open WebUI. Gain : +12 pts → 85/100.

Sprint 2 (Semaine 3-4) — Dashboard et alertes
Construire les 5 panneaux Grafana UGAIA Score + configurer les 3 alertes critiques + ajouter le System Prompt de gouvernance Open WebUI + bannière consentement. Gain : observabilité complète, preuve d'audit ≤48h.

Sprint 3 (Semaine 5-6) — Corrélation et traçabilité EU AI Act
Intégrer Langfuse avec mlflow_run_id comme clé pivot + relier les traces Langfuse au dashboard Grafana + documenter la procédure Droit à l'effacement (Loki Delete API) pour le DPO. Gain : conformité EU AI Act Art. 12 complète.

Le résultat est une architecture où chaque interaction utilisateur via Open WebUI génère une trace complète et auditée dans Grafana, sans qu'aucune donnée personnelle ne soit exposée dans les logs, tout en maintenant une souveraineté totale sur l'ensemble de la pile.