dimanche 26 mars 2017

Sécurité Vol 2 - Les base en cryptographie - 1

J'ai pris le temps pour écrire ce second article sur la sécurité mais vieux motard que jamais. J'ai été pas mal occupé et un peu fainéant pour être honnête. Bref, je vais expliquer brièvement les bases techniques essentielles qu'il est indispensable de maîtriser pour pouvoir comprendre ce qui viendra ensuite.

Précédent article de la série : Sécurite - Vol 1 : définitions

Un peu de vocabulaire

Tout d'abord une précision utile. Le langage couramment employé en matière de cryptographie est généralement incorrect. Entre néologismes et mauvaises traductions de l'anglais, la plupart des gens, et j'en fait partie, utilisent des mots qui portent un sens différent de celui qu'ils veulent communiquer, ou qui carrément n'existent pas. Je vous renvoie à cet article très clair sur le sujet : Les mots « crypter » et « cryptage » n’existent pas !.

J'utilise parfois les conventions courantes bien qu'elles soient incorrectes : par exemple "décrypter" au lieu de "déchiffrer". Toutes mes excuses aux puristes.

Hachage

Le hachage est désigné par de nombreux termes souvent dérivés de l'application de ce principe qui est très employé en informatique et en cryptographie. On entendra donc parler de hashcode, d'empreinte, de condensat, de clé de contrôle et d'autres termes encore.

Le hachage est simplement une fonction (au sens mathématique du terme) qui prend en entrée une information quelconque et produit en sortie une donnée qui a des propriétés particulières qui la rendent très utile dans de nombreux domaines.

Le hash a donc des propriétés intéressantes dont nous allons parler rapidement.

Unicité

Deux données différentes en entrée ne produiront jamais un hash identique. C'est la conception de l'algorithme de hachage qui garantit ceci

Si deux valeurs différents peuvent produire un même hash, on parle de collision, et quand la possibilité d'un tel cas est avérée l'algorithme est abandonné. Ceci s'est déjà produit à plusieurs reprises par le passé ce qui n'est pas sans conséquence. Par exemple, les algorithmes de hachage étant implémentés par les navigateurs pour sécuriser la navigation en https, le fait qu'on découvre qu'un algorithme doit être abandonné et remplacé par un autre implique une mise à jour du navigateur. Voilà pourquoi il est recommandé de toujours utiliser un navigateur récent et à jour pour faire des achats ou toute autre opération sensible en ligne. C'est également pour cette raison qu'il faut maintenir à jour ses systèmes d'exploitation. Actuellement (début 2017) l'algorithme SHA-1 est majoritairement utilisé, or il vient d'être démontré qu'il avait des failles et devait être abandonné au profit d'un algorithme plus robuste (SHA-256 à priori).

Non-réversibilité

Il n'est pas possible de retrouver la donnée en entrée à partir de son hash. Si quelqu'un dispose du hash d'une donnée, il ne peut pas en déduire la donnée initiale.

C'est pour cette raison que les hackers ont constitué des bases de données avec des milliards de chaînes de caractères, et le résultat de l'application des fonctions de hachage courante sur chacune de ces données. Ainsi, en connaissant un hash et l'algorithme avec lequel il a été produit (des données relativement aisées à obtenir), en faisant une recherche dans cette base sur la colonne qui stocke le hash, on pourra déduire la chaîne de caractères initiale si elle n'est ni trop longue ni trop complexe (la complexité de mesurant par le fait de mélanger différentes types de caractères : minuscules, majuscules, caractères spéciaux etc...). On appelle ça une attaque par dictionnaire.

Usages fréquents

Contrôle d'accès par mot de passe

Il est fréquent que les applications nécessitent une authentification de l'utilisateur, ceci afin de vérifier son identité. Une fois l'identité établie, il est possible de déterminer son niveau d'habilitation (les actions qu'il peut entreprendre, les données auxquelles il a accès etc.). 

Le moyen le plus simple et le plus fréquent encore de nos jours de contrôler l'identité d'un utilisateur est de lui demander de s'identifier en saisissant un identifiant (login) et de prouver qu'il est bien le détenteur de cette identité en fournissant un mot de passe. Comme le mot de passe a été défini initialement par l'utilisateur à la création de son compte, et qu'il est censé ne l'avoir communiqué à personne et le conserver secret (en évitant par exemple de l'inscrire sur un post-it collé sur son écran), si le mot de passe fourni correspond, on est certain de l'identité de la personne.

Intuitivement on imagine que l'application en question doit stocker le mot de passe de l'utilisateur quelque part en regard de son identifiant pour pouvoir vérifier le mot de passe. Hé bien non. Il est certes possible de faire ainsi mais c'est une très très très mauvaise pratique et c'est bien souvent interdit. En fait, on ne stocke pas le mot de passe mais uniquement son hash. En comparant le hash du mot de passe saisi avec le hash stocké initialement, on fait la vérification voulue sans devoir stocker en clair le mot de passe (ce qui permettrait à quelqu'un de mal intentionné ayant accès au fichier des mots de passe d'usurper n'importe quelle identité).

Il arrive que des hackers arrivent à voler les fichiers stockant les identifiants et les mots de passe, ou les hash de mot de passe si la sécurité est gérée correctement (ceci dis, si c'était le cas, il n'auraient pas pu voler les fichiers en question). Si les mots de passe sont en clair, ils peuvent directement voler votre identité numérique (s'authentifier sous votre nom et mener des actions qui vous seront imputées).Si ce sont des hash, ils feront une attaque par dictionnaire : si vos mots de passes sont trop simples et trop courts, ils arriveront à leur fin, mais si vous avez défini un mot de passe assez long et mélangeant chiffres + lettres + caractères spéciaux, ils n'arriveront pas à trouver votre mot de passe.

On peut éliminer le risque d'attaque par dictionnaire en utilisant une technique appelée "salage" (salt) : au lieu de stocker le hash du mot de passe, on stocke le hash de la combinaison du hash du mot de passe et d'une chaîne de caractère constante. Il n'y a ainsi plus de lien direct entre la valeur stockée dans le fichier des mots de passe et le mot de passe de l'utilisateur. 

Vous devez comprendre maintenant pourquoi de plus en plus on vous oblige à avoir des mots de passe d'une longueur minimum et avec une certaine complexité. 

Si on ajoute qu'on peut en outre vous obliger à les changer fréquemment, et sans réutiliser des anciens mots de passe, et que vous utilisez de nombreuses applications ayant chacune sa propre liste d'utilisateurs et mots de passe, ça peut rapidement devenir problématique de se rappeler de tous ces mots de passes. Une astuce serait d'utiliser le même mot de passe sur les différentes applications mais d'une part ce n'est pas forcément possible (chaque application imposant des règles de longueur et de complexité différentes), et d'autre part c'est dangereux (le mot de passe volé sur un site donnera accès à tous vos autres comptes sur tous vos autres sites). Une autre astuce consiste à noter tous ces mots de passes et identifiants quelque part... très dangereux aussi car si quelqu'un vole votre fichier, il aura accès à toutes vos identités numériques. Il existe différentes parades dont nous parlerons plus en détail dans un autre article tant le sujet est vaste (en informatique, il existe une discipline spécifique dédiée au sujet, appelée IAM Identity and Access Management) : mise en place de SSO (Single Sign On, on ne s'authentifie qu'une seule fois et une seule identité numérique permet l'accès à de multiples applications), fédération d'identité (un même référentiel utilisateur est utilisé par de nombreuses applications interfacées via des protocoles standards sur le référentiel en question).

Signature électronique

Dans le monde réel, vous authentifiez des documents en apposant votre signature. Il existe un équivalent en informatique qui a la même valeur probante au niveau juridique moyennant le respect de quelques pré-requis.

Nous n'allons pas détailler ce point car nous n'avons pas encore abordé tous les pré-requis. Mais nous pouvons déjà expliquer que la signature numérique est un hash du document qui a ensuite été chiffré par un algorithme de cryptographie asymétrique (rien de compliqué, nous verrons ça dans un prochain article).

Du fait des propriétés d'un hash, on peut vérifier la validité de la signature vis à vis d'un document en recalculant le hash et en le comparant avec la signature numérique (le hash initial qui a été chiffré). Si le document a été modifié, le hash sera différent et la signature invalide pour ce document (par ailleurs, il n'est pas possible de falsifier la signature de par les propriétés de la cryptographie asymétrique)..

Usages courants en informatique

Nous mettons le focus sur la sécurité et n'abordons donc pas toute une catégorie d'usages des fonctions de hachage en informatique (généralement basées sur l'unicité et la moindre taille que la donnée hachée).

Un hash peut servir de somme de contrôle (checksum). L'exemple typique est le téléchargement d'un très gros fichier depuis un serveur web : il y a des risques non négligeables que le fichier téléchargé sur votre poste soit corrompu (un seul octet invalide suffit, si votre fichier fait des centaines de Méga-Octet et est téléchargé depuis l'autre bout du monde et passe par des lignes sous marines et un grand nombre d'équipements réseaux, il n'est pas exceptionnel que des problèmes surviennent). Pour vérifier que le fichier n'a pas été corrompu (et éventuellement de façon volontaire pour introduire un virus dans un programme par exemple, au delà des simples problèmes de communication), vous pouvez généralement télécharger un second fichier (bien souvent le résultat d'un hachage par l'algorithme MD5) : ce second fichier est le hash du fichier téléchargé. Avec l'utilitaire adéquat implémentant l'algorithme de hachage utilisé, vous recalculez le hash du fichier et le comparez avec le hash téléchargé : si ils correspondent, le fichier n'a pas été corrompu sinon vous n'avez plus qu'à relancer le téléchargement).

Conclusion (temporaire)

La sécurité est un sujet relativement complexe : si on essaye de le prendre de front c'est très obscur, mais si on commence par comprendre les briques de base, ça devient assez simple, tant qu'on ne rentre pas dans les arcanes des algorithmes (sinon un très solide bagage mathématique est requis).

Nous venons de voir une première brique, les autres suivront dans quelque temps.

lundi 27 février 2017

Open source : la base

Depuis longtemps, je constate qu'il y a une assez large incompréhension de ce qu'est le logiciel libre. Du coup, j'ai rédigé un petit article sur le sujet, histoire de dégrossir un peu le sujet.

Free ne veut pas dire gratuit

Je rentre directement dans le lard d'une fausse idée largement répandue. Le mouvement du logiciel libre est à l'origine anglo-saxon et dans la langue de Shakespeare on parle donc de Free Software. Le terme "free" peut avoir différentes traductions dont "gratuit". Cependant, ce n'est pas ce sens qu'il faut retenir ici, mais celui de liberté. Pour ceux qui en douteraient, voici un pointeur sur une saine lecture sur le site de la Free Software Foundation, un organisme qui promeut la diffusion de code source ouvert : https://www.fsf.org/about/what-is-free-software

Un logiciel "free" n'est pas dans le domaine public : quelqu'un en détient la propriété intellectuelle et son usage est soumis à une licence : vous devez respecter les conditions d'utilisation dictées par la licence, vous ne pouvez pas faire ce que vous voulez. Mais la logique qui prévaut à la rédaction de la licence est bien différente que dans le cas d'un logiciel propriétaire, et elle vous accorde beaucoup plus de droits et de libertés.

Un logiciel "free" est donc un logiciel dont vous pouvez, selon certaines conditions qui dépendent de la licence associée, utiliser le code bien sur mais également l'étudier, le modifier pour l'adapter à vos besoins ou encore le copier et le diffuser. C'est là la principale différence avec un logiciel "propriétaire" dont la licence ne vous permet que d'utiliser le logiciel (le code source n'est pas fourni, et quand bien même vous pourriez vous le procurer par décompilation, ce serait illégal) ; si vous constatez un bug, vous ne pouvez pas le corriger, si vous voulez améliorer une fonctionnalité, vous n'en avez pas le droit.

Un logiciel "free" peut tout à fait être payant. C'est d'ailleurs le modèle économique retenu par de nombreux acteurs de l'open source. Quand un tel acteur souhaite, pour des raisons X ou Y, générer des revenus grâce au logiciel qu'il a développé, il le distribue souvent selon deux modèles : une version gratuite assortie d'une licence présentant certaines restrictions qui en rendent l'usage impossible dans un cadre commercial, et une version payante assortie d'une autre licence levant les dîtes restrictions.

Certains acteurs de l'open source ne cherchent pas à se rémunérer (ils ont d'autres motivations, diverses et variées). D'autres proposent des services de consulting ou de support qui seront retenus par ceux pour qui l'outil est un élément critique (qui connaît mieux un produit que son développeur ?). Certains développent des compléments payants autour d'une base gratuite. D'autres enfin détournent quelque peu l'idée généreuse originale et proposent des versions open source très limitées qui n'ont que pour objet de pousser à l'achat d'une version payante (pot de miel).

Pluralité/Complexité des licences

Il n'existe pas un modèle de licence open source. Il en existe des dizaines, réparties en deux grandes familles. Et avec des différences qu'il est essentiel de comprendre

Précision utile : si vous développez un logiciel non commercial et à code source ouvert, vous n'avez probablement pas à vous soucier outre mesure des licences. C'est dans le cadre d'un développement commercial appuyé sur du code logiciel ouvert qu'il convient de prendre quelques précautions sous peine de sérieuses déconvenues, voire de désastre.

Dans les premiers temps de l'open source, de nombreuses fausses idées ont été diffusées, en particulier par les grandes sociétés commercialisant des logiciels commerciaux, afin d'effrayer les entreprises. Il en résulte malheureusement encore souvent des craintes infondées. Il n'est pas exceptionnel que cela constitue un frein à l'utilisation de logiciel libre dans certaines grandes entreprises peu au fait des subtilités à maîtriser. Les choses ont cependant évoluées ces dernières années, même Microsoft s'est mis à l'open source, et de nombreuses entreprises ont adopté l'open source comme levier d'innovation et de performance.

Il nous faut préciser le sens de "commercial" : c'est une application qui est commercialisée, distribuée, dont on peut acquérir un exemplaire. Un développement interne réalisé par une entreprise n'entre pas dans ce cadre. Une application commercialisée en mode SAAS étant non distribuée n'est pas non plus une application commerciale. Toutefois, nous développerons ce dernier point un peu plus loin.

Viralité de la licence

La viralité d'une licence définit le fait que le logiciel développé à l'aide du logiciel soumis cette licence virale soit lui même obligatoirement à code source ouvert (le terme exact est copyleft).

En gros, si vous utilisez pour votre projet commercial, une librairie ou un framework open source qui a une licence virale, vous avez l'obligation de fournir votre code source. Du coup, n'importe qui peut prendre le fruit de votre travail et l'utiliser à son tour. Ce pose bien évidemment plusieurs problèmes majeurs : n'importe qui peut monter un commerce concurrent au votre avec un avantage économique majeur lié au fait qu'il n'aura pas supporté le coût de l'investissement initial (le développement du logiciel). 

C'est à ce type de licence virale (licences GPL principalement) que recourent les acteurs open source qui veulent générer des revenus par de la vente de licence. Si vous ne voulez pas diffuser votre code source et que vous voulez utiliser leur code, vous devez passer par une distribution payante assortie d'une licence non virale (licences BSD, ASF, MIT, MPL ...).

Conclusion ; il est nécessaire en cas de projet commercial de bien examiner la licence de toutes les librairies, frameworks, et autres éléments logiciels open source que vous prévoyez d'utiliser afin de vérifier leur viralité. 

Précision importante : un développement spécifique interne ne sera pas distribué et ne constitue pas un logiciel commercial, même si il est commandé et acheté à un prestataire externe.

Mode SAAS

Si vous ne savez pas ce qu'est le SAAS, vous pouvez lire cet article : Formes et intérêts du Cloud computing. Sinon, en résumé lapidaire, c'est la commercialisation d'une application mise à disposition sur Internet sur un modèle de location (facturation à l'usage).

La commercialisation d'application en mode SAAS étant une tendance assez lourde, il y a une facilité à contourner les règles du copyleft (utilisation à des fins commerciales de produits open source sous copyleft sans partage du code produit, ce qui est contraire à l'idée de partage de la connaissance derrière le mouvement open-source).

En réaction est apparue la licence AGPL qui ajoute des clauses spécifiques pour prévoir ce cas.

Conclusion

Le recours aux logiciels open-source amène de nombreux avantages mais comporte également quelques risques. Toute médaille à son revers. Si l'éditeur décide de changer de stratégie et de changer son modèle de licence à partir d'une certaine version, que ferez vous ? Si vous découvrez en cours de route que les fonctions incluses dans la version gratuite sont trop limitées et qu'il vous faut la version payante, que se passera il ? Si le développement du produit est interrompu, quelles conséquences pour vous ?

La gratuité, fréquente, du logiciel ne doit pas faire négliger les autres aspects du choix.

Chaque situation est différente et une réflexion doit être menée au cas par cas. Par exemple, dans le cas d'un développement spécifique, un des rôles de l'architecte applicatif est de faire les bons choix au regard du contexte, dans le cas d'un projet SI, il ne faudra pas négliger les coûts de montée en compétence des personnels de l'IT. Toute brique technique open source occupant un rôle central dans une architecture SI ou simplement applicative doit être envisagée sous de nombreux angles.

Les compétences techniques ne sont pas suffisantes pour une prise de décision éclairée. Des aspects juridiques et stratégiques sont à considérer.

lundi 23 janvier 2017

La java des loggers

Petite plongée rapide dans le merveilleux monde du logging Java.

Les loggers

Dans le monde Java, on a pléthore de libraires de logging : 
  • LOG4J est la solution « legacy », elle existe depuis très longtemps et est largement adoptée. 
  • La version 1.4 du JDK a introduit le Java Utility Logger, JUL de son petit nom, qui est assez peu employé du fait de son arrivée tardive et de ses capacités moindres. 
  • Plus récemment, on a vu apparaître logBack qui est à mon avis le meilleur des trois et qui est celui à privilégier de nos jours, on peut le voir comme une version largement améliorée de LOG4J (qui date un peu et comporte quelques bugs gênants en utilisation avancée). 
  • Il en existe d’autres encore.

Du coup, l’architecte logiciel doit faire un choix… mais les architectes n’aiment pas se mettre à la colle avec une dépendance quand ils peuvent l’éviter. Pour cette raison, il existe des façades permettant d’abstraire l’API de log. En utilisant ces façades, on ne dépend plus d’une API de logging particulière et le client de l’API peut déployer celle qu’il préfère, il dépendra par contre de la façade. Mais on n’aura plus accès aux spécificités de tel ou  tel logger non exposées par le façade.

Les façades

Où ça se complique un peu c’est qu’il existe deux façades. La plus ancienne est Java Commons Loggin, JCL de son petit nom. Elle est largement utilisée car c’est la première à être apparue. Mais elle pose quelques problèmes dont on s’est aperçu au fil du temps, et une autre façade est apparue, Simple Logging Facade For Java, SLF4J de son petit nom. C’est aujourd’hui indubitablement le meilleur choix.

Spring utilise JCL du fait de son ancienneté, et le conserve pour des raisons de compatibilité ascendante même si ça ennuie manifestement ses développeurs (la documentation est très claire sur ce point, aujourd’hui ils prendraient SLF4J sans hésitation). Hibernate qui est plus récent s’appuie sur SLF4J, probablement comme tous les frameworks ou API récents.

Quelle différence entre JCL et SL4J ? 

La principale est la façon dont ces façades déterminent au bootstrap le logger concret à utiliser. 

JCL s’appuie sur un mécanisme dynamique de configuration et essaye de deviner quel est le logger à utiliser. Or ceci pose des soucis dans les environnements complexes avec de nombreux classloaders (typiquement un serveur d’application JEE). 

A l’inverse SLF4J s’appuie plus prosaïquement sur une dépendance qui peut être satisfaite par diverses implémentations concurrentes, la première trouvée dans le classpath étant nécessairement la gagnante (ça s’appelle un binding dans la terminologie SLF4J) : c’est plus simple et plus facile à maîtriser, par contre on a une contrainte à gérer au niveau de l’assemblage de l’application en prévoyant bien la dépendance voulue.

Regardons de plus près comment c’est implémenté. 

Une rapide incursion dans la documentation et le code source nous permettra de mieux comprendre.

L’API SLF4J fournit une interface Logger qui matérialise le concept de logger dans le code client, et une factory associé LoggerFactory. Cette factory s’appuie en interne sur une implémentation d’une interface ILoggerFactory pour fabriquer les loggers concrets. L’implémentation est déterminée au premier appel (pattern singleton) en parcourant le classpath à la recherche d’une classe org.slf4j.impl.StaticLoggerBinder (qui bien sur implémente l’interface ILoggerFactory). Cette classe n’est pas fournie dans le composant slf4j-api mais par un des « bindings SLF4J».

Donc selon le binding déployé, on obtient une implémentation différente qui renverra soit une implémentation directe de  l’interface Logger (cas du logger logBack), soit un adapter quelconque vers un framework tiers. Ainsi, un adapter vers LOG4J routera les appels sur l’interface Logger, par simple application du polymorphisme, vers les classes de LOG4J ; un adapter vers JUL fera de même mais vers les classes du JDK.

Si vous êtes attentif, vous devez vous demander comment on peut compiler SLF4J vu qu’il a une dépendance sur des classes qui ne sont pas dans son code source et dont il existe une multitude d’implémentation. Et comment il se fait que si on oublie de déployer le binding, on ne se prend pas une ClassNotFoundException mais un joli message bien travaillé. La réponse est bien entendu l’utilisation des mécanismes de réflexion (qui permettent de référencer une classe de façon dynamique).

Voici pour le mécanisme de base de SLF4J qui se base donc sur le mécanisme de classloading java pour obtenir de façon totalement agnostique une implémentation. C’est en quelque sorte du lazy binding, le binding entre la façade et le logger concret est effectué au runtime.

JCL fournit une interface Log qui a exactement le même rôle que l’interface Logger dans SLF4J, et bien sur une factory associée LogFactory. LogFactory est une classe abstraite et l’implémentation par défaut est LogFactoryImpl qui fait partie de JCL. Contrairement à SLF4J, cette factory ne délègue pas le job à une classe tierce déterminée au runtime, mais fait le travail elle-même via un algorithme de découverte dynamique (voir la javadoc de la classe org.apache.commons.impl.Log.LogFactoryImpl  pour le détail).

Rappel rapide des principes de fonctionnement

Rappelons rapidement le mécanisme de base : une application qui veut loguer obtient un logger via l’appel à la factory de l’API puis utilise les méthodes de cet objet pour loguer des messages avec un niveau associé (debug, info, error …). A un logger est associé un niveau de log (tout log de niveau inférieur produit avec ce logger sera ignoré) et un éventuellement un ou plusieurs appenders. Un appender est chargé d’écrire le log (dans un fichier, sur une socket, dans une base de données …), et accessoirement dispose également d’un niveau de log.

Un logger correspond basiquement à une chaîne de caractère organisée de façon hiérarchique à la façon des noms de domaines ou des noms de package (x.y.z). De ce fait tout logger à un père (x.y est le père de x.y.z et a comme père x, qui a comme père « root »). Quand on logue sur un logger et qu’il n’a pas d’appender associé, c’est celui de son père qui va jouer, s’il n’en n’a pas non plus ce sera le grand-père etc. jusqu’au sommet de la hiérarchie appelé rootLogger. Et c’est généralement sur le rootLogger qu’on branche un appender (on peut aussi en brancher sur les niveaux inférieurs par exemple pour séparer les logs par couche applicative, ou par brique technique, ou pour surveiller plus particulièrement le comportement d’un composant. On est ici sur des choix de design effectués par l’architecte logiciel). 

La configuration de quel appender est associé à quel logger (et tous les autres éléments de configuration comme les level ou les formats des messages) peut se faire de façon programmatique via l’API du logger (directement, pas de couche d’abstraction de ceci dans les façades) ou plus généralement via un fichier (properties ou XML).

Cohabitation JCL / SLF4J

Un souci survient quand on a dans une application diverses briques qui utilisent pour certaines JCL et d’autres SLF4J, si on veut regrouper toutes les écritures de logs dans un même fichier par exemple.

Imaginez que vous avez dans votre application des composants basés sur JCL et d’autres sur SLF4J. Il faut vous assurer que ces deux composants vont utiliser les mêmes loggers pour éviter d’avoir des appenders écrivant des logs de façon concurrente sur des canaux distincts. Et ici commencent les difficultés… 

Alors, je ne vais pas faire ici le tour de la question, ce serait un peu long et ce n’est pas mon objet dans cet article mais si vous avez compris ce qui est exposé plus haut vous devez comprendre qu’il faut déjà s’assurer que les deux factory de log concurrentes (celle de JCL et celle du binding SLF4J) vont s’appuyer sur la même API de log. 

Puis pourront venir des problèmes liés au fait que les classes des API de logging pourront éventuellement être chargées par des classloaders différents, et là ça devient assez compliqué car les mécanismes en question sont spécifiques par exemple au serveur d’application utilisé, à sa configuration, à sa version, et à la façon dont les APIS sont intégrées.

Bien, je vais maintenant vous donner une bonne nouvelle. Ce n’est pas la panacée absolue mais ça permet de simplifier la problématique : SLF4J fourni un mécanisme qui permet de rediriger les logs produits par JCL vers SLF4J, et de là vers l’API de logging bindée. C’est un bridge JCL-SLF4J. Et nous allons étudier rapidement son principe de fonctionnement, juste pour le fun. Ca ira très vite car c’est en fait très simple, et très crade. Mais pourquoi crade ?

En matière de design des systèmes selon le paradigme objet, il existe des grands principes, il en existe même des chiées, parfois contradictoires les uns avec les autres, mais c’est là le travail de l’architecte de privilégier tel ou tel principe selon ses priorités. Et ici on viole brutalement un des principes les plus sacrés, c’est plus du hack qu’autre chose à mon sens, m’enfin si c’est brutal il faut reconnaître que c’est efficace. Et il faut relativiser, pour avoir étudié en détail quelques frameworks open source ou interne aux API du JDK (tiens au hasard, JAAS, le framework de sécurité de la plateforme java), je peux témoigner que nos grands gourous ne se privent pas de prendre des raccourcis, dans le genre « faîtes comme je dis, pas comme je fais ». Ceci dit, quand on veut faire des choses totalement génériques, le paradigme objet comme le langage Java atteignent leurs limites, et parfois le design de certains composants ne laisse pas le choix. Ce n’est pas un hasard s’il existe des langages dynamiques, et si le JDK lui-même embarque des capacités de scripting.

Bref, le bridge JCL over SLF4J ré-implémente tout simplement l’API JCL. Oui, vous avez bien lu, il écrase les classes JCL publiques par les siennes (même classes, même packages). A partir de là, c’est un jeu d’enfant de rediriger les appels vers les API SLF4J, la suite vous la connaissez. Bien sûr, pour que ça fonctionne il faut ici aussi veiller au grain lors du déploiement ; le jar du bridge doit être avant le jar JCL dans le classpath (le mieux étant de ne pas l’avoir mais ici on peut rencontrer des problèmes car c’est souvent une dépendance interne des serveurs d’application, et on retombe dans des soucis de classloading).

Allons un peu plus loin

Allons encore un peu plus loin. Je m’appuie sur un exemple. J’ai Bonitasoft (une solution BPM Java, mais peu importe, disons simplement une webapp déployée sous tomcat) qui utilise SLF4J et Spring (basé sur JCL) et Hibernate (basé sur SLF4). 

Tout ce petit monde est déployé sous Tomcat qui lui aussi utilise JCL pour ses propres logs. Bon vu comme ça, on peut se dire que ça ne va pas être un poème, mais en fait tout est déjà solutionné par l’intégration Bonita/Tomcat qui est plutôt très bien faîte. On a un joli fichier de configuration logging.properties, une documentation propre, et des templates dont s’inspirer. Le système de logger concret est JUL (enfin presque comme on va le voir). 

Mais à l’examen de ce fichier de configuration, je découvre une syntaxe absolument pas conforme à la façon dont se configure JUL. Creusons.

Comme j’aime bien comprendre, je me plonge un peu plus avant dans la documentation Tomcat (ici : http://tomcat.apache.org/tomcat-7.0-doc/logging.html) et je vois des choses un peu bizarres. 

On commence par vous expliquer qu’on utilise JCL mais que depuis la version 6 Tomcat utilise sa propre version dans des packages renommés. C’est quoi encore cette sombre bidouille ? 

Histoire d’en avoir le cœur net, je télécharge le code source de Tomcat, et effectivement ils n’utilisent pas JCL mais un truc à eux qui ressemble à JCL comme deux gouttes d’eau mais qui n’est pas JCL

Ça s’utilise comme JCL mais ce sont des classes spécifiques à Tomcat et le mécanisme de découverte dynamique de JCL a été supprimé et remplacé par du code qui bootstrape directement le logger utilisé en interne. 

Ça m’inspire deux questions :

·         à quoi ça sert d’avoir une couche d’abstraction qui code en dur l’utilisation du logger concret ? La réponse est que la distribution Tomcat fournit d’autres implémentations de leur bouzin, et la documentation associée, pour écraser leur implémentation par défaut par une autre qui n’est pas hardcodée et permet d’utiliser un autre logger concret. Même principe qu’avec le bridge JCL-SLF4J, on écrase les classes par d’autres.
·         Si JCL posait tant de problèmes qu’on a dû le remplacer par autre chose, tant qu’à devoir passer sur tout le code pour le refactorer, pourquoi pas avec SLF4J qui fonctionne très bien et est un standard de fait, plutôt qu’une implémentation maison exotique ?

Bref, je continue ma lecture de la documentation et du code source. L’implémentation de Log renvoyée par la factory semble être essentiellement un passe-plat vers JUL  (un adapteur), avec juste un petit bloc d’initialisation statique qui modifie la configuration par défaut de JUL sur des points mineurs.

A ce stade, je n’ai toujours pas compris comment est géré le bootstrap de JUL. Je sais qu’il est spécifique car le format du fichier de configuration supporte des options non standards et que j’ai bien vu une différence de comportement. 

Finalement, je trouve que l’explication réside dans une implémentation spécifique de l’interface LogManager de JUL ; cette interface est en charge de gérer la configuration de l’arbre des loggers en mémoire.

Cette implémentation spécifique se justifie et est expliquée dans la documentation. Elle permet de gérer un jeu de configuration par webapp, et elle permet de gérer correctement la libération des ressources en cas de déchargement d’une webapp pour éviter les fuites mémoire (j’ai regardé vite fait, à priori c’est la mise en œuvre d’une WeakHashMap qui apporte ça).

Conclusion

Voilà, pour ce petit tour rapide. Comme on peut le voir, dans le monde Java on ne fait pas toujours dans la simplicité.

L’exercice sur Tomcat pourrait être renouvelé sur la plupart des autres serveurs JEE, mais pas toujours avec le code source disponible … 

lundi 29 août 2016

Sécurite - Vol 1 : définitions

L'utilisation croissante d'outils informatiques divers, et les données de plus en plus sensibles que nous leur confions, font de la sécurité une problématique de plus en plus prégnante. Pour autant c'est un sujet souvent mal compris par les utilisateurs qui sont pourtant régulièrement impactés dans leurs usages par les procédures mises en oeuvre, sans nécessairement comprendre le pourquoi ni le comment.

Le sujet est complexe et nécessite d'être abordé progressivement. Nous allons tenter de donner un premier niveau de compréhension des problèmes et solutions. Comme d'habitude sur ce blog, notre objectif n'est pas de tenir des propos d'experts mais de vulgariser le sujet et donner les informations clés pour faciliter un éventuel travail complémentaire du lecteur intéressé.

Dans ce premier article nous expliquons les enjeux. Les articles suivants exploreront divers aspects des solutions usuelles et expliqueront les bases techniques requises (cryptographie en particulier).

La donnée au cœur de la problématique : DICP

Tout d'abord il est important de préciser ce qu'un professionnel de l'informatique entend par "sécurité" car ce n'est pas nécessairement la même chose que le grand public qui se focalise généralement sur la confidentialité.

Tout le monde a entendu parler du vol de données par d'audacieux pirates qui s'emparent des données de tel ou tel site web. Récemment, un site organisant des rencontres extra-conjugales s'est fait voler ses données et ces dernières ont été mises en ligne publiquement, conduisant à au moins deux suicides de personnes ne supportant pas de voir leurs infidélités, avérées ou non, dévoilées sur la place publique. Des "people" se sont fait voler des photos intimes dénudées qui ont fait la joie des voyeurs. Wikileaks est à l'origine de crises diplomatiques. Les exemples ne manquent pas. Ici, on est face à des problèmes de confidentialité de la donnée.

Egalement dans l'actualité récente, des pirates travaillant pour le compte de l'Etat Islamique ont mené des attaques de types DDOS (Distributed Deny Of Service) sur des sites de l'état afin de les rendre indisponibles. Rappelons qu'une attaque de ce type vise à solliciter un site en le bombardant de requêtes de façon à dépasser ses capacité de traitement et le faire tomber en panne. Ici, on est face à un problème de disponibilité de la donnée (le site étant indisponible, il ne peut plus délivrer la donnée).

Les mêmes pirates après les attentats du 13 novembre à Paris ont modifié les pages d'accueil de sites destinés au grand public, comment par exemple le site de France 5, afin de remplacer les contenus initialement publiés par des messages de propagande. Ici, on est face à un problème d'Intégrité de la donnée (l'information publiée "les terroristes ont commis un attentat abominable" est devenue un bullshit du genre "les héros du jihad ont puni les infidèles" ce qui bien sur n'est pas le message que voulait délivrer le rédacteur).

Plus récemment, après cette fois les attentats de Nice, l'application "alerte attentat" que l'état avait fait développer afin d'envoyer des messages d'alerte au public (enfin pour ceux équipés d'un smartphone Apple ou Android, ayant une couverture réseau pour les data, et ayant activé l'application... ) a totalement foiré : les messages d'alerte sont arrivés très longtemps après la bagarre car l'application était indisponible le moment venu. Encore un problème de disponibilité (de la donnée "une attaque est en cours à Nice, allez vous mettre à l'abri, évitez la zone") mais qui cette fois ci n'est pas lié à une attaque du système informatique.

Au travers de quelques exemples, nous avons mis en exergue les 3 aspects de la sécurité :
  • D pour Disponibilité de la donnée
  • I pour Intégrité de la donnée
  • C pour Confidentialité de la donnée

Auxquels il faut en ajouter un quatrième : P pour Preuve. Il s'agit ici de tout ce qui touche, en gros, aux logs qui permettent après la survenue d'un problème (comme la corruption ou l'indisponibilité d'une donnée) de déterminer
  • comment il est survenu, donc pour permettre d'analyser le problème et faire les corrections nécessaires
  • qui est responsable (notion de preuve) et qui doit éventuellement supporter les conséquences, financières et/ou judiciaires, du problème survenu
Les logs c'est le jargon informatique pour désigner les traces que laisse tout programme, principalement dans des fichiers dits de journalisation, sur ce qui se passe en interne, ou sur les actions sensibles menées par des opérateurs humains.

La sécurité du système d'information c'est la bonne prise en compte de ces 4 aspects, résumés dans l'acroyme DICP, à tous les niveaux (conception, exploitation, utilisation).

Firewall, antivirus etc.

Nous venons de définir ce qu'est la sécurité d'un système d'information et pour autant nous n'avons aucunement cité les premiers sujets qui viennent à l'esprit de nombreuses personnes quand on aborde le sujet. 

Le firewall a été popularisé par les conneries débitées dans les films et séries, et tout le monde a entendu parler des méchants virus informatiques et des antivirus qui les combattent.

Firewall comme antivirus ne sont que des moyens. Ce sont des éléments, certes importants, de la politique de sécurité (qui vise à garantir DICP des données) mais ce ne sont que des éléments parmi d'autres.

Pourquoi installons nous des antivirus (et les maintenons nous à jour, nous assurons nous que les utilisateurs ne peuvent les désactiver etc.) ? > Pour nous prémunir contre des virus. 

Pourquoi nous prémunissons nous des virus ? > Car les virus vont avoir une action malveillante qui impactera le DICP. Ils vont surveiller vos frappes au clavier et vous voler vos identifiants et mots de passe, ce qui compromet la Confidentialité et fausse les Preuves, ou mettre en place divers mécanismes pour atteindre ce même objectif. Ils vont supprimer ou modifier vos fichiers ce qui compromet l'Intégrité. Ils vont utiliser votre ordinateur pour faire des actions malveillantes (attaque ddos, spam, diffusion de virus ...) et ce faisant le priver d'une partie de sa capacité de traitement et compromettre la Disponibilité.

Quel est le rôle d'un firewall ? Interdire l'accès au réseau interne aux personnes non autorisées et donc, entre autre, garantir la Confidentialité et l'Intégrité des données.

Politique de Sécurité de l'Information

Nous avons parlé jusque ici de sécurité du système d'information (ou du système informatique, c'est la même chose).

Mais le système d'information n'est qu'un outil, qui sert à gérer de l'information, et ce qu'on cherche à protéger in-fine c'est l'information. Et il faut donc commencer par définir une politique de sécurite de l'information. Un simple exemple : à quoi bon dépenser des millions pour sécuriser à outrance les données stockées dans votre SI vis à vis du monde extérieur, si tout le monde ou peu s'en faut dans l'entreprise y a accès et sans avoir conscience des enjeux économiques associés ni être responsabilisé ?

La politique de sécurité du SI n'est qu'un élément de la politique de sécurité de l'information (un élément essentiel de nos jours mais pas le seul élément).

La politique de sécurité de l'information doit définir les informations importantes et leur sensibilité en terme de DICP. En effet, ce sont ces exigences qui vont guider la construction de la politique de sécurité du système d'information et elles ont un impact majeur en matière de coût.

Par exemple, si le besoin de disponibilité est très important, il va falloir mettre en place des solutions de haute disponibilité avec de la redondance sur tous les éléments, un site de secours informatique permettant de redémarrer très rapidement en cas de sinistre majeur, impliquant de la réplication en temps réel entre les deux sites et donc la location de liens réseaux à très haut débit etc.

Nul besoin d'être un expert pour comprendre que deux sites informatiques, ça coûte grosso modo le double d'un seul site... Votre société préfère peut être se trouver sans outil informatique pendant quelques jours, que supporter en permanence le coût d'une capacité de redémarrage en 1 Heure pour un sinistre dont la probabilité de survenance est somme toute assez faible. Des procédures manuelles dégradées et un processus de reprise progressif sur quelques jours sont sans doute suffisants. Mais si vous gérez un aéroport ou une base de missile nucléaire les choses sont différentes...

Je vous suggère la lecture de l'article en lien qui donne un très bon exemple et une très bonne explication des DICP de façon très amusante et en Français tant qu'à faire.

Quelques données clés au sujet de la sécurité

La sécurité est l'affaire de tous, à commencer par les utilisateurs des systèmes qui en constituent le principal maillon faible. L'ingénierie sociale est un des principaux moyens utilisés par les pirates pour détourner les mesures de sécurité mises en place par les organisations.


La sécurité ne relève pas que des informaticiens et de la mise en oeuvre de moyens technique ; il y a aussi et entre autre des aspects organisationnels ou de gestion RH. Par exemple, il faut penser à désactiver les comptes des collaborateurs quittant la société, sensibiliser les utilisateurs, identifier les responsables de la sécurité et les former, organiser les locaux ...


La sécurité maximale du SI est la sécurité de son élément le plus faible. Imaginez un SI super sécurisé au niveau réseau et pour lequel on permettrait un accès administrateur depuis un poste hébergé dans un local dont la porte ne fermerait pas a clé.

Il existe des méthodologies pour vérifier la prise en compte des contraintes DICP sur lesquelles s'appuient les consultants en sécurité pour mener des audits. Les formations relatives à la sécurité se développent, il y a un marché en plein essor en la matière.

Il existe des certifications qualité pour garantir que les organisations ont le souci et sont organisées d'une façon satisfaisante au regard du DICP. Le respect de telle ou telle certification est une exigence de plus en plus courante pour des grands contrats.

Il y a une prise de conscience forte de l'état sur l'importance de la sécurité compte tenu de la digitalisation croissante de l'économie et des risques de cyber-attaques pouvant gravement déstabiliser un état ou une économie. L'état s'est doté d'une agence de sécurité et embauche à tour de bras. Des opérateurs d'importance vitale (OIV) sont identifiés et se voient imposés par la loi des normes et règles en matière de sécurité.

Focus sur l'exemple "Alerte attentat"

La raison du dysfonctionnement était que suite à des travaux de génie civil (un bien grand mot pour parler d'ouvrier qui ont fait une tranchée dans le sol) le câble réseau raccordant le datacenter où était hébergée l'application a été coupé, ce qui a entraîné un dysfonctionnement de l'application.

Les sondes surveillant le bon fonctionnement de l'application et sur lesquelles s'appuyait la supervision (la surveillance du bon fonctionnement) ont données de mauvaises informations et laissé croire que l'application fonctionnait correctement après rétablissement de la connexion réseau.

Quand on a eu besoin de l'application, à priori dans les minutes qui ont suivi l'attentat de Nice (supposition, il y a peut être ici aussi eu des dysfonctionnements et des retards dans l'activation du système d'alerte) on s'est rendu compte du problème et il a fallu un long moment pour redémarrer le système (ce qui en soit n'est pas normal non plus).

Une première remarque : un datacenter digne de ce nom doit disposer de deux accès réseaux redondés de façon à ce que ce type d'incident, pas si rare, n'ait pas d'incidences. Ensuite, pour une application aussi critique, le bon sens aurait voulu qu'elle soit installée sur deux sites (deux datacenters) distincts et suffisamment distants géographiquement. Ces deux mesures de simple bon sens auraient permis d'apporter ce qu'on appelle la Haute Disponibilité (voir mon article sur la HD disponible ici), et ce d'autant plus facilement que la solution s'appuie sur une couche de virtualisation (voir mes articles sur la virtualisation ici, ici et ici). La Haute Disponibilité est un moyen au service de la politique de sécurité (plus particulièrement de l'aspect Disponibilité).

Ensuite, j'estime qu'une application bien conçue doit être capable de supporter une perte et un rétablissement de la connexion réseau. Il suffit de prendre cette considération en compte dans la phase de conception technique, les solutions existent. Enfin, la supervision a manifestement été bien mal conçue puisqu'elle affichait un voyant vert où on aurait du avoir des alertes en rouge clignotant partout. Bref, un amateurisme bien difficile à accepter s'agissant d'une application qui est censée protéger des vies humaines et qui doit être financée, conçue et exploitée en conséquence.  Ici aussi on est sur un problème de disponibilité et on voit que cette problématique de sécurité doit être prise en compte dans la conception, et donc en amont dans la spécification et l'expression du besoin qui en est à l'origine. La sécurité doit être prise en compte à tous les étages.

Face à cet échec, des corrections sont à apporter (et ont à priori été apportées). Mais au delà, il peut être intéressant d'établir les responsabilités respectives des différents intervenants du projet :

  • la MOA (l'état qui a rédigé le cahier des charges, défini le planning, financé l'opération, validé la solution) a elle exprimé le besoin de Haute Disponibilité, suffisamment financé l'opération pour permettre cette mise en oeuvre, vérifié le bon fonctionnement ? N'a elle pas imposé ou accepté un planning ne prévoyant cette mise en HD qu'ultérieurement (voire pas du tout) ?
  • la MOE (le prestataire qui a conçu et réalisé l'opération) a elle bien fait son travail, a elle rempli son devoir de conseil en alertant la MOA sur un besoin de HD non exprimé ou non financé, a elle bien sélectionné l'hébergeur (si ce n'est pas l'état qui l'a imposé ce qui est tout à fait probable dans le cas présent) ?
  • l'hébergeur (la société qui est en charge des serveurs physiques sur lesquels est installée l'application, et de leur connexion Internet) offrait il le niveau de sécurité requis ?
  • l'exploitant (la société en charge de la supervision applicative c'est à dire de surveiller le bon fonctionnement et de rétablir la situation en cas de problème, ici la même que l'hébergeur à priori). A priori il semble hors du coup car le mauvais fonctionnement des sondes ne peut guère lui être opposé, un exploitant  ne fait qu'utiliser les outils qu'on lui fournit en suivant des procédures qu'on lui fournit. Si ces outils ou procédures sont défaillants, il ne peut pas en être responsable, sauf dysfonctionnement manifeste qu'il n'aurait pu que constater et qu'il n'aurait pas signalé.
Ici on voit l'importance de bien contractualiser et de disposer des logs permettant de comprendre l'origine d'un problème afin de pouvoir se retourner contre le responsable et obtenir des dédommagements ou le faire condamner en cas de conséquence condamnable au civil ou au pénal. La sécurité doit être prise en compte à tous les étages.

Conclusion (temporaire)

La sécurité est un sujet d'actualité et qui ne cesse de prendre de l'importance.

Tout utilisateur régulier de site internet ou d'applications mobiles a pu voir apparaître de nouveaux usages en lien avec la sécurité, même si ils n'ont pas forcément fait le lien :
  • généralisation de techniques de double authentification : par exemple envoi de sms sur votre portable avec un mot de passe temporaire
  • possibilité d'utiliser ses identifiants de réseaux sociaux (FaceBoox, LinkedIn, Google+...) sur de multiples sites sans devoir se créer à chaque fois de nouveaux identifiants
  • demande d'autorisation pour autoriser à des applications d'accéder à certaines données personnelles gérées pour vous par diverses applications (réseaux sociaux ou autre)


Cette rapide  introduction visait à préciser que la sécurité du SI s'inscrivait dans un cadre plus global visant à la sécurité de l'information, qu'elle ne relevait pas uniquement des informaticiens et des moyens informatiques, et que son champ d'application était bien plus développé que ne l'imaginent probablement les néophytes sur le sujet.

Dans les prochains articles nous expliquerons rapidement les quelques principes de base en cryptographie dont la compréhension est requise, et nous mettrons un focus sur les problématiques d'authentification et d'habilitation.

dimanche 22 mai 2016

Docker, tour d'horizon rapide

Une précédente série d'articles a introduit la virtualisation, ses usages, et son rôle dans le développement de l'offre Cloud, en particulier IAAS et PAAS.

Vous êtes maintenant armés pour aborder le nouveau sujet qui fait le buzz depuis 2 ans et qui ne cesse de monter : Docker !

Si la virtualisation, les termes IAAS PAAS SAAS, la gestion de configuration, sont des termes abstraits, je vous recommande de commencer par lire ces articles précédents qui introduisent toutes ces notions :



Déjà une précision : Docker est une technologie de conteneurisation, et au delà de Docker nous allons nous intéresser à cette notion de container. Docker est le produit phare dans ce domaine mais il n'est pas le seul et l'offre est probablement amenée à se diversifier fortement

On peut aborder Docker et la notion de container sous différents angles. Un angle très technique consisterait à expliquer comment ça fonctionne, ce qui nous amènerait inévitablement à devoir aborder des notions systèmes avancées, avec un pré-requis important sur le fonctionnement interne d'un système d'exploitation Linux. Nous n'allons pas prendre ce chemin, j'aborderais quelques points mais tant mes compétences en la matière que le vocation de ce blog me font privilégier une approche plus axée sur les usages.

L'idée de base du container

Comme le nom l'indique, un container est une espèce de boite logique, virtuelle, dans laquelle on enferme certains éléments pour les isoler du reste du monde.

Pensez à une boite fermée dans laquelle vous stockez des aliments dans votre cuisine. Remplacez la boite physique par une boite virtuelle, les aliments par des fichiers stockant des données binaires représentant des programmes et des données, et la cuisine par un serveur et vous devez comprendre à peu près l'idée. 

On parle bien sur de serveur physique ici, un ordinateur sur lequel on fait tourner un système d'exploitation, Linux dans le cas de Docker.

Vous pouvez donc avoir plusieurs containers sur votre serveur, de la même façon que vous pouvez avoir plusieurs boites dans votre cuisine. L'avantage est que les aliments d'une boite n'iront pas, par exemple, imprégner de leur odeur les éléments d'une autre boite. Et dans le serveur l'objectif est le même, les données et programmes d'un container n'iront pas interagir avec ceux d'un autre container.

L'intérêt est que comme vos boites se partagent la cuisine, ses étagères et son frigo, les containers se partagent un certain nombre de ressources à commencer par le système d'exploitation. Imaginez un peu si deviez avoir un placard ou un frigo distincts pour chaque aliment, ça vous coûterait cher et ça vous prendrait plein de place. Mais grâce aux boites hermétiques, vous pouvez tout ranger côte à côte.

J'arrête là les métaphores culinaires, je pense que l'idée de base est posée.

En terme informatique, on obtient la possibilité pour un serveur physique de fournir davantage de services grâce à la mutualisation de ses ressources entre divers containers fournissant chacun un service. Sans cette technologie, si on a 10 containers et donc 10 services, il nous faudrait 10 serveurs avec chacun un système d'exploitation supportant un service. Ou encore, un serveur physique avec un hyperviseur et 10 machines virtuelles chacune hébergeant un système d'exploitation supportant un service.

Et bien sur comme vous l'aurez deviné, 10 serveurs et 10 licences d'OS ou encore 1 gros serveur de VM, 1 licence pour un hyperviseur, et 10 licences d'OS ça coûte plus cher que la solution où on a un seul serveur, qui a bien moins besoin de puissance que le serveur de VM, avec 1 seul OS et 10 containers.

Pourquoi le serveur qui héberge 10 containers a il moins besoin de puissance qu'un serveur qui héberge 10 VM ?

Point besoin d'être un grand crack en informatique pour comprendre. L'hyperviseur consomme des ressources, et 10 VM ça veut dire 10 OS qui chacun consomment des ressources (et en outre elles émulent le matériel ce qui a aussi un coût), alors que dans le cas du container on n'a ni hyperviseur, ni émulation, et un seul OS qui tourne (qui embarque un démon Docker, c'est à dire un service en tâche de fond qui tourne en permanence).

Alors bien sur, toutes choses étant égales par ailleurs, cet avantage se paye ailleurs par des inconvénients, mais nous y viendrons plus loin.

J'en termine sur cette introduction sur la notion de container pour parler des usages qui sont faits de cette technologie :
  • exploiter des plateformes multi-utilisateur : un seul système d'exploitation qui est partagé par un grand nombre d'utilisateurs (bien sur connectés à distance, avec par exemple le bureau à distance Windows, ou avec une solution de DAAS comme le propose Citrix par exemple). On a un container par utilisateur qui isole ses données et programmes de ceux des autres utilisateurs simultanés.
  • exploiter de nombreux programmes sur un seul ordinateur de façon à limiter les coûts matériel

C'est ce second usage qui va nous intéresser, et en particulier sa mise en perspective avec les solutions de virtualisation qui permettent également de répondre à ce même besoin.

Container vs Machine virtuelle

La technique de conteneurisation a certaines similitudes avec la virtualisation au niveau des usages ; elle permet d'atteindre de façon différente, avec des avantages et des inconvénients, certains des avantages clés procurés par la virtualisation.

Du fait des ces similitudes, on qualifie souvent Docker, la solution phare, de solution de virtualisation légère pour l'opposer aux hyperviseurs qualifiés de virtualisation lourde. C'est à mon sens un abus de langage, Docker n'étant pas une solution de virtualisation. Simplement, il entre en concurrence avec la virtualisation sur certains cas d'usages.


L'isolation des environnements est un point important. Il ne serait pas acceptable de faire tourner de multiples services sur une même machine physique si ils pouvaient se perturber mutuellement. Cette isolation est assurée par l'hyperviseur dans le cas de la virtualisation et par le logiciel de conteneurisation, disons Docker, dans le cas des containers. Et ici la virtualisation gagne la manche sans aucune discussion possible, l'isolation est bien plus sure et le risque d'avoir un service qui fait dysfonctionner les autres bien moins grand.

La consolidation de multiples serveurs sur un seul serveur physique. C'est l'avantage économique majeur qui a permis à la virtualisation de s'installer depuis 10 ans comme une technologie incontournable. Ici le match est plus serré et dépend fortement des besoins à satisfaire. Comme nous l'avons déjà vu, la conteneurisation est plus optimale en terme de ressources requises et permet donc de consolider davantage de serveurs et donc de réaliser des économies plus importantes. Mais il y a une contrainte forte ; alors qu'avec un hyperviseur vous pouvez faire tourner à peu près n'importe quel système d'exploitation courant, tous les containers se partagent le même OS et donc doivent impérativement tourner sous le même OS, Linux en l’occurrence pour Docker.

Automatisation

La conteneurisation n'est en rien une idée nouvelle et diverses technologies, essentiellement propriétaires, existent depuis bien longtemps, notamment au niveau des systèmes Unix.

En fait, on peut même faire le rapprochement avec un style d'architecture logicielle qu'on appelle le multi-tenant (multi-tenancy) et qui vise à permettre la mutualisation d'un élément utilisé pour rendre un même service dans différents contextes d'utilisation. Simplement ici, l'élément factorisé au lieu d'être un logiciel serveur quelconque ou une application métier commercialisée en PAAS (contexte le plus fréquent de mise en oeuvre du principe) est l'OS lui même.

Linux a des capacités en la matière depuis longtemps, inspirées des Unix propriétaires, mais elles ont été étendues de façon astucieuse par les auteurs de Docker. En particulier, ils ont ajouté la capacité de gérer des modèles de container qu'on peut stocker, référencer, mettre à disposition ... et les outils permettant de les déployer avec une grande facilité et une très grande vitesse. Et ainsi procuré à l'outil un avantage important par rapport aux solutions de virtualisation.

Ainsi, en couplant un repository (un endroit où on stocke des définitions de container) avec un outil simple d'utilisation disponible sur un système Linux équipé du logiciel Docker, on obtient la possibilité d'automatiser le déploiement des environnements avec une grande facilité (chaque environnement étant un container).

De la même façon qu'un développement logiciel bien organisé s'appuie sur un repository de composants (librairies de code, frameworks) et des outils de build automatisant leur téléchargement et leur déploiement (ici le déploiement c'est l'intégration du composant dans le produit final issu du build), on a des repository Docker et les outils Docker associés. Pour faire le parallèle avec le monde du développement Web Java, Docker fournit à la fois le repository Maven et l'outil Maven avec le plugin qui va bien (ou encore un équivalent npm ou bower côté développement front). 

On utilise parfois le terme terme Infrastructure As A Code pour désigner cette capacité. Cette capacité est très importante en ingénierie logicielle car elle améliore la gestion de configuration en permettant de gérer les versions de l'environnement d'exécution d'un programme (la définition d'un container, ce qui est quelque chose de léger) avec ou en parallèle du code du programme proprement dît. Toujours pour faire un parallèle avec le développement Java/Web c'est l'équivalent du stockage du pom.xml Maven avec le code source (pour ceux à qui ça parle).

Un des articles sur la virtualisation cité en préambule détaille l'intérêt de la capacité à reproduire de façon automatisée un environnement et cite un certain nombre d'outils existants et utilisés conjointement avec les solutions de virtualisation (Vagrant and co). Docker apporte les mêmes capacités mais de façon plus simple et mieux intégrée. Et surtout... déployer et démarrer un container Docker est une affaire de secondes, là où la même opération pour une machine virtuelle est infiniment plus lourde.

DevOps

La démarche DevOps est à la croisée de nombreuses tendances (en matière d'organisation des DSI, d'architecture logicielle, d'outils, de démarche agile ...) et on ne saurait la résumer en quelques mots tant elle impacte de nombreux aspects du métier. 

Un de ses aspects clés est de casser la barrière existant entre les équipes de développement d'une part (Devs), et les équipes d'exploitation d'autre part (Ops). Les premières travaillent à fabriquer les logiciels utilisés dans l'entreprise, les secondes à les mettre à disposition des utilisateurs et à s'assurer qu'elles fonctionnent correctement et avec des coûts de fonctionnement maîtrisés. 

Je détaillerais ceci dans un article futur sur le sujet mais pour le moment ce qui nous intéresse est de savoir que ces équipes travaillent chacune sur des environnements différents qui sont, dans une DSI correctement organisée selon les cadres méthodologiques de référence, totalement étanches. Or, il est essentiel que ces environnements soient identiques afin d'éviter des différences de comportement des logiciels entre par exemple le serveur de test utilisé par les développeurs pour le test et la mise au point des programmes, et le serveur de qualification utilisée par la maîtrise d'ouvrage pour qualifier le bon fonctionnement, ou encore le serveur de production utilisé par les vrais utilisateurs.

Et ici Docker apporte une vraie plus value en permettant le partage des environnements (de la définition des containers stockée dans un repository commun par exemple) entre les deux équipes. C'est une autre des raisons de son succès.

Docker peut donc être cité comme un des outils favorisant l'adoption d'une démarche DevOps dans une DSI.

Cloud

Les capacités natives d'automatisation du déploiement des environnements, la forte capacité de consolidation de nombreux environnement sur un serveur physique, et le fort intérêt de la profession envers Docker ont amené tous les grands acteurs du Cloud à mettre en place des offres basées sur Docker, en particulier pour les offres de PAAS.

Et les choses choses vont au delà. Pour offrir de la haute disponibilité, il s'avère nécessaire de gérer des clusters de containers, c'est à dire des ensembles de containers coordonnés sur des machines physiques différentes. Ceci est indispensable pour le support de la tolérance de panne par exemple, mais également utile pour permettre l'ajustement dynamique des capacités de traitements aux besoins ce qui est une caractéristique essentielle du Cloud.

La gestion de repository de container est également un autre aspect, tant pour permettre aux organisation de gérer leurs containers, que fournir des containers "clés en mains" (ce qu'on appelle des appliances) pour répondre aux besoins courants.

Signe de l'intérêt pour Docker et de son adoption, divers outils sont apparus :
  • Google a mis à disposition Kubernetes qui a reçu un accueil très favorable
  • Docker fournit Swarm
  • La fondation Apache (acteur incontournable de l'open source) a étendu son offre Mesos pour prendre en compte Docker

Le temps et la place me manquent pour entrer plus dans le détail de ces sujets passionnants. Si vous devez retenir une chose, c'est que ces outils permettent à Docker de passer à une dimension supérieure et le signe indubitable du grand intérêt de la profession pour cette solution. Pour le reste, Google is your friend ;-)

Adoption de la technologie

Il semble indéniable que la technologie Docker est plus qu'un effet de mode. Elle est soutenue par tous les acteurs majeurs de l'industrie qui investissent.

Quelques éléments à l'appui de cette affirmation.

Un consortium a été créé ce qui est un signe favorable car la mise en place d'une gouvernance autour du sujet est essentielle pour éviter l'apparition de multiples chapelles et d'incompatibilité qui peuvent conduire une belle idée à l'échec.

Microsoft met les bouchées doubles pour le support de Docker, dans son offre Cloud Azure bien sur, mais également dans son offre de systèmes d'exploitation ce qui est déjà plus surprenant. Il y a également des rumeurs de rachat de la société Docker par Microsoft.

Le support de Google s'exprime de diverses façons, nous avons déjà cité Kubernetes, IBM en fait la pierre angulaire de son offre BlueMix, nous avons déjà parlé du support de Microsoft, nous pourrions continuer longtemps ainsi.

La fin de la virtualisation ?

Je tue d'entrée le suspense.

L'intérêt grandissant pour Docker ne va pas mettre un terme à la prééminence actuelle des solutions de virtualisation, et pour de nombreuses raisons.

Détaillons.


Déjà, les entreprises ont lourdement investi sur la virtualisation ; il a fallut recruter, former, monter en compétences... Tout ceci prend du temps et coûte cher et ces investissements ne vont pas être jeté aux orties tout de suite. L'accélération du rythme des innovations technologiques et des ruptures majeures est en décalage avec les capacités des organisations à les intégrer (et la question se pose de leur intérêt d'un point de vue purement économique).

Docker est encore trop jeune, insuffisamment éprouvé, et présente des défauts. Les choses progressent vite, il y a des exemples de sites importants en production mais on n'en est pas encore au stade de l'adoption générale. Même si on a largement dépassé le stade du buzz, il ne faut pas confondre vitesse et précipitation.

La société Docker, qui a développé le produit éponyme, doit faire face à l'émergence de nouveaux acteurs sur ce marché, facilitée par le modèle open source des produits, ce qui peut créer de l'incertitude (mais aussi stimuler l'innovation). Je pense en premier lieu à CoreOS (la société). 

La virtualisation et Docker ont des cas d'usages distincts. Du fait de leurs avantages et inconvénients respectifs, ces technologies sont adaptées à des besoins différents. Docker est par exemple adapté en cas de très nombreuses instances d'un même service unique, tandis que la virtualisation est indispensable pour supporter une multitude d'OS hétérogènes, et recommandée dans le cas où un noeud (une VM ou un container) doit exécuter plusieurs services (encore qu'à titre personnel je sois moins affirmatif sur ce point). 

La combinaison des deux technologies est possible et présente des intérêts certains. On a aujourd'hui trois possibilités :
  • un serveur physiques avec un hyperviseur et des VM (virtualisation classique)
  • un serveur physique avec Linux et Docker (ou un concurrent équivalent), approche qualifiée de "bare-metal"
  • et une architecture mixte : un serveur physique avec un hyperviseur hébergeant des VM Linux/Docker.
Chaque architecture a ses avantages et inconvénients mais on peut simplement noter que l'architecture mixte présente ses intérêts propres et permet de s'appuyer sur l'existant tout en bénéficiant des dernières innovations.

VMWare, le plus gros acteur de la virtualisation, a senti le vent et promeut l'architecture mixte, notamment au travers du projet Photon. Il a tout simplement fait une version de Linux/Docker optimisée pour fonctionner avec son hyperviseur ESX. A noter, d'autres acteurs développent (ou participent dans le cadre d'un projet open source) sur des noyaux Linux spécialisés pour une large utilisation de Docker comme par exemple CoreOS (sur lequel s'appuie Kubernetes de Google).

Conclusion

J'espère que cet article vous permettra d'avoir les idées claires sur ce qu'est Docker et pourquoi tous les geeks ont le zizi tout dur dès qu'on aborde le sujet ;-)

Ce qui me semble le plus important à comprendre est d'une part l'écosystème autour de la solution de conteneurisation proprement dite (dépôts de containers, format standard de container  non lié à un éditeur, outils de gestion de clusters évolués Kubernetes and Co), et le fait que la technologie ne remplacera pas la virtualisation mais sera une possibilité supplémentaire et éventuellement complémentaire. Du pain sur la planche pour les architectes système, et des décisions compliquées pour les directeurs informatique en vue ...

Pour un développeur, au sens large, c'est la vision "infrastructure as a code" et l'appui de la démarche DevOps qui me semble la plus importante.

samedi 2 avril 2016

Le javascript dans tous ses états

Javascript est incontournable tout simplement car c'est le seul langage utilisable pour exécuter des applications directement dans un navigateur. Et le navigateur tend à devenir de plus en plus omniprésent et ubiquitaire.

On m'aurait dit ça il y a 15 ans je ne l'aurais pas cru  : "quoi ce machin immonde pour bidouilleurs du dimanche ?" me serais je écrié. Comme quoi, parfois on peut bien se planter (et en outre sur le jugement de valeur du langage faussé par une incompréhension initiale, mais bon faut savoir reconnaître ses erreurs). 

Il faut dire que l'histoire a quand même failli me donner raison ; il y a quelques années on pariait beaucoup sur le succès de diverses solutions techniques basées sur des plugins de navigateurs exécutant des machines virtuelles et supportant des langages plus évolués : Flex d'Adobe, SilverLight de Microsoft ont connu le succès avant de disparaître brutalement. Google a même proposé un nouveau langage pour supplanter javascript (DART), mais sans succès.

Désormais les dés en sont jetés, c'est ainsi : les grands acteurs de l'informatique ont tous fait le choix de javascript et investi des sommes colossales en R&D pour en améliorer l'usage, avec succès. 

Mais le javascript d'aujourd'hui est bien différent de celui d'hier. Le langage, si il conserve toujours un grand nombre de ses défauts de jeunesse, a évolué dans le bon sens. La normalisation du cœur du langage et de ses principales APIS, bien qu'incomplète, a permis d'améliorer la compatibilité cross-navigateur. Et diverses techniques se sont développées pour permettre de vivre du mieux possible avec et contourner ses défauts et limitations. De nombreuses initiatives visant à continuer les améliorations sont toujours en cours et avancent rapidement.

Je dresse un petit tour d'horizon rapide du sujet. Les premiers paragraphes sont là plus pour rappel car ils abordent des sujets déjà un peu ancien et assez largement connus, les deux derniers s'intéressent à des aspects bien plus novateurs.

Pour le lecteur qui ne serait pas familiarisé avec les bases techniques indispensables, la série d'article suivante donne les pré-requis, en particulier le dernier épisode qui explique le rôle du javascript et son fonctionnement au sein du navigateur :
Cette autre série d'article introduit également les bases nécessaires pour comprendre ce que sont un programme, un compilateur, une machine virtuelle, au cas où


Petit rappel rapide sur les architecture web

Pour bien comprendre pourquoi le js est aussi important aujourd'hui, il faut bien avoir en tête les architectures actuelles. Je résume grossièrement et rapidement le sujet.

Initialement, les applications web étaient construites en mode page à page : un navigateur émettait une requête http, le serveur web la passait au serveur d'application (ou moteur de script dans le cas de php par exemple) qui fabriquait une page html et la renvoyait. Toute la logique était gérée côté serveur (back-end), toute action de l'utilisateur côté client impliquait ce cycle complet. Avec a la clé, une ergonomie insatisfaisante et une charge serveur importante.

Avec la standardisation du XHR (XmlHttpRequest), une fonctionnalité du langage javascript permettant de faire des requêtes http asynchrones, la programmation AJAX s'est popularisée et a permis l'apparition du web 2.0. Il devenait possible de rafraîchir partiellement une page sans devoir la recharger : le programme js fait une requête au serveur http, qui renvoie des données et non une page html, données qui sont utilisées par le programme js pour manipuler le DOM de la page et modifier les données à l'écran (technique autrefois appelée DHTML, D pour Dynamic).

Voici l'étape suivante qui est l'état de l'art actuel, et une tendance lourde pour les nouveaux développements : on télécharge une application client javascript dans le navigateur (elle peut être développée dans un autre langage, cf les explications plus loin, mais le code qui s'exécute est du js), cette application gère toute la logique de navigation (ce qui n'est donc plus fait côté serveur) et d'affichage (plus du tout, ou beaucoup moins, selon le type d'application et les choix d'architecture, de génération de code html côté serveur), et elle fait appel aux services implémentant les règles métier (par exemple un calcul de devis) et l'accès aux bases de données, qui eux s'exécutent toujours côté serveur. 

Tout ceci nous ramène donc à l'architecture client serveur d'il y a 20 ans, hormis le fait qu'on s'appuie sur des standards ouverts alors que les architectures client/serveur s'appuyaient quasiment toutes sur des standards propriétaires et fermés : on a donc une application client (en js), une application serveur (java, ruby, groovy, C#, php, js, perl, python etc.), des appels client/serveur de procédures distantes (RPC Remote Procedure Call) comme il y a 20 ans, mais avec un protocole de transport standard (HTTP), un format de donnée JSON standard (un standard javascript, en lieu et place de divers formats binaires spécifiques à chaque éditeur). Ajoutons que les serveurs ont désormais la possibilité d'envoyer directement des données aux clients sans que ceux ci aient à le solliciter (websockets ou version 2 de la norme HTTP), et on est de retour à l'époque pré-internet.

Des conventions établies sur la syntaxe d'appel aux services donnent son nom à cette architecture : REST. REST est un style architectural qui définit notamment la sémantique des différents verbes du protocole HTTP (tel verbe pour une création, tel autre pour une lecture, tel autre pour une suppression, tel autre pour une mise à jour) et la forme que doivent prendre les url (chaque appel RPC étant une requête http, il est bien entendu défini par une url).

L'émergence de ce modèle a pour origine et pour conséquence les améliorations des technologie js.

Librairies 

Le premier pas a été l'apparition de librairies permettant d'améliorer le niveau d'abstraction du langage, la productivité des développeurs, et la compatibilité cross-navigateurs. Je pense bien sur à JQuery en premier lieu.
Un petit mot sur le sujet de la compatibilité cross-navigateur.

Le langage javascript a été inventé par un chercheur de la société qui éditait le navigateur Netscape Navigator, un des tout premiers navigateurs ayant existé. C'était donc à l'origine une initiative privée, hors de tout contexte normatif. L'idée de base étant bonne, elle a été reprise par les autres éditeurs de navigateurs qui ont fait leur propre version du langage, compatible pour une grande part mais avec chacun diverses extensions (des capacités supplémentaires du langage) qui leur étaient propres, et des syntaxes parfois un peu différentes.

Il faut bien comprendre qu'à l'époque il y avait une guerre féroce entre les acteurs du marché pour essayer d'imposer leur navigateur qui devenait, du fait de l'importance prise en entreprise et chez les particuliers par ce logiciel, un enjeu majeur. En sortant le premier une extension adoptée par les développeurs, on captait le marché.

Du coup, un site web développé en faisant usage d'une extension propre à un navigateur ne pouvait fonctionner que sur un navigateur, celui de l'éditeur ayant inventé ladite extension, et pas sur les autres navigateurs (du moins le temps qu'il s'alignent). Autant dire que ça allait à l'encontre des principes même ayant conduit à l'adoption du web. La conséquence est que les développeurs devaient faire plusieurs versions d'un même site, en détectant le navigateur sur lequel le code s'exécutait, ce qui posait de nombreux problèmes, à commencer par une majoration significative des coûts de développement. Notons que ce problème se posait également pour le langage CSS (et HTML dans une moindre mesure).

Un mot rapide encore sur la technique utilisée pour détecter le navigateur. Elle peut se faire côté serveur car une requête HTTP émise par un navigateur embarque certaines informations dont une donnée appelée USER-AGENT qui permet de savoir à quel navigateur on a affaire. Il suffit alors de renvoyer un code js spécifique au navigateur utilisé. Mais la technique probablement la plus utilisée est bien plus ennuyeuse ; il s'agit d'une série d'astuces de programmation empiriques qui consistent à exécuter un bout de code et à voir ce que ça donne et deviner le navigateur en fonction du résultat constaté. On appelle ça un hack et c'est une technique assez risquée : comme elle résulte de comportement pas forcément spécifié, sa connaissance est empirique et rien ne garantit sa pérennité dans le temps (quand c'est basé sur des comportements non spécifiés). L'usage fréquent de ces techniques faisait de la programmation web un art plus qu'une science ...

Il y a eu une prise de conscience des éditeurs et le langage js a été normalisé et est devenu ECMAScript (javascript étant une implémentation de la norme, d'autres implémentations existant par ailleurs). Les API telles que DOM permettant de manipuler le contenu des pages ont également été standardisées. Mais le mal était fait et il a fallu beaucoup de temps pour que les navigateurs implémentent correctement les normes officielles ; voilà pourquoi il est préférable, et de plus en plus souvent obligatoire, d'avoir un navigateur récent sur son poste de travail (pour Internet Explorer au minimum une version 10, et de préférence la 11 ou encore Edge son successeur sous Windows 10, une version à jour de Chrome ou Firefox).

Bref, l'utilisation de JQuery a permis de masquer toute cette complexité (les hacks sont implémentés dans la librairie et le développeur n'a pas a en avoir conscience) et d'améliorer la productivité et la qualité des développements (par exemple pour manipuler le DOM d'une page).

Frameworks

En introduction à cette section, le lecteur peu familiarisé avec la notion de framework et de design pattern peut lire cet article : Mythes et légendes de la POO 1/2. La lecture du second volet n'est pas indispensable. L'article traite des concepts qui nous intéressent dans le cadre plus spécifique de la programmation selon le paradigme objet, mais peu importe.


Après JQuery, de véritables frameworks sont apparus ces dernières années, rendant disponible côté client un grand nombre des techniques d'ingénierie logicielle éprouvées côté serveur (injection de dépendance, structuration du code par le pattern MVC, tests unitaires ...)

A la clé, amélioration de la productivité, testabilité, maintenabilité accrue.

Ce domaine est en pleine effervescence et le développeur qui veut gagner plein de pepettes aujourd'hui à tout intérêt à se spécialiser là-dessus. Je pense bien sur à Angular et consorts.


De nouvelles normes sont en maturation au sein des éditeurs et du w3c. Quand elles seront enfin disponibles, elle représenteront un progrès considérable. Je pense en particulier à "l'arlésienne" WebComponents qui semble avoir bien du mal à sortir. Cette spécification permettra de modulariser les développements sous formes de composants d'IHM réutilisables ce qui sera un grand pas en avant. Elle est très attendue mais sa mise au point semble poser un grand nombre de difficultés, comme d'habitude liées au poids de l'existant, à savoir en l’occurrence les spécifications initiales de HTML / CSS et bien sur js (modularisation non prévue bien que possible via certaines conventions et design pattern).

Le projet CommonJS devrait également apporter des avancées significatives, d'autant que selon certaines rumeurs le w3c s'intéresse de près à cette initiative. Ce projet apporte par exemple un système de module utilisé par exemple par Node.js (plateforme d'exécution javascript totalement décorrélée du navigateur permettant le développement d'applications serveur ou standalone) qui a inspiré la spécification de la version 6 du langage Ecmascript.

Tout un tas d'autres APIS sont standardisée, ou en voie de l'être, dans de nombreux domaines (persistence des données, accès au matériel, ...). Le plus simple pour les personnes intéressées est de jeter un oeil ici.

Interpréteurs, JIT, Environnement d'exécution

Google a lancé la course avec V8 voici 6 ou 7 ans. Cet interpréteur javascript de nouvelle génération a explosé tous les records de performance, notamment grâce à l'usage de la compilation à la volée (JIT). Rappelons que les techniques JIT permettent de compiler en code binaire natif des portions de code javascript (sous réserve qu'il soit écrit de manière qui le permette).

Les autres acteurs ont suivi, Microsoft longtemps à la traîne a enfin réagi avec Edge (le navigateur par défaut de Windows 10) et une nouvelle version de Chakra (son moteur js). Tellement performant qu'il y a désormais une version de Node.js animée par ce moteur (V8 de façon classique). SpiderMonkey de Mozilla n'est pas en reste non plus.

On doit également citer Node.js un environnement d'exécution Javascript implémentant le pattern Reactor grâce à une libraire C++ d'I/O asynchrone ultra-performante.

Ce produit a permis à Javascript de quitter le seul univers du navigateur pour devenir une solution plus que crédible pour le développement back-end (développement serveur par opposition au développement client dît front-end) ou d'applications standalone.

Transpileurs

Malgré les améliorations apportées au langage, le javascript reste un langage qui n'est pas très adapté pour des programmes de taille importante. Il n'apporte pas les mécanismes requis de façon simple et native. La version 6 de la norme EcmaScript (sortie mi 2015) apporte des améliorations significatives mais elle ne sera pas supportée tout de suite. Il faudra en outre du temps pour que les développeurs se l'approprient. Notons toutefois que cette version apporte enfin un mécanisme de modules standardisé.

La transpilation (ou compilation source à source) est un procédé qui consiste à lire un code source et à le transformer pour produire en sortie un seconde code source exprimé dans un autre langage (ou dans une autre version du langage source). Le transpiler est l'outil qui réalise l'opération. La technique est utilisée pour améliorer, simplifier, enrichir divers langages : CSS est ainsi amélioré par SASS (par exemple), et Javascript par toute une famille de langages.

Il est ainsi possible de développer dans un langage plus évolué et de transpiler le code en javascript qui s'exécutera dans la navigateur.  Le langage de départ peut être un langage très proche de javascript pour faciliter la transition aux développeurs déjà formés, ou être totalement différent.
Microsoft qui investit beaucoup sur la technologie javascript fournit TypeScript qui permet de faire du développement selon le paradigme objet (javascript le permet nativement mais c'est extrêmement complexe). Nul doute que ce soit une solution appelée à prendre de l'importance dans le futur. Le support apporté par Microsoft au sujet n'est pas neutre et témoigne de l'importance du sujet.

Il existe d'autres solutions plus anciennes comme CoffeeScript par exemple.

Il est également possible d'écrire du code en EcmaScript 6 et de le compiler (transpiler pour être précis, cet abus de langage est fréquent) en EcmaScript 5. L'intérêt est que quand les navigateurs supporteront la dernière version du langage, on pourra simplement supprimer cette phase de transpilation et continuer à utiliser le même code (ainsi on peut développer dès aujourd'hui en profitant des apports au langage de la dernière version et exécuter dans les navigateurs actuels qui ne la supportent pas encore, ou incomplètement).

Outillage des développeurs

On ne peut décemment pas parler du js d'aujourd'hui sans dire deux mots sur l'outillage actuel.

Initialement, on avait un éditeur de texte dans lequel on tapait son js, puis on l'exécutait dans un navigateur en le faisant charger par une page html. Ca marchait ou pas, et quand ça marchait pas on avait juste un message d'erreur généralement incompréhensible et inexploitable. La mise au point était un vrai cauchemar d'autant que les mauvaises pratiques autorisées, voire encouragées, par le langage (portée des variables globale par défaut) étaient vecteurs de production de bugs. Sans parler du manque de normalisation de l'API DOM utilisée pour interagir avec le contenu de la page, de la difficulté à modulariser le code, et diverses autres joyeusetés.

Ce temps est révolu. Tous les navigateurs modernes embarquent des débugueurs puissants. Ce sont des outils qui permettent de visualiser le code au moment de son exécution, le contenu des variables, de stopper une programme et de le dérouler pas à pas etc. Bien plus facile de faire la mise au point.

L'introduction du mode strict dans le langage a permis de supprimer certaines mauvaise pratiques, et des analyseurs de code (Lint, JsLint) sont apparus qui permettent d'alerter le développeur sur une suspicion ou erreur avérée de programmation.

Les IDE ont progressé et proposent de la coloration syntaxique et diverses assistances pour vérifier la conformité de son code au fur et à mesure du développement. On limite ainsi les erreurs de programmation. Bien sur la nature dynamique du langage js, et le fait qu'il soit interprété ne permettent pas d'avoir le même niveau de contrôle en amont qu'avec un langage compilé, mais ce qu'on perd en rigueur on le gagne en souplesse et en facilité pour les non professionnels. On a aujourd'hui des IDE spécialisés très performants (Webstorm par exemple), ou des bons plugins pour des outils plus généralistes (par exemple pour NetBeans, Eclipse est à la traîne).

Puis progressivement on a vu apparaître, depuis disons 2 ou 3 ans, les mêmes outils que ceux utilisés depuis très longtemps côté serveur pour booster la productivité et la qualité des développements. Nous allons citer rapidement les principaux et donner leur équivalent côté back-end pour les développeurs java (le langage le plus utilisé). Mais en préalable je dois me plaindre... Pourquoi nom de dieu, les développeurs ont ils encore ressenti le besoin de réinventer la roue et redévelopper de zéro de nouveaux outils au lieu de simplement faire évoluer les outils existant côté serveur ? A tous les coup pour des raisons à la con (ego des développeurs, volonté de tout faire en js, concurrence ...) mais bref c'est comme ça.



Alors, commençons par les gestionnaires de package... kesako ? Tout projet un tant soit peu important fait usage de nombreuses librairies externes. L'approche traditionnelle qui consiste à les télécharger manuellement depuis le site web du projet est source de nombreux problèmes qui sont résolus par les gestionnaires de packages. Ces derniers se chargent de faire le boulot automatiquement en s'appuyant sur un repository centralisé sur Internet où toutes les librairies sont proprement rangées et versionnées.

Il existe deux solutions concurrentes : Bower et Npm (issu du projet Node.js).
L'équivalent principal côté back-end Java est Maven.




Continuons par les outils de build automatisé. Ces outils automatisent le processus de build et évitent une gestion manuelle fastidieuse et hasardeuse (source d'erreurs). Le build est l'ensemble des phases nécessaires pour passer d'un code source à une application prête à être délivrée.

Ici aussi, on a deux solutions qui se tirent la bourre : Grunt et Gulp.
L'équivalent principal côté back-end Java est encore Maven (ou Ant si on veut).




Passons ensuite sur les outils de test automatisés. On est à la frontière entre le framework (composant logiciel) qui facilite le développement des programmes de test (des programmes qui testent des programmes, oui je sais les informaticiens sont des gens bizarres), et l'outillage qui permet d'exécuter automatiquement ces tests et vérifier qu'il n'y a pas d'erreur (dans le processus de build).

Deux solutions ont le vent en poupe à ma connaissance : Karma et Jasmine.
L'équivalent principal côté back-end Java est JUnit ou TestNG.



Ensuite, un outil de scaffolding. Hein scaquoi ? Le scaffolder est un outil qui génère automatiquement le squelette et une partie du code d'une application. C'est un outil qui permet de gagner du temps car il automatise certains travaux qu'on ferait sinon manuellement sur tout nouveau projet. Il apporte un gain de qualité car il fait les choses selon les meilleures pratiques, ce que ne ferait pas nécessairement le développeur pas toujours au fait des choses. Et il standardise la façon de faire ce qui est bon aussi.

Je connais une solution : Yeoman
L'équivalent principal côté back-end Java ? Il en existe pas mal, disons que les archetypes Maven sont le mécanisme le plus répandu.

Voilà un tour d'horizon rapide et sans doute incomplet. Mon idée est surtout de montrer qu'il y a une forte évolution de l'outillage, qui accompagne logiquement l'adoption massive de l'architecture REST, qui renforce l'importance du js (et donc la nécessité de gains de qualité et de productivité).

Asm.js

Accrochez vous à vos slips, ça devient un poil plus compliqué.

Pour ceux qui n'auraient pas les idées très claires sur ce qu'est une architecture processeur, du code binaire, la compilation, et les machines virtuelles, je préconise de lire ces deux articles :
Mozilla a développé un outillage qui permet de compiler du code C ou C++ en javascript tellement optimisé qu'il s'exécute à peu près aussi vite qu'un code C# ou Java (c'est donc un progrès considérable). Des démos de jeux en 3D portés selon cette technique et s'exécutant sous Mozilla Firefox sont totalement bluffantes.

Cet article en anglais explique parfaitement la technique.  J'en résume les idées clés.

Le code source (C ou C++) est dans un premier temps compilé, via un compilateur spécial (clang) dans un format de bytecode (code binaire virtuel) générique (non spécifique à une architecture particulière de VM). Tout cet outillage est fourni par le projet LLVM. Il est prévu le support d'autres langages.

Ce code binaire virtuel est ensuite transformé en un code javascript bien particulier via un outil développé par la fondation Mozilla (emscripten). Ce code est du code javascript mais il est généré d'une façon très particulière, respectant la spécification asm.js ; le résultat est que ce code javascript est directement traductible en binaire par un compilateur JIT spécialement optimisé ; Mozilla a optimisé le sien, et comme cette optimisation n'est pas très complexe et apporte des gains de performances extraordinaires, les autres acteurs ont suivis.



A priori tous les principaux navigateurs sont aujourd'hui optimisés pour asm.js, à l'exception d'Opera.

Un navigateur dont le compilateur javascript n'aurait pas été optimisé spécifiquement pourra également faire fonctionner le code, puisque c'est du javascript, mais il ne bénéficiera pas des gains de performance.

WebAssembly (wasm de son petit nom)

Tout nouveau, tout chaud.

WebAssembly est un format binaire censé être supporté par tous les navigateurs et destiné à être standardisé par le w3c (organisme qui normalise entre autre html, css, javascript) afin d'être totalement portable entre navigateurs (plus précisément entre interpréteurs js)

On est dans la prolongation du principe asm.js mais alors que le code asm.js est exprimé en javascript (donc en texte), on a ici un format binaire. 


WebAssembly est un format binaire mais ce n'est pas du tout du bytecode destiné à être exécuté par une machine virtuelle. Les informations exprimées par les 0 et les 1 ne sont pas des instructions destinées à une architecture de processeur (qu'elle soit virtuelle comme dans le cas d'une JVM Java par exemple, ou réelle en cas de code natif pour processeur Intel x386 par exemple) mais des structures de données.

Pour comprendre le principe, il faut connaître le fonctionnement des compilateurs. En simplifiant, une première étape consiste à analyser le code source et à écrire une représentation mémoire abstraite de son comportement. Ce qu'on appelle un AST Abtract Syntax Tree. Dans une seconde étape, cet AST est lu pour produire le code binaire correspondant à la plateforme cible. L'existence de l'AST découple les deux phases ce qui est très pratique car le code source peut ainsi être exprimé dans divers langages sources (il faut écrire un analyseur syntaxique pour chaque langage, et ils construisent tous un AST avec les mêmes conventions), et que ce code source peut être utilisé pour produire du code binaire pour différentes architectures processeurs physiques ou virtuelles (il suffit d'écrire un générateur de code binaire pour chaque plateforme). Ce principe est très souple et explique par exemple comment Microsoft permet d'exécuter divers langages sur une même machine virtuelle (CLR Common Language Runtime), ou comment un même code source peut servir à produire des exécutables pour des architectures processeurs différentes.

Dans le cas qui nous intéresse, la partie finale, qui consomme un AST pour produire du code binaire, est toujours la même : c'est le compilateur JIT (ou AOT, peu importe la nuance ici) embarqué par l'environnement d'exécution javascript, c'est à dire le navigateur (ou Node.js).

Dans le mesure où la structure de l'AST est normalisée, tout AST est portable entre environnements. Et c'est précisément le chantier en cours chez tous les éditeurs de navigateur : se mettre d'accord sur une structure normalisée et implémenter dans leurs moteurs respectifs (chakra, V8, spiderMonkey) la capacité de le lire pour générer directement du code binaire sur cette base (qui bien sur s'exécute bien plus vite, disons 10X plus vite, que le code interprété).

Il nous manque encore la partie avant, c'est à dire la capacité de générer cet AST depuis différents langages sources. De nouveaux langages vont peut être apparaître à cette occasion, le langage javascript va peut être évoluer pour se prêter plus facilement à cet usage, l'avenir nous le dira, le chantier est en cours. Mais d'ores et déjà, une partie du travail effectué pour  le support de asm.js est exploitable et adaptable. Les outils qui compilent du code source C ou C++ en bytecode LLVM existent déjà. Modifier emscripten qui sait déjà lire ce format pour générer un binaire wasm au lieu d'un texte asm.js n'est probablement pas très compliqué...

wasm est donc une possibilité en cours de développement, complémentaire et distincte de asm.js.

Premier avantage, elle évite la phase de parsing du code asm.js qui est coûteuse en temps d'exécution (en particulier sur les devices peu performants comme les smartphones), et complique la maintenance des runtime javascript (qui doivent implémenter deux parsers, un pour le code "régulier" et un pour le code "asm.js").

Second avantage, un format binaire est plus compact qu'un format texte et le temps de transport du code par le réseau sera également  fortement réduit.

Donc en conclusion, au lieu de faire voyager du bytecode par le réseau ce qui obligerait à implémenter une machine virtuelle sur chaque environnement (ce qui existe depuis 20 ans avec les applets java), on a choisi de faire voyager une représentation binaire d'une phase intermédiaire de la compilation qui est achevée sur l'environnement client. Le choix a été fait pas des très grands esprits de l'informatique, on peut donc supposer qu'ils ont leurs raisons, même si il n'est pas impossible que des motivations d'ordre tactico-économiques aient pesées dans la balance. 

Je vous invite à lire cette interview de Brendan Eich (l'ignoble individu qui a créé Javascript, et le pire c'est qu'il en est fier).

Pour finir, on peut quand même penser, bien que Brendan Eich s'en défende, que ce choix signifiera à terme la mort du javascript ou du moins la fin de sa prévalence. En effet, n'importe quel langage accompagné d'un analyseur syntaxique capable de produire un AST au format wasm pourra être utilisé. Et ce sera un très grand progrès pour les développeurs de la prochaine décennie.

Conclusion

Le poids de l'existant... en informatique ça a toujours été quelque chose de très lourd.

Javascript est un langage plein d'inconvénients et de défauts mais on doit faire avec. Ces inconvénients étant en bonne partie liés au fait que l'usage qu'on en fait aujourd'hui est très différent de ce pour quoi il était apparu à l'origine (un langage de scripting accessible aux non professionnels pour dynamiser des pages web et écrire des programmes courts).

Du coup, on (ré)invente des tas de technologies complexes, et envisageables uniquement car les processeurs actuels en ont sous le pied, pour faire de façon compliquée ce qu'on aurait pu faire mille fois plus simplement en reprenant les choses à la base.

Enfin quoi qu'il en soit, les choses vont dans le bon sens et n'ont manifestement pas fini de progresser.

Ha oui, dernier point, on constate que le sujet est complexe, riche, et en perpétuelle évolution. Pour cette raison je ne peux que conseiller à tout société qui investirait sur le développement d'applications en javascript, de se faire accompagner par des vrais spécialistes du sujet. Comme côté back-end, la fonction d'architecte prend tout son sens, ce n'est pas qu'une invention des SSII pour facturer plus chers des prestations... Même si bien entendu il n'est pas inutile de vérifier que le profil qu'on vous place comme architecte a bien la large culture technique et le côté pragmatique indispensables pour ce poste clé dans une équipe de production (fuyez les geeks).