Inventaire DPIA — flux de données personnelles dans AKKO¶
Qui est responsable du DPIA ? L'opérateur AKKO (le client) est responsable du traitement et doit déposer le DPIA auprès de son DPO. AKKO en tant qu'éditeur de plateforme fournit cet inventaire pour que le responsable de traitement sache exactement quelles données les composants AKKO touchent — sans avoir à reconstituer l'information à partir des logs.
Déclenchement — RGPD Art. 35(1) impose un DPIA quand « un type de traitement est susceptible d'engendrer un risque élevé pour les droits et libertés des personnes physiques ». Une plateforme comme AKKO qui ingère l'activité d'utilisateurs authentifiés, fédère des requêtes sur plusieurs sources, et exécute des agents LLM sur du contenu fourni par les utilisateurs franchit typiquement ce seuil.
Lecture de l'inventaire¶
Chaque ligne est un flux de données personnelles distinct. Colonnes :
| Colonne | Sens |
|---|---|
| Composant | Le service AKKO qui détient la donnée |
| Catégorie | RGPD Art. 4(1) — type de donnée personnelle |
| Personne concernée | À qui la donnée appartient (employé / client / utilisateur final) |
| Stockage | Où elle atterrit physiquement |
| Conservation | Durée par défaut de la plateforme |
| Base légale | Base par défaut quand AKKO est utilisé tel que conçu (le responsable peut surcharger) |
| Mesure de sécurité | Mesure technique/organisationnelle qui mitige le risque |
Les valeurs par défaut sont la configuration prête à l'emploi. Le responsable de traitement peut durcir la conservation ou changer la base légale via les runbooks listés en Références en bas.
1 — Authentification & identité¶
| Composant | Catégorie | Personne | Stockage | Conservation | Base légale | Sécurité |
|---|---|---|---|---|---|---|
| Keycloak (akko-keycloak) | Email, prénom/nom, appartenance aux groupes, hash mot de passe (bcrypt), secrets OTP | Employé, partenaire | DB PostgreSQL keycloak |
Jusqu'à suppression du compte | Contrat (Art. 6(1)(b)) — nécessaire pour authentifier | Bcrypt, TOTP optionnel, SSO, log d'audit |
| directory service / 389-DS (akko-directory) | Idem Keycloak quand fédéré | Employé | Backend LDAP | Jusqu'à suppression | Contrat | TLS 1.3, RBAC |
| Cookie de session oauth2-proxy | ID de session chiffré, ID token OIDC (claims : sub, email, groups, exp) | Utilisateur authentifié | Cookie navigateur + Redis | Durée de vie cookie (8h par défaut) | Contrat | Cookie AES-GCM, Secure, HttpOnly, SameSite=Lax |
2 — Activité & logs d'audit¶
| Composant | Catégorie | Personne | Stockage | Conservation | Base légale | Sécurité |
|---|---|---|---|---|---|---|
| Logs de décision OPA | ID utilisateur, rôle, ressource demandée, décision, horodatage | Utilisateur authentifié | Stream decision_logs logs layer |
90 jours par défaut | Intérêt légitime (Art. 6(1)(f)) — audit sécurité | Append-only, accès restreint via cockpit |
| Événements admin Keycloak | ID admin, ID cible, action (create/delete/changement de rôle), horodatage | Admin + cible | PostgreSQL keycloak.admin_events |
90 jours par défaut | Obligation légale (Art. 6(1)(c)) — DORA Art. 11 / NIS2 Art. 21 | Tamper-evident, accès restreint |
| Log de requêtes Trino | ID utilisateur, texte SQL, IP source, horodatage, octets scannés | Utilisateur authentifié | OPA → stream trino_queries logs layer |
90 jours par défaut | Intérêt légitime — audit, capacity planning | Le texte SQL peut contenir des données personnelles si l'utilisateur SELECT depuis des colonnes PII ; gating via row-filters OPA |
| Log d'audit Airflow | ID utilisateur lançant le DAG, instance de tâche, horodatage | Opérateur | PostgreSQL airflow.log |
30 jours par défaut | Obligation légale | UI à accès restreint |
| Log d'accès cockpit | ID utilisateur, page visitée, horodatage | Utilisateur authentifié | Log nginx → logs layer | 30 jours par défaut | Intérêt légitime | Agrégé pour stats d'usage |
3 — Contenu fourni par l'utilisateur¶
| Composant | Catégorie | Personne | Stockage | Conservation | Base légale | Sécurité |
|---|---|---|---|---|---|---|
| Documents akko-rag uploadés | Texte du document + embeddings (pgvector) ; nom de fichier, ID utilisateur uploader | Clients/contrats de l'uploader (potentiellement) | PostgreSQL akko_rag.documents + SeaweedFS akko-rag/originals/ |
Pas de suppression automatique — pilotée par l'opérateur | Consentement (Art. 6(1)(a)) si l'utilisateur final upload via UI ; sinon contrat | TLS en transit, chiffrement colonne pgcrypto disponible, gate OPA sur /query |
| Questions ADEN en langage naturel | Texte de la question, ID utilisateur, horodatage | Utilisateur authentifié | PostgreSQL aden.questions |
30 jours par défaut | Intérêt légitime — amélioration du modèle | L'opérateur peut désactiver via aden.persistQuestions=false |
| Dashboards ADEN | JSON dashboard (peut contenir texte SQL + ID utilisateur) | Utilisateur authentifié | SeaweedFS aden/dashboards/ |
Jusqu'à suppression utilisateur | Intérêt légitime | Gating OPA, URLs signées |
| Sorties de notebooks | Texte/images de cellules (peuvent inclure des données personnelles imprimées) | Propriétaire du notebook | PVC JupyterHub | Pilotée par l'opérateur | Consentement | PVC par utilisateur, pas de lecture cross-user |
| Expériences MLflow | Auteur, paramètres de run, métriques, URI d'artefacts | Utilisateur authentifié | PostgreSQL mlflow + SeaweedFS mlflow/ |
Pilotée par l'opérateur | Contrat | Accès restreint via Keycloak |
4 — Traitement médié par LLM¶
| Composant | Catégorie | Personne | Stockage | Conservation | Base légale | Sécurité |
|---|---|---|---|---|---|---|
| Gateway LiteLLM | Prompts + complétions routés | Utilisateur authentifié | En mémoire seulement par défaut ; log optionnel vers logs layer | 0 (pas de persistance) par défaut | Contrat | TLS vers Ollama upstream ; aucun appel API externe par défaut — souverain |
| Ollama (akko-llm) | Idem | Idem | En mémoire seulement | 0 | Contrat | Air-gapped — modèle tourne sur GPU/CPU local |
| Trace de raisonnement ADEN | Entrées/sorties d'étapes pipeline, contexte récupéré, SQL généré | Utilisateur authentifié | PostgreSQL aden.reasoning |
30 jours par défaut | Intérêt légitime — explicabilité (Sprint 41) | Conservation pilotée par l'opérateur ; l'utilisateur peut purger sa trace |
5 — Lac de données & entrepôt¶
| Composant | Catégorie | Personne | Stockage | Conservation | Base légale | Sécurité |
|---|---|---|---|---|---|---|
| Stockage objet SeaweedFS | Tout ce que le client ingère (peut inclure des PII) | Personnes concernées du client | Volumes SeaweedFS | Pilotée par l'opérateur | Définie par le client | Chiffrement volume optionnel (-volume.encrypted=true — Sprint 52 P1) |
PostgreSQL akko_data |
Idem | Idem | DB PostgreSQL data | Pilotée par l'opérateur | Définie par le client | Chiffrement colonne pgcrypto disponible |
| Tables Iceberg (Polaris) | Idem | Idem | SeaweedFS iceberg/ |
Pilotée par l'opérateur | Définie par le client | Politiques OPA row/column via Trino |
| Catalogue OpenMetadata | Tags + descriptions de datasets (pas de données ligne) | — | PostgreSQL openmetadata + OpenSearch |
Pilotée par l'opérateur | — | Métadonnées seulement, pas de corps PII |
Comment traiter une demande d'accès (RGPD Art. 15)¶
Lancer depuis le namespace akko-aden où le bot du responsable a un
accès lecture sur tous les sous-systèmes. L'helper dsr.sh est livré à
scripts/dsr.sh et produit un bundle JSON unique pour l'utilisateur.
# Identifier l'utilisateur (userId Keycloak, pas l'email — les emails changent)
USER_ID=$(curl -s -H "Authorization: Bearer $ADMIN_TOKEN" \
"https://identity.akko-ai.com/admin/realms/akko/users?email=user@exemple.com" \
| jq -r '.[0].id')
# Bundle de tous les flux pour cet utilisateur
bash scripts/dsr.sh "$USER_ID" > dsr-$USER_ID.json
Le bundle couvre identité Keycloak + décisions OPA + requêtes Trino + runs Airflow + questions ADEN + expériences MLflow + listing PVC notebook + documents RAG uploadés. À remettre au demandeur dans le délai légal d'un mois.
Comment traiter un droit à l'effacement (RGPD Art. 17)¶
Même périmètre que le bundle, mais la suppression nécessite l'accord de l'opérateur car certains enregistrements sont soumis à conservation légale (ex : DORA Art. 11 impose la conservation des logs d'audit même après effacement par la personne concernée). Le script émet un plan de suppression ; l'opérateur valide ; le script exécute par composant, avec une tombstone écrite dans le log d'audit.
bash scripts/erasure.sh "$USER_ID" --dry-run # plan seulement
bash scripts/erasure.sh "$USER_ID" --execute # après validation
Transferts hors UE¶
AKKO est souverain par construction — aucun service ne fait d'appel
HTTPS sortant en déploiement par défaut. Le responsable peut le vérifier
en inspectant les NetworkPolicies (kubectl get netpol -n akko) — seul
le trafic ingress Traefik et intra-namespace est autorisé ; l'egress
vers Internet public est bloqué sauf activation explicite (ex : forwarding
SIEM, documenté dans SIEM forwarder).
Si l'opérateur active une cible SIEM externe (Splunk Cloud, Sentinel, Elastic Cloud), l'activation est elle-même un transfert et l'opérateur doit l'ajouter à ses addenda DPIA avec la base légale choisie (CCT / adéquation).
Addendum Sprint 59 — flows ADEN ADR-041/042/043¶
Le refactor ADEN du Sprint 59 introduit trois nouveaux flows internes. Aucun ne touche aux PII de l'utilisateur — ils raisonnent uniquement sur les métadonnées de tables + le rôle de l'appelant — mais le DPO du contrôleur doit savoir qu'ils existent et où vivent les données.
| Flow | Composant | Catégorie de données | Stockage | Rétention | Base légale |
|---|---|---|---|---|---|
| ADR-041 OPA scope-first batch | OPA + ADEN routes_query.py |
Rôle Keycloak de l'appelant + liste de FQN candidats catalogue.schéma.table (aucune donnée de ligne) |
Mémoire process uniquement | Per-requête, jamais persisté | Intérêt légitime (Art. 6(1)(f)) — enforcement d'accès |
| ADR-042 cache sémantique Tier 2 | ADEN cache_layers.py (LRU in-process) |
Texte de question → embedding 768-d + clé cache 32-char. Même partition rôle/modèle. | Mémoire process uniquement (pas de PVC, pas de Postgres) | TTL 1 h, max 512 entrées par rôle/modèle | Intérêt légitime — optimisation perf. Bypass via body.force=true ou pod restart. |
| ADR-043 catalogue sémantique Milvus | akko-milvus (off par défaut) |
Descriptions de tables + noms de colonnes + embeddings 768-d — aucune donnée de ligne | PVC StatefulSet, in-cluster uniquement | Jusqu'au prochain run du CronJob aden-catalog-indexer (par défaut horaire) |
Intérêt légitime — recherche catalogue sémantique |
Notes pour le contrôleur :
- Le contenu du cache ADR-042 peut inclure des questions utilisateur
(le prompt lui-même). Quand les questions contiennent des données
personnelles ("affiche les transactions du client X"), l'embedding
n'est réversible qu'avec le même modèle
nomic-embed-text-v2— mais le texte de la question est aussi conservé assez longtemps pour construire la clé cache. À traiter comme données personnelles. Le RTBF est honoré par le TTL et parkubectl rollout restart deploy/akko-akko-aden. - ADR-043 Milvus stocke des métadonnées de schéma, pas de lignes.
Lister les noms de tables et de colonnes d'une banque n'est pas en
soi une donnée personnelle, mais le contrôleur peut tout de même
vouloir évaluer la sensibilité (par ex. une table nommée
cessations_clients_2026est révélatrice par elle-même). - Les trois flows respectent
allowed_tablesADR-041 — un cache hit d'un viewer ne peut jamais être servi à un admin et inversement (bucketing par (rôle, modèle)). Le write path applique aussiremember_semanticavec le rôle de l'appelant — prouvé partests/test_cache_layers.py::test_semantic_cache_role_partition.
Références¶
- Matrice de conformité — mapping DORA / NIS2 / RGPD
- Audit playbook — extraction du trail d'audit
- Audit trail — forme des logs et contrôles de rétention
- SIEM forwarder — intégration SIEM tiers
- Chiffrement au repos — pgcrypto + chiffrement volume SeaweedFS
- DR playbook — procédures de récupération (DORA Art. 11)
- RGPD Art. 35 — déclenchement DPIA
- Manuel ENISA « Sécurité du traitement des données personnelles » — guidance technique