Résoudre l’absence de notifications Microsoft Teams déclenchées par GitLab CI via Incoming Webhook

Les notifications automatiques constituent souvent la première ligne de défense lorsque quelque chose tourne mal ; l’arrêt soudain des messages post‑pipeline dans Microsoft Teams peut donc masquer un incident plus grave et ralentir la réaction des équipes DevOps.

Sommaire

Vue d’ensemble du problème

Jusqu’ici, chaque exécution réussie d’un pipeline GitLab CI/CD terminait son cycle de vie par un appel HTTP vers un incoming webhook Teams, charge à ce dernier d’afficher un message coloré dans le canal #build‑status. Subitement, l’activité s’est figée : plus aucun carton vert ou rouge dans Teams, bien que la tuile « Pipelines » de GitLab affiche un historique tout vert. Cette situation typique soulève une double inquiétude : perte de visibilité opérationnelle et doute sur l’intégrité du processus de diffusion.

Comment fonctionnent les webhooks Teams

Un incoming webhook est une URL unique, liée à la configuration du canal ; elle accepte une requête HTTP POST contenant un objet JSON conforme au format de cards Microsoft. Les connecteurs utilisent le service « Office 365 Connector » pour convertir cette charge utile en message enrichi et l’insérer dans la conversation. Dès qu’une des briques suivantes tombe, la chaîne se brise :

  • Résolution DNS de l’URL (outlook.office.com).
  • Négociation TLS 1.2 entre le client (runner GitLab) et le front‑door Microsoft.
  • Validation de la signature interne du message (contraintes de schéma JSON).
  • Politiques Teams prohibant la publication.

Codes d’erreur et limitations de quotas

Code HTTPSignificationAction recommandée
200 OKMessage acceptéAucune
400 Bad RequestJSON mal forméValider la structure, champs obligatoires, taille < 28 KB
401 UnauthorizedWebhook inexistant ou révoquéRégénérer via l’onglet « Connecteurs » du canal
403 ForbiddenPolitique Teams ou AAD bloque l’accèsContrôler CsTeamsMessagingPolicy
429 Too Many RequestsQuota 1 msg/seconde ou 30 msg/min dépasséMise en file d’attente, back‑off exponentiel
5xxPanne côté MicrosoftConsulter le Centre d’administration → Santé

Analyse détaillée des causes probables

Incident global Microsoft 365

Lorsque les équipes de Redmond appliquent une mise à jour sur les connecteurs, un reflux temporaire peut se produire. Le tableau d’état interne (accessible via Santé → État du service) publie des identifiants comme TM401234 décrivant l’incident, la région touchée et l’horaire de rétablissement estimé. Surveiller ces IDs et configurer une alerte e‑mail évite des heures de recherche infructueuse.

Politique de sécurité durcie

Les administrateurs peuvent ajuster la stratégie CsTeamsMessagingPolicy pour supprimer la valeur $true du paramètre AllowUserSendConnectors. Les raisons sont multiples : audit ISO 27001, durcissement post‑incident, ou alignement sur une baseline MDM. Un simple Get-CsTeamsMessagingPolicy | Format-Table Identity,AllowUserSendConnectors identifie la déviation ; rétablissez ensuite la permission via PowerShell ou depuis le Teams Admin Center.

Webhook obsolète

Chaque URL contient un jeton signé numériquement. La moindre modification du canal (archivage, déplacement vers un nouveau team group, changement de confidentialité) invalide ce jeton. Pour confirmer la vie du webhook :

curl -X POST \
  -H "Content-Type: application/json" \
  -d '{ "text": "test Teams webhook" }' \
  https://outlook.office.com/webhook/…

Une réponse 200 valide l’endpoint ; toute autre réponse exige de recréer le connecteur et de mettre à jour la variable GitLab CI TEAMS_WEBHOOK_URL.

Filtrage réseau ou proxy

Les environnements on‑prem ou les runners autoscalés dans un VPC très cloisonné passent souvent par un proxy explicite. Vérifiez que les domaines *.office.com et *.microsoft.com figurent sur la liste d’autorisation. Les solutions CASB, Defender for Cloud Apps ou Zscaler peuvent imposer un contrôle supplémentaire – consultez les journaux d’accès et les catégories de trafic.

Processus de diagnostic pas à pas

  1. État du service – Ouvrez le Centre d’administration Microsoft 365 et confirmez qu’aucune alerte TM ou EX n’est active. Exportez le flux RSS pour une veille automatisée.
  2. Collecte de logs GitLab – Passez la variable d’environnement CI_DEBUG_TRACE à true pour afficher la réponse HTTP complète lors de la tâche notify_teams.
  3. Test « à sec » – Exécutez le curl indiqué ci‑dessus depuis le même runner. Si curl aboutit, incriminez la charge utile ; sinon, suspectez le réseau.
  4. Analyse réseau – Sur un runner Linux, installez tcpdump et tracez tcp port 443 and host outlook.office.com. Aucun paquet sortant ? Le proxy confisque probablement la requête.
  5. Revoyez la politique – Dans PowerShell, exécutez Grant-CsTeamsMessagingPolicy -PolicyName "TaskOriented" sur le groupe d’utilisateurs concerné pour réactiver les connecteurs.
  6. Débogage du JSON – Validez la taille (< 28 KB) et la présence du champ text ou sections. Utilisez jq . pour formater et vérifier la syntaxe.

Bonnes pratiques pour prévenir les coupures futures

  • Versionner l’URL : stockez‑la dans CI/CD > Variables avec la balise Masked. Lorsque vous recréez un connecteur, commentez l’ancienne valeur plutôt que de l’écraser.
  • Supervision active : ajoutez une tâche planifiée dans GitLab (schedule) qui envoie une carte « heartbeat ». Traitez son absence via un bot ou par Azure Monitor.
  • Back‑off exponentiel : en cas de 429, réessayez après 2, 4, puis 8 secondes. Au‑delà, placez le message dans une file RabbitMQ ou Redis pour reprise manuelle.
  • Observabilité : publiez les métriques success_rate et latency_p95 dans Prometheus afin de déclencher un alert rule si le taux de réussite passe sous 95 % sur 5 minutes glissantes.
  • Rotation des secrets : traitez l’URL de webhook comme un jeton et appliquez une rotation semestrielle.

Automatiser les alertes dans GitLab

Un exemple minimaliste :

.notify_template: &notify
  stage: notify
  image: curlimages/curl:8.8.0
  script:
    - >-
      curl -s -o /dev/null -w "%{http_code}" -X POST
      -H "Content-Type: application/json"
      -d "$PAYLOAD"
      "$TEAMS_WEBHOOK_URL" | tee status.txt
    - '[[ $(cat status.txt) == "200" ]] || exit 1'

notify\_success:
<<: \*notify
rules:
\- if: '\$CI\_JOB\_STATUS == "success"'
when: always

notify\_failure:
<<: \*notify
rules:
\- if: '\$CI\_JOB\_STATUS == "failed"'
when: always
variables:
PAYLOAD: '{ "themeColor": "FF0000", "text": "Pipeline échoué ! \$CI\_PIPELINE\_URL" }'

FAQ rapide

Q : Le webhook fonctionne depuis Postman mais pas depuis GitLab ?
R : Postman contourne peut‑être le proxy d’entreprise ; vérifiez la variable d’environnement http_proxy sur vos runners.

Q : Peut‑on protéger l’URL par IP whitelist ?
R : Non, Microsoft ne supporte pas la restriction par IP côté service. Appliquez plutôt un proxy sortant authentifié ou un VNet naté.

Q : Combien de messages par webhook ?
R : Jusqu’à 1 par seconde et 30 par minute. Au‑delà, le service renvoie un 429.
Astuce : pour des pipelines parallèles très verbeux, créez plusieurs webhooks et répartissez la charge.

Conclusion

La disparition de notifications Teams masque souvent une cause triviale (webhook supprimé) mais peut aussi signaler un durcissement de sécurité ou un incident Microsoft. En appliquant la démarche structurée présentée – état du service, validation de politique, test manuel, analyse réseau – vous ramènerez vos alertes en quelques minutes. Capitalisez ensuite en automatisant la surveillance et en documentant la rotation des secrets afin d’éviter toute ré‑occurrence.

Sommaire