Translate

lundi 27 décembre 2010

[INFO]: Terminaison SSL avec Exchange 2010 SP1 et bug avec le Web Service UM pour clients Outlook 2007

Cela faisait longtemps que je n'avais pas posté un petit article. En cette trève de Noël, me voici donc avec un peu de temps libre afin de partager un problème recontré avec le Web Service permettant un client Outlook 2007 d'accéder aux options de Messagerie Unifiée.

Avant d'entrer dans l'explication du bug, je vais défendre la cause de la terminaison SSL sur un répartiteur de charge, et de "pourquoi cela est-ce une bonne idée" :)

Lorsque l'on met Exchange Server 2010 en production, il est pour ainsi dire presque obligatoire d'utiliser un répartiteur de charge externe (autrement dit, un load-balancer aussi appelé HLB pour "Hardware Load-Balancer" bien qu'en définitive, il s'agisse de logiciels :)). Ceci pour deux raisons:
  • Performance: afin de s'assurer que l'on peut répartir les accès clients de manière équitable entre les Serveurs d'Accès Client (Client Access Server, ou CAS);
  • Haute-disponibilité: un autre aspect important est de permettre aux clients - ou applications faisant usage de la messagerie - de basculer de manière plus ou moins transparente d'un serveur à l'autre si celui qu'ils utilisaient venait à tomber en panne, ou même devait être placé sous maintenance (ex: application d'un Service Pack ou autre opération un peu longue)
Bref, lorsque l'on met une application en balance de charge, on se pose la question de savoir comment...

En effet, lorsque vient la question d'un Serveur d'Accès Client (CAS) avec Exchange 2010, il faut effectuer la répartition de charge à minima au niveau 4 (TCP) et au mieux au niveau 7 (Application, autrement dit pour Exchange, l'HTTP).

Voici une liste résumant les modes de répartition de charge pour Exchange 2010:
  • Mapi/Rpc: couche 4 (tcp)
  • POP/POPS:couche 4 (tcp)
  • IMAP/IMAPS: couche 4 (tcp)
  • HTTP/HTTPS: couche 4 (tcp) ou couche 7 (http)
Ce qui nous interesse ici, c'est la balance de charge au niveau HTTP: elle concerne tous les Web Services d'Exchange, qu'il s'agisse d'Outlook Web App (OWA) et de l'Echange Control Panel (ECP), d'Exchange ActiveSync (EAS), de l'Autodiscover (ADS), de l'OAB, du RPC/HTTP, et bien sûr des Web Services "utilitaires" regroupés dans ce que l'on appelle "EWS" (Exchange Web Services).

Lorsque l'on décide de faire de la balance de charge HTTP se pose souvent la question de la terminaison SSL, c'est à dire, qui prend en charge l'encryption des flux transitant entre les clients et les serveurs. Par défaut, celle-ci s'effectue au niveau des serveurs. Historiquement, on utilisait des matériels dédiés afin de décharger les serveurs des calculs nécessaires à l'encryption des données. De nos jours les serveurs sont des milliers de fois plus performants et la question légitime est "ai-je vraiment besoin de terminer le SSL pour réduire la charge sur mes serveurs ?" - la réponse est bien évidemment non pour 99.99% des cas.

Cependant, avec les répartiteurs de charge l'interêt du déchargement SSL est ailleurs: en effet, lorsque l'on fait du déchargement SSL au niveau 7, il est possible d'interpréter les flux entre les clients et les serveurs au niveau du répartiteur de charge (qui agit donc comme un proxy inversé (reverse proxy) et cela donne la liberté d'introduire une "intelligence" sur la façon de gérer la balance de charge et la persistance d'une connexion cliente à destination de tel ou tel serveur).

A titre d'exemple, imaginez une balance de charge HTTP effectuée au niveau 4: la seule persistance possible ici est par adresse IP source... ce qui est bien dans la plupart des cas, mais largement insuffisant voire problématique dans certains autres: lorsque des clients arrivent par un mécanisme réseau ne présentant qu'une seule adresse IP (NAT, reverse proxy entres autres), ils sont systématiquement tous redirigés vers le même serveur cible. Imaginez que 10,000 clients traversent ce NAT ou Reverse Proxy (imaginez par exemple 10,000 teminaux ActiveSync passant par un serveur ForeFront TMG), cela génère une répartition de charge complètement inéquitable et totalement indépendante de l'application Web utilisée.

La bonne idée est donc de terminer le flux au niveau du répartiteur de charge, et donc de vraiment se positionner au niveau 7. Il existe alors plusieurs modes de persistance communs utilisables:
  • Adresse IP source (similaire à la persistance de niveau 4)
  • Cookie applicatif (fourni par le serveur)
  • Cookie inséré par le répartiteur de charge
  • SSL ID
  • En-tête HTTP (au choix)
  • Selon le répartiteur, des algorithmes avancés, voire "programmables" (tels que les iRules chez F5)
A mon sens, effectuer la terminaison SSL au niveau du répartiteur de charge est quelque chose de nécessaire et permet de choisir pour Exchange (entre autres) le bon mode de persistence en fonction du service utilisé (ex: cookies pour OWA/ECP, en-tête "Authorization" pour ActiveSync, etc). Outre ces aspects, cela permet surtout de garantir une équité sur la répartition de charge, quelque soit le mode d'accès utilisé (interne, via NAT, via Reverse Proxy, via Proxy interne, etc).

Comment activer la terminaison SSL avec Exchange 2010 ?

Je ne vais pas rentrer dans les détails, surtout que cela varie entre Exchange 2010 RTM et Exchange 2010 SP1. Je vais simplement m'attarder sur E2010 SP1, car il s'agit de la version actuelle (que vous devriez donc installer en production :)) et surtout la plus facile à configurer pour la terminaison SSL. Aussi je serai bref dans la façon de procéder:
  • Pour OWA/ECP: il faut positioner une clef de registre particulière sur chaque CAS: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\MSExchange OWA ==> SSLOffloaded (REG_DWORD) à 1 (0x00000001) - il faut aussi configurer les répertoires virtuels comme expliqué ci-dessous pour les Web Services
  • Pour Outlook Anywhere (RPC/HTTP): utiliser -SSLOffloaded:$true sur les Cmdlet Enable-OutlookAnywhere ou Set-OutlookAnywhere afin d'activer la terminaison SSL externe; à faire bien sûr pour chaque CAS où le Rpc/Http sera activé;
  • Pour les Web Services en général: toujours sur chaque CAS, aller dans la console IIS et configurer leur répertoire en décochant "Require SSL" dans les propriétés SSL du répertoire (/owa, /ecp, /ews, /microsoft-server-activesync, /autodiscover, /oab, /rpc) -- ne pas le faire sur /rpcwithcert
Il va de soit qu'au niveau de la configuration des répertoires virtuels, vous devez tout de même spécifier des URL faisant référence au protocole HTTPS (ex: https://monnomvirtuel.domaine.local/Autodiscover/Autodiscover.xml pour l'accès au Web Service Autodiscover).

Comme d'habitude, toutes ces opérations sont "scriptable" facilement en PowerShell... ;)
Pour plus de détails, je vous invite à lire un bon article de Henrik Walther ici (en anglais). Cependant il ne parle pas du problème qui nous interesse ici.

Revenons à nos moutons, et parlons du Web Service Messagerie Unifiée pour clients Oulook 2007

Ceux qui ont utilisé (ou testé) la Messagerie Unifiée avec Exchange Server 2007 se rappelleront sûrement qu'il existait un répertoire virtuel particulier contenant un Web Service déstiné à servir les clients Outlook 2007. Tout bêtement, ce Web Service permettait à un client Outlook 2007 (dès lors que le compte utilisateur était "UM-enabled") d'accéder à quelques fonctionnalités et informations de Messagerie Unifiée via le menu Outils ==> Options et l'onglet "Messagerie Unifiée".

Dans Exchange 2010, ce Web Service a été conservé mais n'est plus utilisé par les clients Outlook 2010, il a donc été restructuré et déplacé d'un répertoire dédié (/UnifiedMessaging) au même endroit que les autres Web Services "utilitaires" (/EWS) et s'appelle désormais "UM2007Legacy.asmx".

Mais quel est donc le problème ?

Lorsque l'on fait de la terminaison SSL au niveau du répartiteur de charge, on effectue donc un accès HTTP au Web Service, et non plus SSL. Si cela fonctionne avec tous les Web Services (dès lors que la configuration des serveurs est faite correctement), je me suis rendu compte que cela n'était pas le cas avec le Web Service UM2007Legacy destiné aux clients Outlook 2007... Lorsque j'ai effectué mes tests avec un client Outlook 2007, je me suis rendu compte que l'accès au Web Service ne fonctionnait pas. J'ai eu beau chercher et tenter de trouver une faille dans ma configuration, il s'est avéré que le code erreur ne correspondait pas (le serveur me retournait un "404 Not found" au lieu de tout au code erreur frôlant une logique de mauvaise configuration). C'est après quelques minutes de déboggage intensif que je me suis rendu compte que l'erreur ne venait pas de moi, mais bel et bien d'un "oubli" dans Exchange 2010 SP1...

La raison est simple: depuis Exchange 2010 SP1, les Web Services ont légèrement été modifiés afin d'accepter des access HTTP _et_ HTTPS, indépendament de la manière dont leur répertoire virtuel IIS est configuré. Cela est définit dans les fichiers "Web.config" présents dans les répertoires virtuels des Web Services Exchange. Le plus drôle est que cela n'affecte que Exchange 2010 SP1, pas la RTM puisque dans la RTM, tout était HTTP ou HTTPS, mais pas les deux.

Prenons par exemple les Web Services dans /EWS, donc définis dans $exinstall\ClientAccess\exchweb\EWS\Web.config:


Au travers de ces quelques balises XML, nous pouvons voir que le service Microsoft.Exchange.Services.Wcf.EWSService définit plusieurs terminaisons ("endpoints"), dont deux en HTTPS et deux en HTTP. Il suffit donc de regarder comment sont définis les mécanismes d'écoute (bindings) de ces terminaisons et nous trouvons donc ceci (capture d'image tronquée pour une meilleure lisibilité):

En résumé, cela signifie que le Web Service mentionné plus haut accepte le protocole HTTPS et le protocole HTTP, définis respectivement par les balises httpTransport et httpTransport dans deux noeuds XML différents (donc avec des noms différents).

Lorsque l'on s'intéresse maintenant au service Web UM pour clients Outlook 2007, on trouve ceci:
et ceci:

Il n'y a donc aucune terminaison sur le protocole HTTP de prévue !!! Il s'agit clairement d'un oubli du SP1, qui applique un nouveau fichier Web.Config sur tous les Web Services (cela ne concerne que le Web.Config du répertoire EWS).

Comment corriger cet oubli ?

C'est assez simple. Il suffit d'ajouter un "endpoint" et un "binding" pour le Web Service en question. Pour ceci, utiliser un éditeur de type Notepad, Notepad++ ou tout autre de votre choix afin d'effectuer les modifications suivantes (pensez à effectuer une sauvegarde de votre fichier Web.config auparavant):
  1. Editez le fichier Web.Config ($exinstall\ClientAccess\exchweb\EWS\Web.Config)
  2. Localisez la balise "service" correspondant au Web Service "Microsoft.Exchange.UM.ClientAccess.UMWebService"
  3. Ajoutez un "endpoint" faisant référence à un "binding" en Http (personnellement, j'ai utilisé "UMLegacyHttpBinding") et copié depuis le "UMLegacyHttpsBinding"
  4. Aller dans le noeud "customBinding" et ajoutez un "binding" nommé "UMLegacyHttpBinding" recopié à partir de "UMLegacyHttpsBinding", copiez-le puis remplacez la balise "httpsTransport" en "httpTransport"
  5. Enregistrez le fichier et redémarrez IIS (IISreset /noforce) ou recyclez l'application "MSExchangeServicesAppPool"
  6. Réitérez l'opérations sur tous les CAS
Voici ce que cela doit donner pour la définition du Web Service:
Et dans la définition des bindings:

Voilà, ceci clos mon premier article depuis quelque temps... :p

Il ne me reste plus qu'à vous souhaitez de joyeuses fêtes de fin d'année !!! Et de vous dire à l'année prochaine peut-être pour de nouvelles aventures (si j'ai un peu plus de temps libre pour blogger ;))