Pointez MeetingBaaS vers un stockage objet qui vous appartient et chaque enregistrement, transcription, chunk audio et log y atterrit à la place. Deux jeux d'identifiants, une vraie vérification d'accès, et un compte rendu honnête de ce que vous y perdez.

"Où vit l'enregistrement ?" est la question qui bloque les deals entreprise. Pour une banque, un hôpital, ou n'importe qui soumis à une exigence de résidence des données, "dans nos buckets, chiffré" n'est pas une réponse qu'ils peuvent remonter à leur équipe conformité.
Alors maintenant, vous pouvez nous donner un bucket. Chaque artefact produit par vos bots à partir de ce moment-là, enregistrements, chunks audio, transcriptions, captures d'écran et logs, est écrit dans un stockage qui vous appartient, avec des identifiants que vous avez émis et que vous pouvez révoquer.
GET /v2/storage-config votre configuration actuelle, 404 si absente
PUT /v2/storage-config la définir ou la remplacer
POST /v2/storage-config/test relancer la vérification d'accès
DELETE /v2/storage-config retour au stockage MeetingBaaSOu Settings → Storage dans le dashboard, qui repose sur les quatre mêmes handlers derrière l'authentification de session.
Deux jeux d'identifiants, séparés selon l'endroit où ils finissent physiquement
C'est la décision de conception que je défendrais le plus âprement, alors je commence par là.
Vous fournissez deux paires de clés d'accès, pas une :
| Permissions | Où elles vivent | |
|---|---|---|
| ingest | PutObject, PutObjectTagging, AbortMultipartUpload | Remise au bot d'enregistrement. Sort de notre réseau. |
| service | GetObject, ListBucket, PutObject, DeleteObject | Notre serveur d'API uniquement. Ne sort jamais. |
La clé ingest est le seul identifiant qui s'approche de votre meeting. Elle embarque sur un pod qui fait tourner un navigateur headless à l'intérieur d'un appel, soit l'endroit le plus exposé où un identifiant de ce système puisse se trouver. Elle peut écrire des objets. Elle ne peut pas en relire un, ne peut pas lister ce qui est là, et ne peut rien supprimer. Un pod compromis peut ajouter des déchets dans un préfixe, et c'est tout ce qu'il peut faire.
La clé service fait tout le reste : servir vos enregistrements via des URL signées, écrire les transcriptions quand elles arrivent, et supprimer les artefacts quand votre fenêtre de rétention expire.

Un point mérite d'être précis ici. La clé service n'est pas en lecture seule, et la décrire ainsi serait un mensonge que vous finiriez par nous mettre sous le nez. Elle écrit et elle supprime, parce que l'API fait réellement les deux. Ce que la séparation apporte, c'est que l'identifiant situé à l'endroit risqué est le plus faible des deux. C'est une vraie réduction du rayon d'impact, et ce n'est pas la même chose que du moindre privilège partout : je préfère vous dire exactement lequel des deux vous obtenez.
La mise en place
{
"endpoint": "https://s3.eu-west-3.amazonaws.com",
"region": "eu-west-3",
"force_path_style": false,
"artifacts_bucket": "acme-meeting-artifacts",
"audio_chunks_bucket": "acme-meeting-audio-chunks",
"logs_bucket": "acme-meeting-logs",
"allow_transient_spill": false,
"ingest_access_key_id": "AKIAIOSFODNN7EXAMPLE",
"ingest_secret_access_key": "...",
"service_access_key_id": "AKIAI44QH8DHBEXAMPLE",
"service_secret_access_key": "..."
}Les trois noms de bucket peuvent désigner le même bucket. Les clés d'objet sont de toute façon préfixées par l'id du bot, donc rien n'entre en collision. force_path_style est ce dont MinIO, Ceph et la plupart des passerelles auto-hébergées ont besoin ; AWS et Scaleway fonctionnent sans.
L'endpoint doit être en HTTPS public, sans identifiants ni query string. Les buckets devraient être privés, puisque les artefacts sont servis par des URL signées de courte durée, mais ils doivent bien être joignables depuis internet : les fournisseurs de transcription récupèrent l'audio directement depuis une URL signée au lieu de passer par nous en proxy.
Profitez-en pour autoriser l'origine du dashboard sur le bucket d'artefacts. Le dashboard récupère les artefacts et lit le JSON des transcriptions au lieu de pointer directement dessus : ce sont donc des lectures cross-origin vers votre endpoint, et sans règle CORS le navigateur jette la réponse avant que quoi que ce soit ne s'affiche. GET et HEAD depuis l'origine de votre dashboard, c'est toute la règle. À savoir : PutBucketCors se situe un cran au-dessus des permissions objet que détient la clé service, il faut donc un identifiant de niveau propriétaire — la clé service qui renvoie Forbidden ici, c'est le cloisonnement qui fonctionne, pas un bug.
Relire la configuration vous rend les deux access key IDs, pour que vous sachiez quels identifiants sont utilisés, et aucun des deux secrets. Jamais. Remplacer une configuration implique de ressaisir les deux secrets, parce que nous ne pouvons pas vous montrer ce qui est en place.
La vérification d'accès, et pourquoi ce n'est pas une formalité
PUT vérifie la configuration avant de la stocker. Pas en appelant ListBuckets et en s'arrêtant là.
La clé ingest écrit un objet marqueur dans chaque bucket distinct. Puis la clé service lit cet objet, l'écrit, et le supprime.
Chacun de ces verbes est exercé par l'identifiant qui l'exécutera vraiment en production, donc la sonde échoue de la même façon que la production échouerait. Les quatre sont porteurs : l'upload ingest, c'est par là qu'arrivent les enregistrements ; l'upload service, c'est comme ça que les transcriptions sont écrites ; la lecture, c'est comme ça que les artefacts sont servis ; la suppression, c'est ce qui fait que la rétention expire réellement quelque chose.
La partie vraiment utile, c'est de séparer l'écriture de la lecture. Le marqueur est écrit par un identifiant et doit être retrouvé par l'autre. Ça attrape la panne que personne ne teste : deux paires de clés parfaitement valides chacune, mais pointées vers des buckets différents ou des comptes différents. N'importe quel health check à identifiant unique laisse passer cette configuration, et ensuite vous perdez un enregistrement.
Sans ça, le premier signe d'un nom de bucket mal orthographié est un upload raté à la fin d'un vrai meeting, une fois le disque local du pod disparu. Quand la vérification échoue, nous remontons le message du fournisseur mot pour mot plutôt qu'une erreur générique, parce que "la clé ingest ne peut pas écrire dans le bucket d'artefacts" est tout l'intérêt de la lancer.
Vous pouvez la relancer à tout moment avec POST /v2/storage-config/test, ce qui est exactement ce qu'il faut après une rotation de clés ou un changement de politique de bucket.
Une chose qu'elle ne peut délibérément pas détecter : le CORS. La sonde s'exécute depuis nos serveurs, où le CORS ne s'applique pas ; un bucket peut donc réussir chacun des verbes ci-dessus et refuser malgré tout de livrer un enregistrement à un navigateur. Ce manque est à nous de le combler, et en attendant, la note sur l'autorisation de l'origine du dashboard est ce qui sépare une vérification au vert d'un dashboard qui n'affiche rien.
L'invariant dont tout le reste découle
Un bot se résout toujours vers le stockage dans lequel il a été écrit, jamais vers ce que son équipe a configuré aujourd'hui.
Quand un bot est dispatché, la configuration de stockage en vigueur à cet instant est estampillée sur l'enregistrement du bot. Chaque lecture, chaque URL signée et chaque suppression pour ce bot passe par cette estampille. Pas par l'équipe.
Ça ressemble à un détail d'implémentation. C'est la raison pour laquelle on peut activer la fonctionnalité sans risque, et quatre conséquences en découlent directement :
Changer votre configuration insère une nouvelle ligne et désactive l'ancienne. Jamais de mise à jour sur place. Muter la ligne redirigerait silencieusement les artefacts de tous les bots existants vers un bucket où ils ne sont pas.
DELETE /v2/storage-config ne fait que basculer un flag. Rien n'est supprimé, d'aucun côté. Une suppression dure retirerait les identifiants dont les bots plus anciens ont encore besoin et rendrait orphelin chaque enregistrement de votre compte.
La résolution ignore délibérément si une config est activée ou non. La désactiver empêche les nouveaux artefacts de partir dans votre bucket. Elle ne doit pas rendre orphelins ceux qui y sont déjà.
Une config estampillée introuvable lève une erreur au lieu de retomber sur nos buckets. Ce repli signalerait vos artefacts comme manquants, et lors d'une suppression de rétention, il laisserait silencieusement vos données en place tout en annonçant un succès. Échouer bruyamment est le bon comportement.
En pratique : configurez-le, changez-le ou retirez-le quand vous voulez. Les enregistrements plus anciens continuent de fonctionner à travers tout ça. La seule chose qui rende d'anciens artefacts illisibles, c'est la révocation de notre accès de votre côté, ce qui est votre décision et fonctionne exactement comme vous l'attendez.
Le compromis que vous faites vraiment
allow_transient_spill vaut false par défaut pour les équipes sur leur propre stockage, soit l'inverse de notre valeur par défaut sur la plateforme. Voici ce que cela signifie, en entier, parce que c'est le seul endroit où cette fonctionnalité vous coûte quelque chose.
Normalement, quand un upload échoue, nous recopions l'artefact sur notre propre volume réseau et un job de réconciliation le pousse plus tard. Ce chemin copie le meeting entier : la vidéo, l'audio, la sortie de séparation des interlocuteurs, chaque chunk. Sur notre infrastructure, dans notre compte.
C'est-à-dire exactement ce qu'un client sous contrainte de résidence cherchait à éviter. Pire, ces clients empruntent ce chemin plus souvent que les clients sur la plateforme, parce que leur bucket est hors de notre réseau et souvent chez un tout autre fournisseur.
Donc avec allow_transient_spill: false, ce repli est désactivé sur tous les types de bots et sur le consumer. Un upload qui épuise ses réessais est signalé comme échoué, et l'artefact est perdu.
C'est ça le compromis : la durabilité contre la résidence. Nous le compensons en partie en donnant au client d'upload du bot six tentatives au lieu des trois par défaut du SDK, pour qu'un raté passager ne vous coûte pas un enregistrement, mais une panne prolongée sur votre bucket, elle, vous en coûtera toujours un.
Mettez-le à true si vous préférez garder l'enregistrement plutôt que tenir la garantie. Le dashboard affiche un avertissement expliquant précisément ce que vous abandonnez en le basculant, parce que ça ne doit pas être une case qu'on coche sans y penser.
Si des enregistrements disparaissent et que votre bucket a eu une panne, c'est la première chose à vérifier.
Ce que ça ne fait pas
Quatre choses, annoncées d'emblée pour que personne ne les découvre plus tard.
Rien de ce qui est déjà enregistré n'est déplacé. Il n'y a pas de migration. Chaque bot continue de se résoudre là où il a été écrit, ce qui rend l'activation sans risque, et signifie aussi que votre historique reste sur nos buckets.
Pas de configuration de préfixe par bucket. Les clés sont <bot_uuid>/…, et c'est figé.
Cela ne suffit pas à rendre la résidence étanche. Les pods de bots gardent toujours l'enregistrement sur le disque local pendant que le meeting tourne. Ce que ça ferme, c'est le seul chemin par lequel votre enregistrement vient séjourner sur l'infrastructure partagée de MeetingBaaS.
Les assets du dashboard restent sur nos buckets. Les logos, les avatars utilisateurs et les pièces jointes de support ne sont pas des données de meeting et ne sont pas concernés.
Revenir en arrière
DELETE /v2/storage-config, sans risque à tout moment. Les nouveaux bots repartent immédiatement sur notre stockage. Les bots existants continuent de se résoudre vers vos buckets et continuent de fonctionner.
Sur le même sujet
- Six Fournisseurs de Transcription, Une Seule API — associez une région de bucket à une région de fournisseur pour une résidence de bout en bout
- Héberger Meeting BaaS chez vous — si posséder le bucket ne va pas assez loin
- Référence de l'API Meeting BaaS
Si vous travaillez sur une exigence de résidence et voulez savoir exactement quel composant touche à quoi, demandez-nous. Nous vous donnerons la même réponse qu'ici.