Résumé : avoir accès à une liste de composants logiciels et à leurs métadonnées respectives est essentiel pour effectuer avec succès diverses tâches DevOps. Après avoir examiné les différentes exigences des différentes tâches, nous avons déterminé que la représentation d’un composant logiciel comme une « collection de fichiers » fournissait une représentation optimale. Inversement, lorsque des informations au niveau du fichier sont manquantes, la plupart des tâches deviennent plus coûteuses ou carrément impossibles à réaliser.
introduction
Avoir accès à la liste des composants logiciels qui composent une solution logicielle, parfois appelée nomenclature logicielle (SBOM), est une exigence pour l’exécution réussie des tâches DevOps suivantes :
- Conformité des licences Open Source et tierces
- Gestion des vulnérabilités de sécurité
- Protection contre les logiciels malveillants
- Conformité à l’exportation
- Certification de sécurité fonctionnelle
Un effort communautaire, dirigé par la National Telecommunications and Information Administration (NTIA) [1], est en cours pour créer un format d’échange SBOM piloté principalement par la tâche de gestion des vulnérabilités de sécurité. Le Saint Graal d’une conception SBOM efficace est double :
- Définir une structure de données communément acceptée qui représente le mieux un composant logiciel et ;
- Concevoir une méthode qui identifie de manière unique et efficace chaque composant logiciel.
Un composant doit représenter un large éventail de types de logiciels, y compris (mais sans s’y limiter) : un fichier source unique, une bibliothèque, un exécutable d’application, un conteneur, un environnement d’exécution Linux ou un système plus complexe composé d’une combinaison de ces éléments les types. Par exemple, une collection de fichiers source (par exemple, boîte occupée 1.27.2) ou une collection de trois conteneurs (par exemple, une demi-douzaine de scripts et de documentation) sont deux exemples.
Étant donné que nous devons gérer une gamme éclectique de types de composants, il est essentiel de trouver le bon niveau de représentation granulaire. S’il est trop volumineux, nous ne pourrons pas représenter tous les types de composants et les méta-informations correspondantes nécessaires pour prendre en charge les différentes tâches DevOps. D’un autre côté, cela peut ajouter une complexité, des coûts et des frictions inutiles à l’adoption si elle est trop petite.
Traditionnellement, les composants ont été représentés au niveau du progiciel ou de l’archive, où le nom et la version sont les principaux moyens d’identifier le composant. Cela présente plusieurs défis, les deux plus importants étant :
- Le fait que deux composants logiciels différents puissent avoir le même nom tout en étant différents, et
- Inversement, deux copies de logiciels portant des noms différents pourraient être identiques.
Une autre méthode traditionnelle consiste à s’appuyer sur le hachage du logiciel en utilisant l’une de plusieurs méthodes – par exemple, SHA1, SHA256 ou MD5. Cela fonctionne bien lorsque votre composant logiciel représente un seul fichier, mais cela pose un problème lors de la description de composants plus complexes composés de plusieurs fichiers. Par exemple, la même collection de fichiers source (par exemple, busybox-1.27.2 [2]) pourrait être empaqueté à l’aide de différentes méthodes d’archivage (par exemple, .zip, .gz, .bz2), ce qui entraînerait le même ensemble de fichiers ayant des hachages différents en raison des différentes méthodes d’archivage utilisées.
Après avoir examiné les différentes exigences pour les différentes tâches DevOps énumérées ci-dessus, et étant donné le large éventail de types de composants logiciels, nous avons conclu que la représentation d’un composant logiciel comme une « collection de fichiers » où le « fichier » sert d’unité atomique fournit un représentation.
Ce niveau granulaire permet d’accéder aux métadonnées au niveau du fichier, conduisant à un résultat de meilleure qualité lors de l’exécution des différentes tâches DevOps (par exemple, les licences au niveau du fichier pour la conformité des licences, les données de vulnérabilité au niveau du fichier pour la gestion de la sécurité et les informations de cryptographie au niveau du fichier pour la conformité à l’exportation). Pour calculer l’identifiant unique d’un composant donné, nous recommandons de prendre le « hachage » de tous les « hachages de fichiers » des fichiers qui composent un composant. Cela permet une identification unique indépendamment de la façon dont les fichiers sont conditionnés. Nous discutons plus en détail de cette approche dans les sections qui suivent.
Pourquoi le niveau du fichier est important
Pour obtenir les informations les plus précises pour prendre en charge suffisamment les différentes tâches DevOps, il faudrait accéder aux métadonnées au niveau du fichier atomique. Cela ne devrait pas être surprenant étant donné que les fichiers servent de blocs de construction à partir desquels le logiciel est construit. Si nous représentions le logiciel à un niveau supérieur (par exemple, juste le nom et la version), les informations pertinentes seraient perdues.
Conformité des licences
Si vous voulez comprendre toutes les licences qui imposent des obligations et des restrictions à un programme ou à une bibliothèque, vous aurez besoin de connaître toutes les licences des fichiers à partir desquels il a été construit (dérivé). Il existe de nombreux cas où, bien que la licence de niveau supérieur d’un composant logiciel open source soit déclarée être une licence, il est courant de trouver une demi-douzaine ou plus d’autres licences dans la base de code qui imposent généralement des obligations supplémentaires. Les projets open source populaires empruntent généralement à d’autres projets avec des licences différentes. Le partage ouvert de code est la force derrière le succès du mouvement Open Source. Pour cette raison, nous devons accepter la diversité des licences comme la règle plutôt que l’exception.
Cela signifie qu’un projet est souvent soumis aux obligations de plusieurs licences. Considérez l’impact de cela sur l’utilisation de boîte occupée, qui offre beaucoup de latitude concernant les fonctionnalités incluses dans un build. Comment on configure boîte occupée déterminera quels fichiers sont utilisés. Connaître les fichiers utilisés est le seul moyen de savoir quelles licences sont applicables. Par exemple, bien que la licence de niveau supérieur soit GPL-2.0, le fichier source math.c [3] est régi par trois licences (GPL-2.0, MIT et BSD) car il est dérivé de trois projets différents.
Si l’on distribuait une solution qui inclut une instance de boîte occupée dérivé de math.c et fourni une offre écrite pour le code source, il faudrait reproduire leurs avis de licence respectifs dans la documentation pour se conformer aux licences MIT et BSD. De plus, nous avons récemment vu un composant open source avec Apache comme licence de niveau supérieur, mais au plus profond des entrailles du code source se trouve un ensemble de fichiers propriétaires. Ces exemples illustrent pourquoi avoir des informations au niveau du fichier est critique.
Gestion des vulnérabilités de sécurité
le Saignement de cœur La vulnérabilité a été identifiée dans le composant OpenSSL en 2014. De nombreux serveurs Web utilisaient OpenSSL pour fournir une communication sécurisée entre un navigateur et un site Web. S’il n’est pas corrigé, il permettrait aux attaquants un accès sans précédent à des informations sensibles telles que les identifiants de connexion et de mot de passe [4]. Cette vulnérabilité pourrait être isolée sur une seule ligne dans un seul fichier. Par conséquent, la le plus simple et le plus définitif Le moyen de comprendre si quelqu’un était exposé était de déterminer si son instance d’OpenSSL avait été construite à l’aide de ce fichier.
le Amnésie : 33 annonce de vulnérabilité [5], rapporté en novembre 2020, suggérait que toute solution logicielle incluant le composant FNET était affectée. Avec seulement le nom et la version du composant FNET, on aurait conclu à tort que le système d’exploitation Zephyr LTS 1.14 était vulnérable. Cependant, en examinant la source au niveau du fichier, on aurait pu rapidement déterminer que les fichiers impactés ne faisaient pas partie de la version Zephyr, ce qui montre clairement que Zephyr n’était en fait pas vulnérable. [6]. Devoir procéder à un rappel de produit alors qu’un produit n’est pas affecté serait hautement improductif et coûteux. Cependant, en l’absence d’informations au niveau du fichier, l’analyse n’aurait pas été possible et aurait probablement causé des soucis, du travail et des coûts inutiles. Ces exemples illustrent davantage pourquoi l’accès aux informations au niveau des fichiers est essentiel.
Conformité à l’exportation
La qualité de sortie d’un programme de conformité à l’exportation dépend également de l’accès aux données au niveau du fichier. Bien que différents gouvernements aient des règles et des exigences différentes concernant la conformité des licences d’exportation de logiciels, la plupart des politiques se concentrent sur l’utilisation de méthodes et d’algorithmes de cryptographie. Pour comprendre quelles bibliothèques et algorithmes de cryptographie sont implémentés, il faut inspecter le code source au niveau du fichier. Selon la manière dont une solution logicielle donnée est construite et quels fichiers basés sur la cryptographie sont utilisés (ou non utilisés), il convient de classer le logiciel en fonction des différentes politiques de juridiction. L’accès aux données au niveau des fichiers permettrait également de déterminer dynamiquement la classification d’une juridiction donnée. Les exigences de la tâche de conformité d’exportation signifient également que savoir ce qui se trouve au niveau du fichier est essentiel.
Sécurité fonctionnelle
L’objectif de la sécurité fonctionnelle processus de certification des logiciels est d’atténuer le risque inacceptable de blessures physiques ou de dommages à la santé des personnes et/ou des biens. Les normes qui régissent la sécurité fonctionnelle (par exemple, ISO/IEC 61508, ISO 26262, …) exigent que le contexte du système complet soit connu pour évaluer et atténuer les risques avec succès. Par conséquent, une transparence totale du système nécessite une vérification et une validation au niveau du fichier source, ce qui inclut la compréhension de tout le code source et des outils de génération utilisés, ainsi que la manière dont il a été configuré. L’inclusion de composants de contenu et de provenance inconnus augmenterait le risque et interdirait la plupart des certifications. Ainsi, la certification fonctionnellement sûre représente une autre tâche où la possession d’informations au niveau du fichier devient critique.
Identification des composants
L’un des plus grands défis de la gestion des composants logiciels est la capacité à les identifier de manière unique. Le développement d’une méthode de confiance élevée garantit que deux copies d’un composant sont identiques lorsqu’elles représentent un contenu identique et différentes si le contenu n’est pas identique. De plus, nous voulons éviter de créer une dépendance sur un registre de composants central comme condition requise pour déterminer l’identifiant d’un composant. Par conséquent, une exigence supplémentaire est de pouvoir calculer un identifiant unique simplement en examinant le contenu du composant.
Comprendre la composition au niveau fichier d’un composant peut jouer un rôle essentiel dans la conception d’une telle méthode. Rappelez-vous que notre objectif est de permettre à un composant logiciel de représenter un large éventail de types de composants allant d’un seul fichier source à une collection de conteneurs et d’autres fichiers. Chaque composant pourrait donc être décomposé en une collection de fichiers. Cette représentation permet la construction d’une méthode qui peut identifier de manière unique n’importe quel composant donné.
Les méthodes de hachage de fichier telles que SHA1, SHA256 et MD5 sont efficaces pour identifier de manière unique un seul fichier. Cependant, lors de la représentation d’un composant comme une collection de fichiers, nous pouvons le représenter de manière unique en créant un méta-hachage, c’est-à-dire en prenant le hachage de « tous les hachages de fichiers » des fichiers qui composent un composant. C’est-à-dire, i) générer un hachage pour chaque fichier (par exemple, en utilisant SHA256), ii) trier la liste des hachages, et iii) prendre le hachage de la liste triée. Ainsi, l’approche du méta-hash nous permettrait d’identifier un composant uniquement sur la base de son contenu de manière unique, et aucun registre ou référentiel de vérité n’est requis.
Conclusion
L’accès aux composants logiciels et à leurs métadonnées respectives est essentiel à l’exécution de diverses tâches DevOps. Par conséquent, il est essentiel d’établir le bon niveau de granularité pour garantir que nous pouvons capturer toutes les données requises. Ce défi est encore compliqué par la nécessité de gérer une gamme éclectique de types de composants. Par conséquent, il est essentiel de trouver le bon niveau granulaire de représentation. S’il est trop grand, nous ne représenterons pas tous les types de composants et les méta-informations nécessaires pour prendre en charge la fonction DevOps. S’il est trop petit, nous pourrions ajouter une complexité, des coûts et des frictions inutiles à l’adoption. Nous avons déterminé qu’une représentation au niveau du fichier est optimale pour représenter les différents types de composants, capturer toutes les informations nécessaires et fournir une méthode efficace pour identifier les composants de manière unique.
Les références
[1] NTIA : page Web de la nomenclature des logiciels, https://www.ntia.gov/SBOM
[2] Projet Busybox, https://busybox.net/
[3] Archives du patrimoine logiciel : math.c, https://archive.softwareheritage.org/api/1/content/sha1:695d7abcac1da03e484bcb0defbee53d4652c347/raw/
[4] Wikipédia : Heartbleed, https://en.wikipedia.org/wiki/Heartbleed
[5] « AMNESIA : 33 : des chercheurs révèlent 33 vulnérabilités dans quatre bibliothèques TCP/IP open source », https://www.tenable.com/blog/amnesia33-researchers-disclose-33-vulnerabilities-tcpip-libraries-uip-fnet-picotcp-nutnet
[6] Mise à jour de sécurité Zephyr sur Amnesia:33, https://www.zephyrproject.org/zephyr-security-update-on-amnesia33/