Ribbon SBC en multi-tenant pour un opérateur B2B : retour de terrain
Architecturer un SBC Ribbon 5400 pour héberger des dizaines de tenants PBX clients sur une infrastructure mutualisée. Décisions, pièges et chiffres après 18 mois de production.
Un opérateur européen B2B nous confie son socle SIP : faire tenir des dizaines de PBX clients (Microsoft Teams, 3CX, FreePBX, IPBX legacy) sur une paire de SBC Ribbon 5400 en haute disponibilité, sans dégrader la voix d'un seul tenant quand un autre saturer son trunk. Cet article détaille les décisions structurantes prises, les trois pièges qui nous ont coûté le plus de temps, et ce qu'on changerait avec dix-huit mois de recul. Tous les noms sont anonymisés.
Le contexte de départ
L'opérateur partait d'une infrastructure monolithique : un SBC unique, un seul addressContext global, une cinquantaine de sipTrunkGroup empilés à plat. Quand un nouveau client arrivait, l'équipe ops ajoutait un trunk group, copiait-collait une règle de routage, croisait les doigts. Trois symptômes nous ont été rapportés en cadrage :
- Couplage incident → tous les tenants — Un client lance un test de charge, les CPS du SBC saturent, l'ensemble des autres tenants subit du
503 Service Unavailablesur les nouvelles tentatives d'appel. - Conflits de plan de numérotation — Deux clients utilisent le même préfixe interne (
9pour la sortie ville), les règles de translation se marchent dessus, les opérateurs corrigent à la main au cas par cas. - Aucune métrique par client — Les CDR sortent dans un seul fichier brut, le reporting client réclame une journée d'extraction Excel à chaque demande.
L'objectif était double : isolation logique entre tenants (pas un seul tenant ne doit pouvoir impacter les autres) et provisioning industrialisable (un nouveau client = une procédure répétable, pas un one-shot artisanal).
Décision 1 — Un address context par segment, pas par client
Premier réflexe consultant : addressContext par client = isolation totale. Première erreur. Sur Ribbon SBC 5400, le nombre maximum d'addressContext est limité, et chaque context porte son propre overhead de routing engine.
La décision finale : un address context par segment de marché, pas par client.
| Address context | Population | Politique partagée |
|-----------------|-----------|-------------------|
| AC-MICROSOFT | Tenants Teams Direct Routing | TLS strict, codec Opus prio, NAT-aware |
| AC-CLOUDPBX | 3CX cloud, Yeastar, RingCentral | TLS, RTPProxy, médiation transcodage |
| AC-LEGACY | IPBX on-premise hérités | UDP toléré, RFC 2833 forcé, fallback G.711 |
| AC-CARRIER | Trunks SIP fournisseurs amont | mTLS, STIR/SHAKEN, anti-replay |
L'isolation reste forte (un incident TLS sur AC-LEGACY ne touche pas AC-MICROSOFT), tout en gardant un nombre de contexts gérable opérationnellement (4 au lieu de 50+).
Pour la séparation par client, on travaille à l'intérieur d'un context avec des zone et des sipTrunkGroup nommés selon une convention stricte :
zone : ZN-<CUSTOMERID>
sipTrunkGroup : <CUSTOMERID>-CORE-PRI / <CUSTOMERID>-CORE-SEC
ipPeer : IP-<CUSTOMERID>-<ROLE>
Cette nomenclature permet à n'importe quel ingénieur ops (et à nos scripts) de retrouver instantanément tous les objets d'un client donné, et de tout supprimer proprement à la résiliation.
Décision 2 — Le plan de numérotation tenant vit en SMM, pas en routing
Le piège du plan de numérotation interne client est qu'il diverge à chaque acquisition. Client A utilise 9 en sortie ville. Client B utilise 0. Client C demande 8 parce que son ancien IPBX faisait comme ça. Tenter de gérer ça dans les règles de routage du SBC mène à une explosion combinatoire.
Notre approche : toute manipulation propre au tenant vit dans les SMM (SIP Message Manipulation) attachées à son sipTrunkGroup, pas dans le routing engine.
# Exemple SMM — Client utilisant préfixe "9" en sortie ville
# Strip le 9, normalise en E.164 avec indicatif pays par défaut
condition : Header.RequestLine.URI.User starts_with "9"
action : strip first 1 char from Header.RequestLine.URI.User
action : prepend "+33" to Header.RequestLine.URI.User
Le routing global, lui, ne voit que des numéros au format E.164. Il n'a pas à connaître les habitudes du client X.
Bénéfice opérationnel : ajouter un client avec un plan exotique = écrire une SMM dédiée, l'attacher à son trunk group, c'est terminé. Pas de patch dans des règles centrales partagées par tous.
Décision 3 — Limites par tenant, pas par SBC
Le défaut historique des configurations SBC est de fixer des seuils globaux (MaxSessions, CPS) à l'échelle de la box. Quand un tenant lance une vague de test, il consomme tout le quota.
Sur Ribbon, les policer permettent de plafonner par sipTrunkGroup. Notre standard :
| Profil tenant | MaxSessions | CPS | Burst | |---------------|-------------|-----|-------| | Pilot (≤ 50 users) | 30 | 5 | 10 | | Standard (≤ 500 users) | 200 | 20 | 50 | | Enterprise (> 500 users) | sur dimensionnement | sur dimensionnement | × 2 |
Au-delà du quota, le SBC répond 486 Busy Here au tenant fautif. Les autres tenants ne voient rien. Cette mesure seule a éliminé 80 % des incidents cross-tenant remontés en année 1.
Trois pièges qui nous ont coûté du temps
Piège 1 — TLS et SNI
Plusieurs trunks Microsoft Teams Direct Routing ont commencé à échouer en silence après un upgrade firmware. Cause racine : Microsoft envoie le SNI dans le ClientHello TLS. Notre SBC, configuré avec un certificat unique sur l'interface signaling, négociait correctement, mais Teams refusait la session si le SNI ne correspondait pas exactement au FQDN attendu.
Solution : configurer plusieurs certificats sur la même interface avec sélection par SNI. Une fois fait, échec disparu. Symptôme initial diagnostique trompeur (les logs montraient TLS handshake OK).
Piège 2 — Le RTP qui suit pas la route
Sur les tenants en NAT cône-restreint (typique des petits PBX on-premise derrière un firewall classique), le SBC négociait correctement la signalisation, mais le flux RTP retour partait vers l'adresse IP privée annoncée par le client, jamais reçue.
Solution : forcer latching (apprentissage de la source RTP) sur les profils correspondants, et activer media bypass detection pour ne pas perdre de précieux ports RTP sur des sessions qui n'aboutissent jamais. À retenir : latching n'est pas un paramètre par défaut sur les profils Ribbon "secure" — il faut explicitement l'activer.
Piège 3 — Le CDR qui ne sait pas qui est qui
Premier mois de production, demande client : "donnez-moi le nombre d'appels sortants pour mon tenant en mars". Réponse honnête : on ne savait pas. Les CDR ne portaient pas l'identifiant tenant en clair.
Refonte : ajouter une SMM en émission qui injecte l'identifiant tenant dans un header custom (P-Qaryon-Tenant-ID), puis configurer le CDR enrichment côté Ribbon pour exposer ce header dans le record de fin d'appel. Désormais chaque CDR porte le tenant. Reporting client = une requête SQL au lieu d'une journée d'export Excel.
Les chiffres après 18 mois
- 42 tenants actifs sur la paire de SBC, segments mixtes
- Zéro incident cross-tenant remonté depuis le déploiement de la limitation par sipTrunkGroup
- Provisioning d'un nouveau tenant : 35 minutes en moyenne (procédure scriptée), contre 4 heures avant
- Temps de génération du reporting mensuel par tenant : 2 minutes (SQL) contre 1 jour-homme
Ce qu'on changerait avec le recul
Avec dix-huit mois de production, deux décisions seraient prises différemment :
Industrialiser le provisioning dès le jour un. On a écrit les scripts d'automation au mois 6, après avoir mal provisionné une dizaine de tenants à la main. Refaire ces tenants a pris du temps et créé du risque inutile. Si c'était à refaire : Terraform/Ansible avant le premier client, pas après le dixième.
Choisir le format CDR enrichi dès le départ. Tout le travail de SMM + enrichment décrit ci-dessus aurait été cinq fois plus simple à faire avant la mise en service. Une fois en production, modifier la chaîne CDR sans casser les exports clients existants demande beaucoup de précautions et de fenêtres de maintenance.
Conclusion
Un SBC multi-tenant ne se résume pas à empiler des trunk groups dans une box. Les vraies décisions sont l'isolation par segment plutôt que par client, le déport des spécificités tenant en SMM plutôt qu'en routing, et la limitation explicite des quotas par trunk group. Chacune de ces décisions a un coût initial — et chacune a évité plusieurs incidents en production.
Ce type de mission est exactement ce que qaryon livre : architecture cible, configuration, mise en production, transfert de compétences. Un seul interlocuteur du cadrage à la bascule.
qaryon — Conseil, audit et déploiement en communications unifiées. Prendre contact.