Aller au contenu principal

Connecteur de bases de données (optionnel)

Composant optionnel

Le connecteur de bases de données est optionnel et désactivé par défaut. Avatar fonctionne entièrement sans lui : les jeux de données envoyés sous forme de fichiers (CSV, Parquet) sont anonymisés comme d'habitude. Activez-le uniquement si vos utilisateurs ont besoin des exécutions sur base de données.

Les exécutions sur base de données lisent une base de données et écrivent la copie anonymisée dans une autre base. Les workers qui exécutent les jobs n'ouvrent pas eux-mêmes ces bases. Un service séparé, le connecteur de bases de données, contient tous les pilotes de bases de données et ouvre les bases. L'API conserve les chaînes de connexion ; le connecteur n'en reçoit une que le temps d'un job ; les workers n'en voient jamais aucune.

Cette page explique comment activer le connecteur sur une installation Kubernetes. Le connecteur est désactivé par défaut. Sans lui, les exécutions sur base de données n'atteignent aucune base, PostgreSQL compris, et les bases de démonstration ne sont pas proposées.

Docker Compose

L'outil de déploiement pour Docker Compose n'installe pas encore le connecteur. Pour utiliser les exécutions sur base de données sur une installation Docker Compose, contactez le support Octopize.

Fonctionnement​

worker ── short-lived token ──▶ connector ──▶ your database
│
└── "what does this name mean?" ──▶ API (internal port)
  • Un job porte le nom d'une connexion et un jeton signé par l'API. Le jeton est valable pour une connexion, pour un utilisateur, et pour une durée limitée.
  • Le connecteur vérifie le jeton, puis demande à l'API la chaîne de connexion sur un port interne. Ce port est servi par son propre Service (avatar-api-internal), auquel aucun Ingress ne fait référence, et une network policy le réserve au connecteur. Le port public de l'API ne sert pas cette route.
  • Le connecteur garde la chaîne de connexion en mémoire pendant 30 secondes. Il n'écrit rien sur le disque.
  • Les lignes vont de votre base de données vers le stockage objet du job. Elles ne passent pas par l'API.
  • Le connecteur n'a pas de point d'accès de requête. Il liste la structure d'une base de données, lit des tables, écrit dans des tables qui existent déjà dans une cible, et supprime les lignes des tables qu'une exécution nomme. Il ne crée pas de tables : la cible doit déjà posséder le schéma. Les messages d'erreur donnent une catégorie (par exemple la base de données a refusé les identifiants), jamais un hôte ni un identifiant.

Moteurs pris en charge​

MoteurChaîne de connexionStatut
PostgreSQLpostgresql://user:password@host:5432/databasepris en charge
MySQLmysql://user:password@host:3306/databasepris en charge
MariaDBmariadb://user:password@host:3306/databasepris en charge
Oracleoracle://user:password@host:1521/SERVICE_NAMEpris en charge (pilote thin, sans client Oracle)
SQL Servermssql://user:password@host:1433/databasepris en charge
ClickHouseclickhouse://user:password@host:8123/databasepris en charge (ajoutez ?secure=true pour 8443)
MongoDBmongodb://… ou mongodb+srv://…pris en charge (collections lues comme des tables)
Snowflakesnowflake://user:password@account/database/schema?warehouse=…&role=…aperçu
Google BigQuerybigquery://project/dataset?credentials_base64=…aperçu, lecture seule (source uniquement)
IBM Db2db2://user:password@host:50000/databaseaperçu, absent de l'image publiée

Un moteur en aperçu est proposé, mais il n'a pas encore été validé sur un vrai serveur. L'application web le marque comme aperçu. Le connecteur indique à l'API les moteurs dont il embarque le pilote, et l'API ne propose que ceux-là.

IBM Db2 a besoin d'un pilote qui ajoute 135 Mo et ne fonctionne que sur amd64 : l'image publiée ne l'inclut donc pas. Pour proposer Db2, construisez vous-même l'image depuis les sources du connecteur avec --build-arg WITH_DB2=1 --platform linux/amd64, ou contactez le support Octopize.

L'image contient aussi deux petites bases de démonstration (Northwind et Chinook). Vos utilisateurs peuvent les ajouter depuis Compte > Connexions aux bases de données et essayer une exécution sur base de données avant de connecter leurs propres bases. Une copie d'une cible de démonstration est supprimée 24 heures après sa dernière écriture, et quand le connecteur redémarre.

Avant de commencer​

  • Version 0.0.100 du chart ou ultérieure. La version 0.0.99 a ajouté le connecteur, et la 0.0.100 a corrigé son secret de pull d'image.
  • Version 3.18.0 de l'API ou ultérieure. C'est la première version avec le port interne auquel le connecteur demande les chaînes de connexion.
  • Network policies. Le chart refuse de générer le connecteur tant que networkPolicy.enabled ne vaut pas true, car seules les network policies empêchent le connecteur d'atteindre le reste du cluster. Votre cluster a besoin d'un CNI qui applique les NetworkPolicy, comme Calico ou Cilium.
  • Accès à l'image. L'image quay.io/octopize/avatar-connector est privée. Le chart la tire avec les mêmes identifiants de pull d'images que les autres images Avatar.

Activer le connecteur​

1. Générer les secrets​

Le connecteur a besoin de deux secrets :

  • connector.secret : partagé par l'API et le connecteur. Il signe les jetons que portent les jobs, et le connecteur s'authentifie auprès de l'API avec lui.
  • databaseConnections.encryptionKeys : la clé Fernet qui chiffre les connexions que vos utilisateurs et vos organisations enregistrent. Sans elle, les utilisateurs ne peuvent pas enregistrer leurs propres connexions (l'API répond 503), mais les connexions de déploiement fonctionnent toujours.

scripts/generate-secrets.sh crée les deux, avec les autres secrets du chart. Voir Générer les secrets. Pour les fabriquer vous-même :

# connector.secret
python -c "import secrets; print(secrets.token_hex(), end='')"
# databaseConnections.encryptionKeys
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode(), end='')"

Utiliser un gestionnaire de clés au lieu d'une clé Fernet​

L'API peut chiffrer les connexions enregistrées avec une clé dans un gestionnaire de clés compatible KMS (AWS KMS, ou un service compatible comme Scaleway Key Manager) au lieu d'une clé Fernet. L'API ne détient jamais cette clé : chaque connexion reçoit sa propre clé de données, que seul le gestionnaire de clés peut déchiffrer, et chaque déchiffrement est soumis à la politique et à la piste d'audit de la clé. Le chart n'a pas encore de valeurs pour cela ; réglez les variables d'environnement de l'API via api.extraEnvVars :

VariableValeur
CONNECTION_CIPHERaws_kms. Choisie automatiquement quand CONNECTION_KMS_KEY_ID est définie
CONNECTION_KMS_KEY_IDL'ID, l'ARN ou l'alias de la clé
CONNECTION_KMS_REGIONLa région de la clé
CONNECTION_KMS_ENDPOINT_URLLe point d'accès d'un service compatible KMS. Laissez-la non définie pour AWS
CONNECTION_KMS_ACCESS_KEY_ID, CONNECTION_KMS_SECRET_ACCESS_KEYFacultatives. Sans elles, l'API utilise la chaîne d'identifiants AWS standard

Les connexions déjà enregistrées avec une clé Fernet restent lisibles tant que cette clé reste définie : vous pouvez donc passer de l'une à l'autre.

Fournir vos propres Secrets​

Si vous fournissez vos propres Secrets Kubernetes, utilisez connector.existingSecret (clé connector-secret) et databaseConnections.existingSecret (clés database-connections et connection-encryption-keys). Changez les noms des clés avec connector.secretKeys.* et databaseConnections.secretKeys.*.

2. Activer le connecteur​

Ajoutez ceci à votre fichier de valeurs. Fixez le tag de l'image : le chart refuse de générer quand connector.image.tag et connector.image.digest sont tous deux vides.

networkPolicy:
enabled: true

connector:
enabled: true
image:
tag: "0.4.0"

Puis mettez à jour la release :

helm upgrade avatar <chart> --values my-values.yaml --values avatar-secrets.yaml

Le chart lance alors le connecteur, ouvre le port interne de l'API et ajoute les network policies entre les deux.

3. Permettre au connecteur d'atteindre vos bases de données​

Le connecteur a sa propre network policy. Par défaut, il peut atteindre :

  • le DNS ;
  • le port interne de l'API ;
  • le SeaweedFS intégré au chart, quand il est activé ;
  • l'internet public, sauf les plages privées, partagées, link-local et loopback (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 100.64.0.0/10, 169.254.0.0/16, 127.0.0.0/8).

Une base de données à une adresse publique fonctionne sans aucun changement. Une base de données sur un réseau privé (derrière un VPN ou un peering) a besoin que son réseau figure dans allowedDatabaseCIDRs :

connector:
networkPolicy:
allowedDatabaseCIDRs:
- 10.20.0.0/16

Un stockage objet externe à une adresse privée doit aussi y figurer, car le connecteur écrit les tables qu'il lit dans le stockage objet du job.

Si vos pods DNS ou vos pods de stockage objet ne portent pas les labels par défaut, réglez connector.networkPolicy.dnsSelector (par défaut k8s-app: kube-dns) et connector.networkPolicy.storageSelector (par défaut app.kubernetes.io/name: seaweedfs, app.kubernetes.io/component: s3).

4. Vérifier que cela fonctionne​

Connectez-vous à l'application web avec n'importe quel utilisateur, allez dans Compte > Connexions aux bases de données, cliquez sur Ajouter les connexions de démonstration, puis sur Tester à côté de la source de démonstration. Si le test indique que la base de données est joignable, l'API, le connecteur et les network policies fonctionnent ensemble. Créez ensuite une connexion de test vers l'une de vos propres bases de données.

Déclarer des connexions pour tous les utilisateurs (facultatif)​

Les utilisateurs peuvent enregistrer leurs propres connexions depuis l'application web ou le client Python. Vous pouvez aussi déclarer des connexions pour tout le déploiement. Chaque utilisateur les voit, et personne ne peut les modifier depuis l'application :

databaseConnections:
connections:
- name: crm-prod
label: CRM (production)
dsn: "postgresql://avatar_reader:<password>@crm.internal:5432/crm"
- name: crm-test
label: CRM (test)
dsn: "postgresql://avatar_writer:<password>@crm-test.internal:5432/crm"

Chaque entrée a un name, un dsn au format de Moteurs pris en charge, et un label facultatif, qui est ce que les utilisateurs voient dans les sélecteurs.

Ces valeurs contiennent des mots de passe. Conservez-les dans un Secret Kubernetes (databaseConnections.existingSecret, clé database-connections, sous forme de liste JSON) plutôt que dans un fichier de valeurs.

Les workers lisent le Secret de l'API par son nom

Les workers lisent les connexions de déploiement dans le Secret api, clé database_connections. Un Secret nommé dans databaseConnections.existingSecret ne les atteint pas à lui seul : faites aussi pointer l'entrée DATABASE_CONNECTIONS de dask.worker.env vers lui.

Donnez à la source un rôle qui peut seulement lire. Donnez à la cible un rôle qui peut écrire et supprimer des lignes. La cible doit déjà posséder le schéma : l'exécution ne crée pas de tables.

Autres paramètres​

ValeurDéfautDescription
connector.replicaCount1Nombre de pods du connecteur. Le connecteur est sans état : vous pouvez le mettre à l'échelle librement.
connector.tokenTtlSeconds21600Durée de validité du jeton d'un job. Choisissez une valeur plus longue que votre job le plus long.
connector.storageEndpoints[]Adresses host:port vers lesquelles le connecteur peut écrire les tables extraites. Vide : toutes autorisées. Nous recommandons le host:port de votre stockage objet, tel que les workers le nomment.
connector.internalPort8001Port interne de l'API auquel le connecteur demande les chaînes de connexion. Doit différer de api.containerPort.
connector.containerPort8080Port sur lequel le connecteur écoute. Son Service est toujours ClusterIP.
connector.resourcesrequests 250m / 512 MiB, limits 2 CPU / 2 GiBRessources de calcul du conteneur du connecteur.
connector.extraEnvVars[]Variables d'environnement supplémentaires du conteneur du connecteur.
connector.nodeSelector, tolerations, affinity, podAnnotations, podLabelsvidePlanification et métadonnées des pods du connecteur.

Le connecteur s'exécute avec un utilisateur non root (UID 10001) et un système de fichiers racine en lecture seule. La liste complète des valeurs connector.* et databaseConnections.* se trouve dans le README.md du chart.

Faire la rotation des secrets​

  • connector.secret : quand vous le changez, les jetons des jobs en cours deviennent invalides. Faites la rotation quand aucun job de base de données ne tourne.
  • databaseConnections.encryptionKeys : une liste séparée par des virgules. La première clé chiffre, et toutes les clés déchiffrent. Placez la nouvelle clé en premier, attendez que chaque connexion enregistrée soit réécrite, puis retirez l'ancienne clé.