Sécurité
Nous considérons la sécurité comme un prérequis critique pour toutes nos fonctionnalités. Nous suivons des pratiques de sécurité dès la conception (security-by-design).
Vous trouverez ci-dessous un schéma d'architecture orienté sécurité. Pour plus de détails, voir Architecture
En pointillés : le connecteur de bases de données, optionnel, nécessaire uniquement pour les exécutions sur base de données. Il est désactivé par défaut.
Concernant la confidentialité :
- Tout le trafic transite via un transport chiffré (HTTPS). Nous utilisons Nginx pour offrir une sécurité de premier ordre (gestion configurable des certificats TLS, sécurité mémoire, pile TLS renforcée).
- À ce jour, Nginx termine la connexion HTTPS, ce qui signifie que le trafic entre Nginx et le serveur API utilise HTTP. Cela peut être basculé en HTTPS si nécessaire.
- Pour un déploiement sur site, vous pouvez fournir vos propres certificats TLS.
Pour permettre la gestion de très grands jeux de données, les chargements et téléchargements de données se font via des points de terminaison S3 dédiés. Une demande d'autorisation spécifique doit être effectuée pour la lecture et l'écriture sur ce point de terminaison.
- Tous les fichiers (originaux et avatars) sont conservés pendant la durée de rétention configurée (TTL) puis supprimés automatiquement.
Authentification et autorisation des utilisateurs
Toutes les actions des utilisateurs sont authentifiées, enregistrées et peuvent être auditées.
- L'authentification nécessite un nom d'utilisateur et un mot de passe valides. Les mots de passe sont stockés de manière sécurisée (algorithme de hachage sécurisé avec un sel unique par mot de passe + un "pepper" secret pour l'ensemble du code).
- Nous utilisons des JWT pour le mécanisme d'authentification. Ils expirent après une durée configurable, par défaut 1 heure. Pour plus d'informations sur les JWT, consultez jwt.io.
- Deux rôles sont supportés :
AdminetUser. - Les principaux flux d'authentification sont soumis à un contrôle de débit (rate limiting).
Flux typiques de données d'utilisation
Voici un flux de données typique :
- L'utilisateur se connecte à l'API (via un client HTTPS direct ou l'une de nos bibliothèques clientes) et reçoit un JWT temporaire pour les requêtes suivantes.
- L'utilisateur télécharge les jeux de données (CSV, parquet) contenant des données pseudonymisées vers l'API Avatars, généralement via l'une de nos bibliothèques clientes (web, python). Ce transfert est chiffré en transit via HTTPS.
- Le fichier est stocké chiffré au repos.
- Les métadonnées non sensibles sont stockées dans la base PostgreSQL (par exemple, le hash du jeu de données).
- Le fichier sera supprimé après une durée configurable (voir ci-dessus).
- L'utilisateur peut lancer plusieurs traitements d'anonymisation sur un jeu de données donné. Il peut télécharger le jeu de données avatar (toujours via HTTPS) sur sa machine pour une analyse ultérieure.
- Le jeu de données avatar sera supprimé après une durée configurable (voir ci-dessus).
- Le jeu de données original ne peut pas être téléchargé, même par l'utilisateur lui-même.
Une exécution sur base de données lit ses données dans une base de données plutôt que dans un fichier :
- L'utilisateur choisit une source et une cible parmi les connexions conservées par Avatar. Le job porte leurs noms, jamais un mot de passe.
- Le worker remet un jeton de courte durée au connecteur de bases de données, qui lit les tables source et les écrit directement dans le stockage objet du job. Les lignes ne passent pas par l'API.
- Les tables anonymisées sont écrites dans la base de données cible, par le connecteur. Il ne reste rien à télécharger, et les fichiers du job suivent la durée de rétention habituelle.
Connexions aux bases de données
Les exécutions sur base de données ont besoin d'identifiants pour vos bases de données. Ils sont gérés de sorte qu'aucun job, aucun worker et aucun utilisateur ne puisse les relire :
- Identifiants en écriture seule. Le mot de passe d'une connexion est envoyé une fois, puis jamais renvoyé : ni par l'API, ni par le client web, ni dans un job. Une liste n'affiche que l'hôte et le nom de la base de données.
- Chiffrés au repos. L'API stocke chaque connexion chiffrée, avec une clé conservée hors de sa base de données : un dump de la base, à lui seul, n'ouvre rien. La clé est soit une clé Fernet issue des secrets du déploiement, soit une clé dans un gestionnaire de clés compatible KMS (AWS KMS, Scaleway Key Manager) que l'API ne détient jamais. Avec KMS, chaque connexion est liée à son organisation et à son nom : une valeur copiée dans une autre ligne est refusée.
- Avec une portée. Une connexion appartient à un utilisateur, à une organisation ou au déploiement. Voir Portée des connexions.
- Les workers ne détiennent jamais de mot de passe. Un job porte le nom d'une connexion et un jeton signé par l'API, valable pour cette connexion, pour cet utilisateur et pour une durée limitée (6 heures par défaut).
- Un seul composant détient les pilotes. Seul le connecteur de bases de données ouvre vos bases. Il demande à l'API la chaîne de connexion sur un port interne que le port public ne sert pas, auquel aucun Ingress ne fait référence, et qu'une network policy réserve au connecteur. Il garde la chaîne en mémoire pendant 30 secondes et n'écrit rien sur le disque.
- Pas de point d'accès de requête. Le connecteur liste un schéma, lit des tables, écrit dans des tables existantes d'une cible, et supprime les lignes des tables qu'une exécution nomme. Il ne supprime jamais une table, et n'exécute aucune requête écrite par un utilisateur. Ses messages d'erreur donnent une catégorie, jamais un hôte ni un identifiant.
- Réseau cloisonné. Le connecteur n'est jamais exposé hors du cluster. Sa network policy lui permet d'atteindre le DNS, le port interne de l'API, le stockage objet et l'internet public, mais pas les réseaux privés du cluster, la base de données de la plateforme ni le service de métadonnées du cloud. Une base de données sur un réseau privé doit être autorisée explicitement, réseau par réseau.
De votre côté, donnez à la connexion source un rôle de base de données qui peut seulement lire, donnez à la cible un rôle qui peut seulement écrire et supprimer des lignes, et ne pointez jamais une cible vers une base de production.
Flux réseau
Les utilisateurs accèdent à la plateforme par un unique port entrant, 443 (HTTPS), pour le client web, l'API, l'authentification unique (SSO) et les transferts de jeux de données. Les flux sortants sont listés dans les Prérequis. Quand le connecteur de bases de données est activé, il ouvre aussi des connexions vers les bases de données auxquelles vos utilisateurs se connectent. Les flux optionnels, et exactement ce qu'ils envoient, sont décrits dans Données envoyées à Octopize. Tous peuvent être désactivés pour un déploiement isolé (air-gapped).
Limites de sécurité
Les limites globales suivantes peuvent être configurées pour protéger l'API :
- Taille maximale du corps de la requête : 1 Go (pour l'envoi de jeux de données).
- Limite globale de débit : 1 requête toutes les 100 ms par client et par point de terminaison.
Qu'est-ce qui est installé sur les postes utilisateurs ?
L'utilisateur final n'installe qu'une bibliothèque cliente pour son langage de programmation (par exemple Python) afin de faciliter l'utilisation de l'API Avatar.
Ces bibliothèques sont open source et auditées par analyse statique :
Que sauvegarder ?
Sauvegardez les bases PostgreSQL (celle d'Avatar et celle d'Authentik : utilisateurs et
métadonnées) et les secrets du déploiement, y compris la clé de chiffrement du stockage et, si
vous utilisez les exécutions sur base de données, la clé qui chiffre les connexions enregistrées
(databaseConnections.encryptionKeys). Sans cette clé, chaque connexion enregistrée est illisible
et doit être saisie à nouveau. Voir Sauvegarde.
Le stockage de fichiers est temporaire et n'est pas destiné à conserver les données. Une fois anonymisé, le jeu de données avatar doit être téléchargé et stocké ailleurs.
Pratiques de développement
Nous suivons les meilleures pratiques pour construire des logiciels sécurisés dès la conception :
- Relectures de code
- Analyse statique du code (avec
bandit) - Analyse automatisée des dépendances (avec
dependabotetquay.io) - Intégration continue
- Tests automatisés et manuels (nous surveillons la couverture de code)
- Formation continue des développeurs
- Veille sur les menaces
- Notre organisation Github impose la 2FA et la signature des commits.