S’il est simple de reconnaître un produit ou un service de bonne qualité, il est plus difficile d’en donner une définition absolue. C’est d’ailleurs ce que l’architecte et anthropologue Christopher Alexander avait baptisé Quality Without a Name, dans son ouvrage The Timeless Way of Building sur une nouvelle théorie architecturale fondée sur les modèles des langues (et qui par la suite est devenu une source d’inspiration pour le monde logiciel…). En premier lieu, le concept de qualité sous-tend un certain nombre d’idées liées à l’optimisation d’un produit ou d’un service et les moyens que l’on se donne pour faire en sorte qu’il apporte le maximum de valeur à nos clients.
Et en définitive, c’est un point de vue qui reste subjectif, celui du consommateur, qui va permettre de juger ou non de cette qualité. Naturellement, il s’agit de s’assurer que le produit ou le service est fiable et que son comportement est bien celui souhaité par l’utilisateur. D’un point de vue organisationnel, la qualité c’est surtout la capacité à respecter les délais et à s’aligner sur un time to market conforme à la stratégie business de l’entreprise. Enfin, la qualité est également liée à la façon dont le produit ou le service sera produit. La qualité sera alors considérée à l’aune de critères qui permettent de mesurer l’efficacité de la chaîne de production logicielle. Enfin, ne perdons pas de vue la sécurité, une composante majeure de la qualité, qui elle aussi est à reconsidérer avec DevOps.
Optimisation et fiabilité du service, alignement sur le time to market, efficacité de la chaîne de production logicielle, et sécurité autant d’éléments qui font de la qualité un impératif de la transformation DevOps.
La qualité concerne tous les acteurs de la chaîne de production logicielle. Aux développeurs et équipes de gestion opérationnelle viennent s’ajouter les ingénieurs qualité et les testeurs. Leurs compétences restent d’actualité mais l’évolution vers un monde de services a quelque peu modifié la nature de leurs activités, leur périmètre de responsabilité et l’organisation du système mis en place pour satisfaire aux exigences de qualité.
DevOps : la culture de la qualité…
Adopter une démarche DevOps, c’est souhaiter mettre en place une culture centrée sur l’amélioration continue de la qualité, de la performance, et de la productivité. Cela suppose l’adhésion et l’engagement de l’ensemble des acteurs avec la nécessité, là encore, d’un apprentissage en continu, non seulement pour faire monter les équipes en compétence sur les nouveautés technologiques liées à une évolution de leur métier (comme le Data Driven Engineering), mais aussi pour interpréter et comprendre le flux ininterrompu de données remontées par les utilisateurs du système. Avec DevOps, l’utilisateur est plus que jamais au centre des systèmes et processus liés à la qualité…
Comme nous l’avons vu dans les précédents chapitres, le monde du logiciel s’est progressivement transformé en un monde de services, dans lequel chacun aspire à bénéficier régulièrement de mises à jour, qu’il s’agisse d’évolutions fonctionnelles ou de corrections de bugs. Et ce nouveau modèle s’est également imposé sur les produits logiciels et sur de nombreux types de périphériques qui tirent parti des possibilités qu’offre la large diffusion des protocoles de communication pour pouvoir, eux aussi, être régulièrement mis à jour, jusqu’à la prochaine rupture technologique. L’explosion du marché de la technologie grand public révèle l’appétit des consommateurs pour des solutions plus innovantes mises à disposition avec un rythme toujours plus soutenu. En contrepartie, ils sont sans doute plus prêts à accepter un dysfonctionnement provisoire, s’il est corrigé rapidement et s’il offre l’accès à une nouvelle fonction.
L’évolution du marché du logiciel se traduit donc par l’émergence de nouveaux modes de production logicielle avec une fréquence accrue de livraison ce qui n’est pas sans impact sur la qualité. Il faut aligner les objectifs et les métiers liés à la qualité avec ces nouveaux impératifs du marché. Cela n’est envisageable qu’à condition de maintenir un niveau de qualité acceptable. Cela suppose une évolution significative de ces métiers, évolution dans laquelle une démarche DevOps peut très clairement jouer un rôle de facilitation et d’accélération.
D’un point de vue organisationnel, en simplifiant et fluidifiant leur communication, DevOps rapproche le monde des testeurs fonctionnels de celui des développeurs responsables de la correction de bugs, ou de celui des équipes de gestion opérationnelle en charge de la validation de la disponibilité des infrastructures et du bon fonctionnement des systèmes. Par exemple, les campagnes de tests ont tout intérêt à être définies dans un référentiel commun accessible à l’ensemble des acteurs du cycle de vie logiciel : développeurs, testeurs et responsables de la gestion opérationnelle auront accès aux données fonctionnelles, aux éléments permettant de lancer les tests de performance, ainsi qu’aux résultats de chacun de ces types de test.
DevOps impacte également la définition des modalités d’application de ces tests que ce soit dans leur planification dans les différentes phases du cycle de vie logiciel (fréquence, conditions de déclenchement de ces tests), dans la mise en place de tests en production ou dans l’implication des différents acteurs du projet. Quel que soit le système mis en œuvre pour la gestion du plan de tests, il devra s’intégrer avec les mécanismes permettant d’automatiser l’exécution de ces tests sur l’infrastructure cible.
Selon l’ISO la qualité est l’aptitude d’un ensemble de caractéristiques intrinsèques à satisfaire des exigences, une définition qui ne permet pas d’établir une vision très précise du périmètre des activités d’un ingénieur qualité. De nombreuses difficultés peuvent se présenter au cours du développement d’une solution et le risque ne peut jamais être éliminé. Le rôle de l’ingénieur qualité est d’auditer les actifs du projet (documents de design, code, architecture, sécurité), d’évaluer les risques, et de définir les stratégies de pilotage du projet et de tests de la solution. Il doit gérer les risques considérés comme acceptables et faire en sorte d’éviter tout autre type de menace.
Tout cela suppose une gamme de compétences assez étendue. L’ingénieur qualité a pour principale mission d’aider les développeurs et les équipes de gestion opérationnelle à atteindre leurs objectifs en prévenant tout risque qui puissent les empêcher de les atteindre. Dans une chaîne de production DevOps, il doit également s’assurer que chaque outil est utilisé à bon escient et identifier les tâches d’automatisation complémentaires pour exécuter des vérifications de différents ordres (configuration système, applicative…). Son rôle est aussi de se focaliser sur l’ajout de valeur pour le client et sur ses attentes. À ce titre, il doit décider des données d’utilisation qu’il convient de capturer et de la façon de les collecter et de les exploiter. Il devient donc l’un des acteurs principaux de la qualité pilotée par les données (Data Driven Quality), un sujet que nous explorerons un peu plus loin dans ce même chapitre. L’évolution de son rôle implique également l’acquisition de connaissances sur les sciences et les outils liés aux données.
Comme leur nom l’indique, les testeurs ont pour mission d’assurer la qualité du livrable par la mise en œuvre de tests logiciels. Le test logiciel s’appuie sur des cas de test et leurs exécutions. Les résultats des tests fournissent les données permettant de faire une évaluation de la qualité. À l’origine, un testeur logiciel doit être en mesure de définir, documenter, puis automatiser les tests permettant de valider le bon fonctionnement de l’application cible. Mais aujourd’hui, pour se différentier sur le marché, il convient de pouvoir identifier les pistes d’optimisation de la qualité du service ou du produit, et agir plus tôt dans le cycle de vie afin d’augmenter la probabilité de succès et de réduire les risques. Pour ce faire, il faut réduire les incertitudes en capturant différents types de mesures.
Dans le cas du service, il est maintenant possible de contrôler le déploiement et de superviser la disponibilité, les performances, les dysfonctionnements et l’usage. Si le système est bien conçu, un flux constant de données de télémétrie est émis par le produit ou le service. Il devient alors possible d’exploiter ce flux de données pour améliorer la qualité des produits.
Moins de tests à implémenter et une partie de ces tests directement assurée par les développeurs ou les utilisateurs (dans le cas des tests en production) : tout cela n’est pas sans incidence sur le métier des testeurs logiciels, qui ont donc tout intérêt à développer de nouvelles capacités. Le testeur logiciel est maintenant en situation d’obtenir des données sur un problème quasiment au moment où il se produit et le rôle du testeur est de faire en sorte que les développeurs et les équipes de gestion opérationnelle soient plus efficaces pour y remédier alors que la solution est en production. Non, le test n’est pas mort, au contraire de ce qu’affirmait Alberto Savoya pour lancer sa keynote et obtenir un maximum d’attention, lors de l’Annual Google Test Automation Conference 2011. Certes, le rôle du testeur évolue, mais il conserve sa mission de pourfendeur de bugs avec toutefois une réorientation de ses priorités.
Il s’agit de veiller à ce qu’aucun bug critique ne vienne interrompre durablement le bon fonctionnement du système et de s’assurer que l’infrastructure et les processus mis en place permettent de réagir très rapidement pour y répondre, ce qui au final représente sans doute une diminution du nombre de tests à mettre en place. Il faut adapter le code de test pour qu’il alimente les données d’instrumentation du système et qu’il apprenne à analyser les journaux d’évènements qui vont fusionner le résultat des tests et les données capturées.
Le testeur DevOps doit appliquer la même démarche quel que soit l’environnement sur lequel s’exécute l’application. Il doit connaître et comprendre le fonctionnement du système en charge de l’utilisation réelle. Il doit également se concentrer sur les données associées aux comportements des utilisateurs et apprendre à rechercher des modèles dans les données. Il doit être en situation de pouvoir distinguer les zones dans lesquelles l’expérience utilisateur est potentiellement insatisfaisante (dysfonctionnement, latence, navigation complexe…) de celles dans lesquelles le service est rendu dans d’excellentes conditions (sans doute plus difficiles à identifier). Il passe donc d’un monde où la qualité était validée de façon binaire (le test a réussi ou échoué) à un monde probabiliste dans lequel il doit faire usage de calculs statistiques pour comprendre ce que font les utilisateurs et pourquoi ils le font, en établissant des correspondances entre les données capturées et la qualité du produit.
Les tests sont inhérents au développement logiciel. Durant les différentes étapes du cycle de production logicielle, de nombreux types de tests doivent s’exécuter. Tester un logiciel va d’abord consister à lancer les composants logiciels ciblés dans un contexte d’exécution permettant de mesurer les résultats obtenus afin de déterminer si les objectifs de ces composants sont atteints. Avant DevOps, le développeur était principalement concerné par les tests unitaires et les tests d’intégration. Avec DevOps, le développeur est directement responsabilisé sur la qualité du code produit. Il ne se limite plus à de simples tests unitaires. DevOps diversifie les types de tests, en impliquant le développeur sur des tests ayant une portée plus globale pour l’acceptation du code. Dans ce deuxième cas, il peut s’agir non seulement de valider le comportement fonctionnel de l’application, mais aussi ses temps de réponse. Le développeur DevOps doit donc implémenter et instrumenter ces tests en prenant en compte ces contraintes. Comme nous l’avons vu, il est déjà en situation de pouvoir vérifier le bon fonctionnement de son code sur des environnements semblables à la plate-forme de production. Il dispose en outre de beaucoup plus d’informations sur la façon dont le code a fonctionné (ou non) en production.
Compte tenu de son niveau d’interaction plus fort avec le métier, le développeur peut d’ailleurs être amené à intégrer les exigences fonctionnelles dans le développement même des composants logiciels concernés (Test Driven Developement). Le développeur doit rester responsable de sa méthode de conception et s’assurer du fait que cette démarche se traduit globalement par un réel gain de productivité. Le développeur DevOps qui livre un composant logiciel, doit prendre en considération toutes les contraintes techniques auxquelles ce composant est susceptible d’être soumis : consommation de mémoire, de bande passante, performance, sécurité, instanciations multiples sur la même machine, sur de multiples machines… Il doit donc être capable d’implémenter les tests permettant de valider le respect de ces contraintes. Il participe notamment au développement de tests de charge permettant de simuler de très nombreux utilisateurs afin de vérifier les performances de l’application sous différents niveaux de stress. Dans certains contextes, la validation effective de la charge ne peut se faire qu’en production. C’est d’ailleurs au cours des périodes de pic de charge qu’il convient de mettre à disposition (en mode contrôlé et non généralisé) de nouvelles fonctions, afin d’obtenir le maximum d’information sur leur usage.
Des environnements de déploiement dédiés sont souvent nécessaires pour l’intégration fonctionnelle et la mise en œuvre de tests de performances pertinents. Le cloud offre une réponse particulièrement adaptée à ce type d’usage, avec sa capacité à cloner et déployer des configurations fournies à la demande et facturées à l’usage. Et là encore la composante Infrastructure as Code de DevOps joue un rôle déterminant par sa capacité à automatiser la mise à disposition de ces environnements de tests. Les équipes de gestion opérationnelle sont alors en mesure de développer et faire évoluer ces scripts d’automatisation, qu’ils ciblent des environnements Linux ou Windows. De plus, ces équipes sont directement impliquées dans les tests et concernées par le suivi de l’application en production. À ce titre elles sont les garantes de la capacité à remédier à un dysfonctionnement dans les plus brefs délais.
Les experts en sécurité ont de solides connaissances en réseau, en système d’exploitation, et dans différents langages en fonction des types d’environnement dont ils doivent assurer la protection. Avec DevOps, ils sont maintenant directement intégrés dans les équipes de développement et de gestion opérationnelle. Leur rôle est de transmettre le savoir et déléguer certaines de leurs responsabilités à l’ensemble des acteurs de la chaîne de production logicielle, afin de faire en sorte que chacun puisse avoir une connaissance des menaces auxquelles sont exposées les ressources et des moyens à mettre en œuvre pour les préserver.
Pour ce faire, les experts en sécurité doivent eux aussi comprendre les processus de développement et de gestion opérationnelle. Leur mission est de s’assurer que ces derniers puissent être automatisés en incluant un paramètre supplémentaire : la sécurité. Le système devient ainsi plus réactif à d’éventuelles attaques, car le déploiement de plateformes intègre des mécanismes de protection sur des cycles itératifs, plutôt qu’au terme d’une longue implémentation.
D’un point de vue culturel, cela suppose un engagement de la part de chacun, une active communication entre les différents acteurs, une capacité à s’adapter au changement, et la mise en avant de préceptes déjà évoqués tel que l’expérimentation, les architectures failsafe ou le principe de simplicité…
La confiance que suppose la démarche DevOps n’exclut pas le contrôle. Pour garantir un certain niveau de qualité, il faut mettre en place outils et mesures permettant d’assurer un suivi constant de la solution sur de multiples critères. Il s’agit donc de définir les métriques qui vont permettre d’identifier les pistes d’amélioration dans l’évolution du produit, dans sa fiabilité, dans la disponibilité du service qui l’expose et dans la chaîne de production logicielle. C’est également sur la base de ces métriques que pourront se décider les grandes orientations à donner d’un point de vue fonctionnel et organisationnel.
La production d’une solution logicielle impose parfois des choix qui ne plaisent pas à tous les acteurs du système. Disposer de paramètres quantifiables permet de réaliser ces choix de façon plus objective et de les faire plus facilement accepter. En outre, quantifier la qualité et l’avancement de la réalisation d’une application permet de faciliter l’établissement d’une relation de confiance entre les acteurs de la chaîne de production, prérequis indispensable à la mise en œuvre d’une démarche DevOps.
Il n’est pas toujours aisé de choisir les bonnes métriques. Une approche efficace peut consister à appliquer une démarche top-down de type GQM (Goal/Question/Metric) en six étapes. En premier lieu, il s’agit de se fixer un certain nombre d’objectifs prioritaires (du point de vue business, du point de vue du client), puis d’énoncer les questions qui permettront de savoir si cet objectif est atteint en termes quantifiables, enfin de définir un certain nombre de métriques qui apporteront une réponse à ces questions.
Par exemple, si l’un des objectifs est d’améliorer la disponibilité d’un service web, l’une des questions sera : « quels sont les indicateurs qui permettent de mesurer la disponibilité ? » Les métriques à considérer pourraient être le Average Response Time, le Http Server Errors, le Http Success, le CPU Time, le Memory Working Set. À cela s’ajoute la définition des mécanismes pour la collecte de données, leur capture et leur analyse. Ce type d’approches présente en outre l’avantage d’être facile à partager avec le management et d’éviter de s’intéresser à des métriques qui au final s’avéreraient inutiles.
Suivant l’objectif ou la perspective considérée les mesures sont de différents types. D’un point de vue organisationnel, c’est le time to market qui prévaut. Il correspond à différentes métriques telles que le lead time ou le cycle time. Les métriques liées à la chaîne de production logicielle permettent d’évaluer sa capacité à s’adapter : taux
d’innovation, bug, coût de production. Les métriques liées à la qualité de la solution proprement dite permettent de mesurer la disponibilité du service (temps de fonctionnement…), sa performance (temps de chargement page, latence…) et son utilisation (comportement et fidélité de l’utilisateur…). Ces informations sont obtenues par l’analyse des données issues de la télémétrie de l’application complétée par celle des logs du système.
Les métriques doivent être partagées et régulièrement revues. Il est pertinent de superviser leur évolution et leur adéquation par rapport à des objectifs qui eux aussi peuvent varier dans le temps. Leur utilisation en tant qu’outil d’évaluation de la performance des acteurs de la chaîne de production logicielle n’est pas à encourager, surtout dans une optique DevOps. Il est préférable d’éviter toute tentation d’altération de ces métriques. Dès lors qu’un individu sait qu’il est mesuré il modifie son comportement pour optimiser les critères d’évaluation plutôt que la solution elle-même (Hawthorne Effect). Enfin, la collection de ces métriques doit être totalement automatisée, transparente et partagée entre les différents acteurs du système d’information, afin que chacun puisse prendre connaissance de ces éléments et agir en conséquence.
L’organisation doit disposer de différentes métriques pour définir sa stratégie.
Le lead time est le délai de la déclaration d’une tâche d’implémentation dans le backlog jusqu’à sa mise en production. Il permet de savoir combien de temps est nécessaire avant de pouvoir offrir un nouveau service. Un délai de livraison plus court permet d’obtenir des résultats plus rapidement et augmente la valeur du service ou du produit. Ces mesures peuvent également exposer des inefficacités (temps d’inactivité) dans le process, ce qui d’un point de vue organisationnel est à proscrire.
Work-In-Progress (WIP) définit le nombre de travaux démarrés mais non achevés. Idéalement, cet indicateur devrait être relativement constant, avec un équilibre entre les nouveaux traitements de demandes et ceux qui s’achèvent. Cela permet d’offrir plus de prédictibilité sur la durée. À l’inverse, si cet indicateur augmente l’organisation est en droit de s’inquiéter, car cela signifie plus de changements de contexte pour les différents acteurs du système d’information et potentiellement plus de dépendances entre les éléments constitutifs de la solution.
À cela s’ajoute la fréquence de livraison, le délai de stabilisation d’une release, le cycle time : la durée nécessaire pour implémenter une fonction ou compléter une tâche (le temps est mesuré entre le début de la réalisation de la tâche et son achèvement).
Il existe de multiples métriques liées à l’évaluation d’une chaîne de production logicielle.
Des métriques fonctions de la méthode
Suivant la démarche ou la méthode appliquée, le nombre de métriques peut être très significatif. Par exemple, CMMI appliqué au développement est très consommateur de métriques. L’approche DevOps sera plutôt alignée sur celle de l’agile. L’objectif n’est pas de disposer des preuves de la mise en application de l’ensemble des processus requis par l’ingénierie, mais de se doter des moyens permettant d’évaluer le niveau de qualité d’un sprint et des axes d’optimisation pour les suivants.
Mesure de la vélocité de développement
Il s’agit de pouvoir mesurer l’évolution de la vélocité d’un sprint à l’autre sur les phases de développement liées à la production du service. Les métriques associées au design et au développement correspondent à ce qui peut être mesuré entre la phase de définition du backlog et le déclenchement du build suite à l’archivage du code dans le référentiel de source. Elles correspondent à différents indicateurs comme l’évolution du backlog, le nombre de bugs actifs, le code churn (le nombre de lignes modifiées depuis le dernier build), le code coverage (le pourcentage du code couvert par des tests) ou le statut des tests.
L’un des intérêts de collecter ces métriques est de pouvoir les analyser conjointement. Supposons par exemple que le nombre de bugs augmente en proportion de l’évolution du code churn. Cette information est déjà intéressante en soi, mais peut-être faut-il la corréler avec le code coverage. Peut-être est-ce aussi l’occasion d’instrumenter les éléments de code concernés pour essayer de déterminer les conditions qui les prédisposent à une défaillance…
Mesure de la vélocité sur les phases opérationnelles
Les métriques liées à la gestion opérationnelle sont concentrées sur le déploiement vers les différents environnements. Un indicateur très intéressant est le Mean Time To Deployment (MTTD) qui correspond au temps requis pour déployer une nouvelle version en production du service. Dans un monde où l’on est prêt à plus facilement pardonner une défaillance en production, ce qu’il convient de privilégier, c’est la réduction du temps de détection (Mean Time To Detection) et de remise en service (MTTR : Mean Time To Recovery). Ceci étant dit, ne pas avoir un Mean Time To Failure peut rester un objectif en soi…
Mesure de la vélocité globale du projet
Par essence, le développement est moins prédictible que la gestion opérationnelle qui, par l’automatisation, peut réduire la variabilité de leur processus. De même, les processus de conception et de développement sont souvent plus longs que ceux de mise en production. Au final, dans un monde de services, la qualité première d’un logiciel reste sa capacité d’adaptation aux demandes du marché : taux d’innovation, bug, coût de production sont donc les mesures à considérer en priorité. Elles sont obtenues directement sur la chaîne de production, par analyse des données issues de l’intégration du système de build avec le contrôle de code source et le système de gestion des releases.
Dette technique
La dette technique est due à un non-respect des règles établies en phase de conception (patterns, framework, règles de codage…) ou à des mauvais choix de conception à l’origine. Elle peut être involontaire (manque de maîtrise, absence de communication et d’outils permettant de garantir le respect des règles) ou volontaire (choix pragmatique pour répondre à des soucis de délais de livraison). Dans un cas comme dans l’autre, il faudra, tôt ou tard, s’acquitter de cette dette et la rembourser avec des temps de développement de plus en plus longs et de bugs de plus en plus fréquents. Elle est mesurée en fin de sprint, en comptabilisant les problèmes rencontrés, les bugs, mais aussi les dérives du code par rapport aux règles définies au lancement. D’où l’intérêt de se familiariser avec des méthodes génériques d’évaluation du code comme SQALE (Software Quality Assessment based on Lifecycle Expectations) et avec des outils d’analyse de la qualité du code comme la solution open source SonarQube.
SQALE permet aussi d’aider à prioriser les efforts de remédiation de la dette technique. Toutefois, dans une approche plus agile, il est aussi possible de considérer l’alternative suivante dite de la fuite d’eau : lorsque vous avez une fuite d’eau, vous commencez par la stopper, avant d’essuyer le sol. Appliquée à la dette technique, cela devient :
La qualité du service est mesurée par la collecte de données sur les composantes de ce service et permet d’évaluer sa disponibilité, ses performances, son évolutivité et sa fiabilité.
La disponibilité du service est mesurée en pourcentage de temps d’activité et peut faire l’objet d’un SLA. Elle peut être impactée par des soucis liés à l’infrastructure, à des bugs applicatifs, à un dimensionnement insuffisant.
La performance est la capacité du service à exécuter une action dans un laps de temps acceptable. Cela inclut la mesure et le suivi de l’évolution temporelle de la consommation de ressources (CPU, mémoire, réseau, I/O disque…) sur chacun des serveurs de l’infrastructure cible, ainsi que sur les middlewares (nombre de messages déposés dans une file d’attente, nombre de requêtes par seconde, temps de réponse des serveurs web, latence sur les appels d’API…) ou sur les bases de données (nombre de transactions par seconde…).
L’évolutivité est la capacité du service à gérer une charge plus conséquente sans interruption de service ni impact sur les performances.
La fiabilité d’un service est sa capacité à ne pas rencontrer de dysfonctionnements. La difficulté est de faire le lien entre les données liées à un plantage de l’application en production (erreurs dans le journal des évènements, état de la pile d’appels) et les données d’utilisation (l’état dans lequel était l’application lorsque le problème s’est produit). D’où l’intérêt pour le testeur DevOps de mettre en place le niveau d’instrumentation permettant d’établir cette corrélation ou de s’appuyer sur des technologies comme IntelliTrace sur des environnements .NET.
En définitive, la qualité est avant tout le résultat d’un ensemble de caractéristiques laissées à la libre appréciation de l’utilisateur. Certes, offrir un excellent niveau de fiabilité du logiciel avec une très bonne disponibilité du service est fondamental, mais proposer une solution exempte de tout défaut qui ne serait utilisée par personne ne présenterait aucun intérêt. Parmi les critères à retenir, l’un des plus importants reste donc doute celui de l’adéquation entre les fonctions proposées par ce produit ou ce service et les attentes de l’utilisateur. Sont-elles effectivement appelées ? Quelle valeur ajoutée apportent-elles ? La solution offre-t-elle globalement un niveau de finition (performance, ergonomie et design de l’interface) aligné sur le niveau d’exigence de l’utilisateur ? Autant de questions auxquelles la capture de données d’utilisation peut apporter un premier niveau de réponse.
En effet, les données d’utilisation d’une application sont aujourd’hui un élément clé dans la détermination de la qualité du service. Afin de savoir comment un service est réellement utilisé, il est nécessaire d’obtenir de grandes quantités de données et de pouvoir en analyser certaines en temps réel. La télémétrie permet de savoir comment les clients interagissent avec l’application. Mais pour garantir la bonne utilisation d’un service, il faut étendre la capture de données utilisateurs à d’autres sources comme par exemple les logs du support en charge du service, ou les feedbacks remontés par les utilisateurs sur des canaux internes ou externes (réseaux sociaux…). L’analyse de ce type de données avec un fort potentiel de volume et de vélocité suppose l’utilisation de technologies liées au monde du big data.
La collecte des données sur l’utilisation que l’utilisateur fait du service doit respecter sa vie privée, en particulier s’il s’agit de données sensibles comme le numéro de carte bleue ; le développeur ou le testeur DevOps devront donc veiller à ne pas archiver ce type de données dans les logs et à rendre anonymes celles qui concernent directement l’utilisateur.
Du fait de l’évolution du marché et de la mise à disposition de nouvelles versions d’un service ou d’un produit dans des temps plus réduits, il devient nécessaire d’adopter une approche plus pragmatique pour les tests. Il faut éviter de gaspiller des ressources, en réalisant, documentant et en exécutant des tests inutiles ou qui ne tiennent pas compte des nouvelles possibilités qu’offrent la capture et l’analyse de flux d’information.
Le concept du Minimum Viable Product issu de la méthode Lean Startup s’applique aux équipes qualité DevOps. Selon ce principe, il s’agit de livrer un logiciel avec un niveau de qualité suffisant et de nouvelles fonctions qui permettent de livrer au plus tôt pour fidéliser les utilisateurs existants et en attirer de nouveaux… Ce niveau de qualité suffisant associé à une prise de risque contrôlée correspond à une évolution de la démarche de garantie de la qualité par les tests. Il s’agit donc d’éviter de trop tester, car non seulement cela a un coût mais cela traduit aussi par un accroissement des délais de mise à disposition des services ou des produits. On parle alors de Lean Testing : tester moins, mais de livrer plus souvent des évolutions sur des périmètres plus réduits et de garder le contrôle grâce à la capture en continu de données issues de la production. Au final, la qualité reste plus maîtrisée.
Comme nous l’avons vu, garantir la qualité consiste à gérer des risques. Une approche équilibrée consiste à définir des catégories d’utilisateurs avec des populations susceptibles d’avoir un niveau variable d’acceptation d’une défaillance provisoire et de capitaliser sur les possibilités qu’offre l’automatisation de l’infrastructure pour procéder à d’éventuels retours arrière.
Ainsi, chez Microsoft le premier cercle des testeurs est l’équipe en charge du développement du produit ou du service. Ils acceptent plus facilement la présence de bugs, et sont aux premières loges pour les corriger. De même, on y pratique depuis de nombreuses années le dogfooding, approche qui consiste à valider le bon fonctionnement des dernières versions des logicielles en les mettant en production sur l’informatique interne… Les bugs sont acceptés, tant qu’ils ne sont pas préjudiciables à l’activité de l’entreprise. Enfin, le programme Windows Insider, qui a accompagné (et continue d’accompagner) le développement de la dernière version du système d’exploitation de Microsoft, a impliqué 4,1 millions d’utilisateurs dans plus d’une centaine de pays. Une population qui est prête à souffrir de défaillances prévisibles d’une pré-version, mais qui les accepte afin de pouvoir faire partie des early adopters et de pouvoir contribuer à l’évolution fonctionnelle du produit. On retrouve la même approche sur les choix d’interfaces proposées aux utilisateurs de Facebook ou sur les expériences que Google mène sur son portail de recherche.
Lorsqu’elle est correctement implémentée, cette approche permet d’organiser plusieurs typologies d’utilisateur avec différents niveaux d’acceptation du risque. En général, plus le nombre d’utilisateurs augmente, plus le niveau de risque diminue. Et en définitive, pour le consommateur, la tolérance à l’échec est très faible : il faut offrir aux clients un niveau de qualité en adéquation avec leurs attentes, sous réserve de les perdre à jamais.
Avec l’évolution du métier du testeur logiciel, le Data Driven Engineering a remplacé le Software Testing.
Prévenir plutôt que guérir
Plutôt que détecter les bugs a posteriori, l’approche DevOps consiste à essayer de les anticiper.
Ainsi Alan Page, architecte au sein du groupe Microsoft Engineering Excellence et responsable de la mise en œuvre des tests logiciels, raconte comment, en constatant la fréquente occurrence de bugs liés à une mauvaise utilisation d’une librairie, il avait écrit un code permettant de détecter cette erreur. Il l’avait ensuite lancé sur le référentiel de code source pour permettre la correction de l’existant et l’avait ajouté à la liste des vérifications à effectuer par le développeur avant chaque archivage de code, prévenant ainsi de multiples bugs. Cette démarche est applicable dès lors qu’ont été établis un modèle d’erreur reproductible et le correctif de code associé. En général, ces risques d’erreurs récurrentes sont gérés lors des revues de code.
Une démarche outillée permet d’aller plus loin en pratiquant une analyse prédictive de la qualité. L’objectif est d’utiliser l’information extraite de l’analyse des données pour anticiper les modèles de comportement des utilisateurs et de fonctionnement du système en utilisant les techniques du machine learning.
Une nouvelle stratégie d’ingénierie
Cette stratégie correspond à un type d’expérimentation en ligne permettant de piloter un projet par les données. Elle consiste à utiliser de multiples sources de données, y compris de production, pour permettre une action rapide destinée à améliorer la qualité des produits. Les données de production permettent de vérifier la qualité réelle de l’application. Elle suppose la mise en œuvre d’un cycle itératif organisé sur différentes étapes de définition des KPI, de conception pour la collecte des données de qualité de production, de sélection des sources de données, d’analyse des résultats, et d’apprentissage. Les données de production sont issues de télémétrie sur la navigation des utilisateurs mais aussi d’informations directement générées par le système.
Le challenge, dans une perspective DevOps, sera de s’intégrer dans la globalité d’un système qui manipule également des données issues de la production et capturées en temps réel. Une première approche peut consister à injecter ses propres tests dans le système, de sorte qu’ils puissent aider à affiner l’exploration de pistes de remédiation ou d’optimisation. Il s’agit donc d’étendre les données d’instrumentation avec des données purement liées aux tests. L’approche DevOps consiste alors à émettre des hypothèses et à les instrumenter de façon à les confirmer ou les infirmer. Une autre démarche consiste à se plonger dans les données capturées et à utiliser des connaissances statistiques complétées par des techniques et des outils liés au big data pour rechercher des corrélations et identifier des modèles.
Le big data au service du développement logiciel
Même si un service ne génère pas de gros volume de données, son utilisation à l’échelle d’internet le rend potentiellement éligible à l’emploi de procédés liés au monde du big data afin de pouvoir mesurer sa qualité.
Les données brutes ne présentent pas nécessairement d’intérêt. Il faut les transformer et les analyser pour y découvrir des modèles de corrélation, y valider des hypothèses sur le fonctionnement du système et de nouvelles questions à se poser sur l’itération suivante. C’est le volume de ces données, leur variété et leur vélocité qui vont permettre ou non d’obtenir des réponses à ces questions. Et ce sont les outils et les solutions retenues qui permettront de les traiter et d’acquérir ainsi une meilleure compréhension des comportements des utilisateurs.
Il existe de multiples technologies ciblant le realtime distributed processing (comme la solution open source Apache Spark qui offre un traitement parallèle de données pour les applications analytiques du big data) ou le complex event processing (comme la solution open source Apache Storm qui est un système de calcul distribué et résilient pour le traitement de données en temps réel, inclus dans Hadoop). Ces solutions peuvent s’exécuter dans le contexte d’un service managé comme HDInsight Service.
Dans le même ordre d’idée existent également des solutions propriétaires comme le couple Event Hub et Azure Stream Analytics, qui ciblent la comparaison de plusieurs flux en temps réel. Ces solutions que l’on rencontre souvent dans le monde de l’IoT (Internet of Things) sont totalement indépendantes du contexte de la supervision. Toutefois, elles sont naturellement conçues pour remonter et analyser un grand nombre d’évènements et peuvent fort bien être adaptées pour mettre en place une remontée d’informations liées à la plateforme sur laquelle s’exécute une application et à leur analyse. Par exemple, elles peuvent être utilisées pour la détection d’anomalies et offrir ainsi la possibilité de déclencher une alerte lorsqu’une erreur ou une condition spécifique apparaissent.
En complément de ces solutions génériques, il existe des frameworks capables d’analyser un flux de données en temps réel, qui ont pour objectif de répondre spécifiquement à une problématique de type supervision. Par exemple, la solution open source Riemann, implémentée sur Riak (un système distribué NoSQL orienté documents, évolutif, hautes performances et sans schéma) permet de disposer de retours d’information avec une très faible latence permettant la notification d’un dysfonctionnement dans des délais de l’ordre de la milliseconde (et être notifié ultérieurement du résultat effectif de la correction). Elle repose sur l’utilisation d’agents capables de relayer les évènements à très haute fréquence. Le débit est ensuite impacté par la durée de traitement du flux, mais la solution est parallélisée pour traiter un grand volume de messages à très faible latence. Riemann agrège dans un flux de données les événements qui se produisent sur les serveurs et dans les applications grâce à un langage de transformation.
Ce langage permet de gérer des évènements qui se matérialisent comme des structures de données véhiculées via des Protocol Buffers (déclenchement d’alerte sur une exception, suivi de la latence de l’application web, caractéristiques sur chacun des serveurs…). Une transformation DevOps
Cette évolution nécessite une profonde transformation qui s’inscrit totalement dans une démarche DevOps. Les possibilités qu’offrent DevOps en termes de supervision et de déploiement favorisent la mise en place d’une stratégie d’ingénierie pilotée par les données. Une fois détectée et analysée la cause du dysfonctionnement, les évolutions ou les correctifs (ou les mesures d’atténuation) peuvent être déployés sur le service, l’ensemble de ces opérations s’effectuant dans un cycle de détection continu. De plus, la transformation DevOps pour la qualité nécessite un accompagnement (formation, outils, processus…) au niveau des équipes, que ce soient les testeurs, les développeurs ou les opérations. Il s’agit en effet de définir les métriques et indicateurs clés, le processus de traitement de ces données, les référentiels du stockage qui leur est alloué, les outils d’analyse, historiques ou prédictifs pour les exploiter.
Les acteurs du système d’information doivent donc progresser en connaissance sur les domaines du big data, voire du machine learning et étendre leur périmètre de vision sur la globalité du système. Au-delà de l’évolution des compétences des équipes, c’est l’occasion de voir émerger de nouveaux rôles au sein des équipes intervenant sur le cycle de production logicielle : les data scientists dont le rôle est aussi d’accélérer la progression de leurs collègues sur l’utilisation de techniques issues du big data, afin que chacun soit en mesure de s’inscrire dans un cycle d’ingénierie pilotée par les données. Cela suppose également un changement de culture au sein de l’organisation pour qu’elle accepte l’expérimentation en ligne et le pilotage de la qualité par les données. Enfin, et surtout, pour que cette évolution soit possible, il faut assurer une intense collaboration entre les différentes équipes, avec un partage des connaissances, des outils, des processus et des environnements. DevOps est donc très clairement la démarche appropriée pour évoluer vers cette Data Driven Quality.
L’une des façons d’offrir plus de qualité consiste à décomposer le projet en plusieurs phases plus courtes afin de gérer les priorités et d’anticiper les tests et les correctifs… La modularité favorise les tests, mais il est important de tester chacun des services sans présupposer du bon fonctionnement des autres. Un des moyens qu’offre DevOps pour aller vers plus de qualité est de réaliser les tests dans le prolongement du développement, avec un déclenchement dans le cadre d’un processus d’intégration continue qui permet aux développeurs, qui archivent fréquemment leur code d’obtenir très rapidement un premier niveau d’information sur la qualité de leur code.
Livrer plus fréquemment réduit les risques car la quantité et le niveau de complexité des changements sont plus réduits et donc plus faciles à contrôler. De plus, l’itération régulière d’un processus facilite sa maîtrise par l’ensemble des participants. En outre, l’automatisation de l’ensemble de la chaîne autorise les retours arrière. Il en résulte une augmentation du niveau de qualité. Le continuous delivery permet également d’obtenir plus rapidement des données sur le code de fonctionnement en production avec des utilisateurs réels. Cependant le niveau de qualité doit être suffisant pour garantir une utilisation de l’application, prérequis indispensable à la capture des données permettant de valider le bon fonctionnement du code…
D’un point de vue qualité, la gestion des releases peut être mise en œuvre selon de multiples stratégies. Plutôt que de générer à chaque nouvelle version, un package complet, une première démarche dite de release partielle peut consister à ne livrer que les composants modifiés, ce qui suppose une architecture fortement découplée. L’empreinte de la mise à jour étant nativement plus réduite, le risque de défaillance est plus réduit.
Une autre approche baptisée Toggle Features consiste à déployer les nouvelles versions des services en y intégrant les évolutions mais en s’assurant que les conditions de vérification sont validées avant de les activer par configuration. En cas d’erreur, il devient alors très simple de faire machine arrière.
Une dernière alternative consiste à exploiter la catégorisation des utilisateurs proposée par le modèle de Lean Testing en déployant progressivement vers des groupes qui acceptent un niveau de risque de défaillance du service plus ou moins élevé. Chez Netflix, cette stratégie a fait l’objet de l’appellation Canary Releases, par analogie avec le système jadis mis en place par les mineurs pour se protéger de coups de grisou, gaz inodore dont la présence ne pouvait être détectée que par l’arrêt du chant (voire la mort prématurée) du canari.
Le continuous learning est l’une des valeurs fondamentales de DevOps. Il s’agit pour chacun d’étendre ses connaissances et ses compétences dans une démarche d’apprentissage permanent pour répondre à un environnement en constante évolution. Cela passe par l’observation, l’expérimentation, le partage d’expérience, la prise de risque, l’application de modèles éprouvés et la formation. Cette démarche doit être personnelle et organisationnelle afin de permettre aux équipes d’être à même de s’adapter au changement du marché et des technologies.
D’un point de vue qualité, l’apprentissage en continu va concerner les différents moyens qui permettront d’orienter la stratégie produit et d’améliorer l’application.
La connaissance passe par la donnée
Comme nous l’avons vu dans la définition des métriques, pour prendre de meilleures décisions sur les évolutions et correctifs à apporter à une solution, un ensemble de questions clés doit être déterminé en amont du processus de mise à disposition du produit ou du service. Il s’agit ensuite d’analyser les données capturées en production pour extraire des informations, puis d’utiliser les résultats obtenus pour améliorer la qualité du service et l’expérience utilisateur. Ces données véhiculées par télémétrie sont issues du besoin de mieux comprendre comment les clients utilisent l’application. Cette démarche se déroule dans le cadre d’un cycle alimenté en continu par de nouvelles questions faisant suite aux connaissances acquises dans les précédentes itérations.
Tests en production
Malgré la mise en œuvre de tests en charge, de laboratoires de tests, il est souvent impossible de recréer les mêmes conditions qu’en production sur un environnement de pré-production. Les tests en production (TiP) proposent une façon d’apprendre sur la qualité du système en l’exposant directement aux utilisateurs réels sur les environnements de production. L’expérimentation en ligne, en conditions réelles, permet d’obtenir une meilleure connaissance de ce qui correspond ou non aux attentes des utilisateurs, d’avoir une meilleure compréhension de leurs modèles d’utilisation et d’identifier des cas de dysfonctionnement non anticipés. Cela s’inscrit totalement dans la démarche d’ingénierie pilotée par les données que nous avons précédemment décrite.
Les tests en production ne sont pas exempts de risque, mais ce risque peut être atténué en gardant le contrôle sur le niveau de diffusion du service segmenté par audience. Pour qu’une stratégie de tests en production soit couronnée de succès elle doit être associée à la mise en place d’un système de supervision et de gestion des opérations très réactif. Ainsi si la nouvelle version rencontre des dysfonctionnements, un retour arrière peut immédiatement être déclenché.
Les tests en production sont très souvent utilisés dans le monde des services, mais peuvent également être mis en œuvre sur des produits, à condition qu’ils soient connectés. Toutefois, cela suppose des contraintes supplémentaires comme la limitation des ressources de l’environnement sur lequel s’exécute l’application (mémoire, stockage, processeur…). Souvent, cela justifie l’envoi d’un ensemble d’informations issues de l’agrégation de multiples évènements, plutôt que d’une communication de ces données en continu. D’autres critères peuvent également être considérés comme la gestion des données privées ou la sécurité des réseaux.
Un exemple de processus de tests en production est l’A/B Testing. Il s’agit d’un procédé qui permet de savoir quelle est la solution qui répond le mieux aux attentes des utilisateurs en combinant l’analyse d’informations issues de la télémétrie et le déploiement par catégorie d’utilisateur. Chaque déploiement est l’occasion de déployer en production de multiples versions de la même application offrant chacune une interaction et une expérience différente pour l’utilisateur. Le système est couplé avec un mécanisme permettant de router dynamiquement les différentes typologies d’utilisateurs sur le service ciblé. L’objectif est ensuite de mesurer par analyse statistique quelle version offre le meilleur niveau de satisfaction aux objectifs de la fonction et d’engagement de l’utilisateur (achat, recherche…). Une variante peut consister à déployer une nouvelle version, proposant par exemple une nouvelle interface utilisateur en parallèle de l’ancienne, pour les comparer deux à deux, grâce à la capture de données qualitatives en production. C’est une pratique des plus courantes chez Amazon, Google ou Microsoft.
L’échec comme source d’apprentissage
Enfin, une autre façon d’apprendre est d’échouer. On a beau essayer de prévenir l’échec, tôt ou tard il finit par se produire. L’approche DevOps consiste alors à apprendre et à progresser à partir de ces défaillances. Comme nous l’avons déjà dit, une façon d’accompagner cette démarche va consister à injecter volontairement des défauts dans le système afin de s’assurer que le service est tolérant aux pannes et qu’il sera capable de se reconfigurer (ou d’être reconfiguré) en cas d’interruption de service. De bons exemples de cette démarche sont les initiatives de Netflix (la fameuse Simian Army avec ses Chaos Monkey et Chaos Gorilla) ou d’Amazon (Amazon Game Day).
Déjà considérée comme un frein pour les processus IT existants, la sécurité peut devenir un véritable obstacle pour DevOps : avec le continuous delivery, les mécanismes traditionnels liés à la mise en production sécurisée d’une nouvelle application ne sont plus applicables. Un changement culturel est donc requis pour intégrer la sécurité au cœur des processus DevOps. Les outils de sécurité existants doivent également être revus ou complétés pour éviter les délais induits par une utilisation trop statique ou ponctuelle. Depuis quelques années, différentes initiatives participent à cette évolution.
De multiples initiatives portées par des communautés ou des éditeurs recommandent l’inclusion des contrôles de sécurité tout au long des différentes phases du cycle de vie de développement de logiciel.
Open Web Application Security Project (OWASP)
OWASP est une communauté dont l’objectif est d’aider les organisations à devenir plus efficaces dans la protection de leurs systèmes sur Internet en proposant des recommandations (OWASP Testing Framework, OWASP Developer Guide) et en mettant régulièrement à jour un inventaire des dix types de menaces liées à la sécurité les plus critiques pour les applications web : injection, violation de gestion d’authentification et de session, cross-site scripting (XSS), références directes non sécurisées à un objet, mauvaise configuration de sécurité, exposition de données sensibles, manque de contrôle d’accès au niveau fonctionnel, falsification de requête inter-sites (CSRF, Cross-Site Request Forgery), utilisation de composants avec des vulnérabilités connues, redirection et renvois non validés.
Microsoft SDL
Microsoft SDL (Security Development Lifecycle) est un processus d’assurance qualité centré sur le développement de logiciel. Depuis 2004, SDL est appliqué sur chacun des produits, technologies et services Microsoft. La formation et la responsabilisation des acteurs du cycle de vie logiciel sont au cœur de cette démarche : chacun doit avoir une compréhension des causes et des effets des vulnérabilités en sécurité, dans un environnement dans lequel les typologies de menaces sont en constante évolution. Pour permettre aux organisations de réagir le plus efficacement face à ces changements, SDL recommande la mise en œuvre de revues régulières du processus en vue d’une amélioration en continu, notamment par la collecte de métriques pendant son déroulement. Enfin, SDL inclut un plan de réponse aux incidents et impose l’archivage de l’ensemble des données liées à leur résolution.
Rugged Software Development
L’objectif de cette initiative, lancée en 2009 est de créer des applications hautement disponibles, tolérantes aux pannes, sécurisées et résilientes, en anticipant les risques de menaces et en créant les défenses appropriées. Cette démarche consiste à instrumenter le code, expérimenter en continu pour vérifier s’il existe des failles et aboutir à un code vraiment robuste.
Rugged DevOps
Rugged DevOps lancée lors de conférence RSA en 2012, par Gene Kim, CTO et créateur de Tripwire, avec Joshua Corman, directeur de la sécurité pour Akamai Technologies, adapte les principes du Rugged Software Development à une gestion sécurisée de l’infrastructure, du développement et des opérations. La démarche consiste à intégrer la sécurité à chaque étape du cycle de vie logiciel dans l’architecture et le design du projet, dans les pratiques et outils opérationnels associés au pipeline de déploiement et de réserver aux tâches liées à la sécurité une priorité plus élevée dans le backlog.
La sécurisation du cycle de vie logiciel suppose la prise en compte de principes de sécurité, dès la phase de conception.
Conception
La sécurité est intégrée dans la définition des besoins et de l’architecture, avec un focus particulier sur le modèle de gestion d’identité appliqué aux utilisateurs ou aux composantes des applications, et plus généralement sur le chiffrement des données et des échanges.
Le modèle de menaces est défini pendant la phase d’expression des exigences. Il s’agit d’un document qui inventorie les attaques possibles et leur traitement dans le backlog. Les développeurs s’attachent également à réduire la surface d’attaque des ressources les plus exposées vis-à-vis de l’extérieur, ce qui suppose l’identification (et la limitation) des services requis par l’application. Souvent, l’application évolue par rapport aux choix fonctionnels et techniques initiaux. Il convient donc de revoir régulièrement la modélisation des menaces et la définition de la surface d’attaque, afin de pouvoir prendre en compte tout nouveau type de risque de sécurité.
Implémentation
Le code fait régulièrement l’objet de revue pour s’assurer du respect des règles définies en phase de conception. Cette démarche est complétée par l’utilisation d’outils d’analyse de la conformité du code.
Le code est archivé dans un contrôle de code source et peut faire l’objet d’audits (horodatage de la modification, identité de l’utilisateur). Il faut éviter d’y persister tout élément lié à l’authentification (mot de passe, clés d’API, clé privée SSH). Dès lors qu’une donnée sensible a été archivée dans un référentiel de code source, elle doit être considérée comme compromise et doit être renouvelée, même lorsqu’il est possible d’éliminer le fichier de l’historique des versions (par exemple dans le cas de Git, il existe des commandes comme git filter-branch ou des outils comme BFG Repo-Cleaner).
Déploiement
L’automatisation du déploiement de l’infrastructure (et la validation de sa mise en œuvre sur les différentes plateformes complémentaires à la production) permet de fiabiliser l’infrastructure en supprimant le risque d’erreur humaine. Cependant les scripts de configuration doivent faire l’objet de revue de sécurité et, comme le code de l’application, ne pas contenir d’information sensible. Lorsqu’ils requièrent des informations d’identification, celles-ci doivent être chiffrées. Par exemple, dans Azure Automation, elles sont chiffrées l’aide d’une clé unique, générée pour chaque compte.
Contrôle de la sécurité
L’instrumentation du code permet de suivre et mesurer le détail de chaque action ayant entraîné tel ou tel comportement défectueux de l’application. Elle garantit la mise à disposition des éléments liés au respect de la conformité et susceptibles d’être soumis à un audit.
Le fonctionnement sécurisé de l’application est contrôlé dès la phase de build qui échoue, si des vulnérabilités ont été détectées.
Assurer la sécurité d’une application et éviter les régressions suppose la capacité à détecter ses vulnérabilités en continu, ce qui suppose le lancement automatisé de tests dont il convient de définir les spécifications.
Behavior Driven Development (BDD)
La démarche BDD consiste à faire usage d’un langage formel (comme Gherkin), compréhensible par chacun et à le rendre exécutable. Description des tests et actions sont alors couplées et directement intégrés dans des processus automatisés. Au langage Gherkin peuvent être associés des solutions open source comme JBehave ou Cucumber pour les compléter par une implémentation des fonctions correspondantes (features) réalisée en association avec des frameworks de tests unitaires.
Ainsi, dans le monde .NET, l’extension Cucumber s’appelle SpecFlow et elle peut être directement couplée à NUnit. Autre exemple, dans les environnements Ruby, la solution open source Gauntlt (fournie sous forme de gem) offre une infrastructure de tests de sécurité automatisée. Elle complète la formalisation de tests Gherkin avec une combinaison d’outils de sécurité (dont on peut automatiser l’installation avec le script vagrant Gauntlt Starter Kit). Gauntlt est livré avec un ensemble de définition d’attaques prédéfinies associées aux outils de sécurité permettant de vérifier le niveau de protection vis-à-vis de ces attaques : comme NMap pour tester quels sont les ports ouverts, SQLmap pour détecter les vulnérabilités aux attaques de type SQL injection, Arachni pour se prémunir contre le Cross-Script Scripting (XSS)…
Cette approche présente en outre l’intérêt de partager la connaissance sur les exigences de sécurité et de les inclure dans les critères d’acceptation de la solution. Elle suppose la mise à disposition de différents types de tests automatisés.
Tests automatisés
L’inclusion de mécanismes permettant de sécuriser l’application directement dans le pipeline d’intégration et de déploiement continu repose sur la mise en œuvre d’outils et de tests de sécurité automatisés sur l’application en exécution. Le résultat de ces tests est ensuite conservé pour en assurer la traçabilité.
Ils existent de nombreux outils génériques de test permettant de déceler les vulnérabilités (XSS, CSRF…) sur les serveurs cibles, de les classer par criticité, de proposer une assistance à la remédiation et de faciliter le contrôle de conformité, avec des fonctions de scan réseau, d’interception des échanges http, de découverte des pages (spider), d’analyse, modification et jeu des requêtes web… Parmi les solutions les plus connues, on peut citer Nessus (ou son fork OpenVas), w3af (web application attack and audit framework), OWASP Zed Attack Proxy (ZAP), Burp Intruder…
Mais, comme l’a rappelé Michael Howard lors de la Conférence AppSec OWASP de 2006 : Tools do not make software secure! They help scale the process and help enforce policy. Les outils génériques ne suffisent pas à identifier l’ensemble des failles que peut présenter une application. Pour aller plus loin dans la détection des vulnérabilités d’une application, des tests dynamiques spécifiques à l’application peuvent être réalisés. Par exemple, les tests fuzz par injection de données mal formées ou aléatoires sur les interfaces de l’application sont directement liés à ses caractéristiques fonctionnelles et techniques. Dans le cas des applications web, l’implémentation de ce type de tests peut être facilitée par l’utilisation d’outils open source comme Sélénium, WatiR –(Ruby), WatiN (.Net) ou propriétaires (Visual Studio…).
Le principe consiste alors à automatiser ces tests, qu’ils soient génériques ou spécifiques avec des frameworks comme Cucumber, Gauntlt, Behave et à les intégrer dans le processus de build, afin de pouvoir les appliquer le plus fréquemment possible. Enfin, plus généralement, l’ensemble des composants de l’application doivent également faire l’objet de tests permettant de valider leur robustesse avant intégration.
Tests d’intrusion
Une fois l’application déployée, la démarche de détection des vulnérabilités se poursuit par la mise en œuvre de tests d’intrusion (pentest). Il s’agit d’une simulation d’attaque ciblant un défaut de code ou de configuration, en vue de proposer un plan d’actions permettant d’évaluer les risques et améliorer la sécurité d’un système. Ces tests sont de différents types.
Test de type blackbox
Le testeur ne dispose d’aucune information. Les tests blackbox débutent donc par une recherche d’informations sur l’entreprise que l’on tente d’infiltrer (ou ses employés) par des techniques non intrusives : réseaux sociaux, moteurs de recherche, outils DNS (nslookup, whois), outils de géolocalisation d’adresse IP (traceroute). À partir de ces premières informations, l’approche consiste à établir une cartographie du système en inventoriant les ressources (via des protocoles tels que SNMP, RPC et SMB), en analysant les flux de communication avec un sniffer, en balayant les ports (avec des outils comme Nmap), et en identifiant les services. L’objectif est de tenter de compromettre le système en détectant (avec des outils comme Nexus), voire en exploitant ses vulnérabilités.
Test de type greybox
Le testeur dispose d’un nombre limité d’informations qui lui permet notamment de passer l’étape d’authentification (par exemple couple identifiant - mot de passe). L’objectif d’un test greybox est d’évaluer le niveau de sécurité vis-à-vis d’un simple utilisateur.
Test de type whitebox
Le testeur possède de toutes les informations requises pour lui permettre de rechercher les failles (architecture, code source, identifiants…) directement depuis l’intérieur du système.
Stratégie Assume Breach
Quel que soit le niveau de sécurisation de la chaîne logicielle, des failles peuvent subsister dans le système. D’où l’intérêt de mettre en place une stratégie fondée sur l’existence présumée de ces vulnérabilités. Ainsi, chez Microsoft une équipe (Red Team) d’experts en sécurité simule en permanence des attaques sur le réseau, la plateforme et les services pour valider la capacité du cloud Microsoft Azure à résister à ces attaques ou la capacité des équipes à y remédier en suivant un processus de gestion des incidents en cinq étapes (identification, isolation, éradication, restauration, et analyse a posteriori). De même, chez Netflix, l’outil Security Monkey est lancé périodiquement pour détecter les vulnérabilités. Nous en reparlerons au chapitre 8.
Réduire le MTTRQ
Il est impossible de pouvoir prévenir toute attaque. Là encore, c’est la réduction du MTTR qui permet d’avoir une infrastructure plus sécurisée en offrant un niveau de réponse plus rapide et des contre-mesures qui n’ajoutent pas de nouvelles vulnérabilités.
En résumé
Les nouveaux impératifs de fréquence accrue de livraison qu’impose le marché, dans un monde de services en perpétuel changement ont un impact très significatif sur les métiers liés à la qualité. Que ce soit l’ingénieur qualité, le testeur logiciel, le développeur ou l’administrateur système, chacun à un rôle à jouer dans cette évolution. Pour l’accompagner, il devient plus que jamais nécessaire de disposer d’outils permettant de mesurer en continu la qualité sur la base de critères organisationnels, techniques et fonctionnels. Le fondement de la qualité devient donc la donnée.
Avec le Data Driven Engineering, la qualité joue aujourd’hui un rôle majeur dans la stratégie d’ingénierie, en permettant de directement alimenter et orienter la chaîne de production logicielle avec des données issues de la production. La qualité vient donc enrichir la production logicielle qui dans le même temps va vers toujours plus de qualité, dans un mode de continuous learning. Cela suppose pour l’ensemble des métiers l’acquisition de nouvelles compétences sur les domaines du big data, voire du machine learning et l’émergence d’un nouveau rôle au sein des équipes intervenant sur le cycle de production logicielle : celui du data scientist. Cette transformation est favorisée par les possibilités offertes par la mise en œuvre d’une démarche DevOps, tant sur le plan culturel, avec l’expérimentation en ligne et le pilotage de la qualité par les données, que sur le plan de la collaboration entre les différentes équipes.
Enfin, intégrer la sécurité au cœur des processus DevOps requiert la responsabilisation de chacun des acteurs du cycle de production logicielle et une évolution des outils et des processus de l’automatisation de la détection et de l’identification des vulnérabilités.