Gestion des dépendances

Restez organisé à l'aide des collections Enregistrez et classez les contenus selon vos préférences.

Ce document décrit les dépendances d'application et les bonnes pratiques pour les gérer, y compris la surveillance des failles, la vérification des artefacts, la réduction de l'encombrement de la dépendance et la compatibilité avec les builds reproductibles.

Une dépendance logicielle est un logiciel dont votre application a besoin pour fonctionner, comme une bibliothèque logicielle ou un plug-in. La résolution des dépendances peut se produire lors de la compilation du code, de la compilation, de l'exécution, du téléchargement ou de l'installation de votre logiciel.

Les dépendances peuvent inclure des composants que vous créez, des logiciels tiers propriétaires et des logiciels Open Source. L'approche que vous adoptez pour gérer les dépendances peut avoir un impact sur la sécurité et la fiabilité de vos applications.

Les spécificités de la mise en œuvre de bonnes pratiques peuvent varier en fonction du format de l'artefact et des outils que vous utilisez, mais les principes généraux s'appliquent.

Dépendances directes et transitives

Vos applications peuvent inclure des dépendances directes et transitives:

Dépendances directes
Composants logiciels auxquels une application fait directement référence.
Dépendances transitives
Composants logiciels requis par les fonctionnalités directes d'une application. Chaque dépendance peut avoir ses propres dépendances directes et indirectes, créant ainsi un arbre récursif de dépendances transitives qui affectent toutes l'application.

Différents langages de programmation offrent différents niveaux de visibilité sur les dépendances et leurs relations. En outre, certains langages utilisent des gestionnaires de packages pour résoudre l'arborescence des dépendances lors de l'installation ou du déploiement d'un package.

Dans l'écosystème Node.js, les gestionnaires de packages npm et yarn utilisent des fichiers de verrouillage pour identifier les versions de dépendance permettant de créer un module, ainsi que les versions de dépendances téléchargées par un gestionnaire de packages pour une installation spécifique du module. Dans d'autres écosystèmes de langage tels que Java, l'introspection des dépendances est plus limitée. En outre, les systèmes de compilation doivent utiliser des gestionnaires de dépendances spécifiques pour gérer systématiquement les dépendances.

Prenons l'exemple du module npm glob version 8.0.2. Vous déclarez des dépendances directes pour les modules npm dans le fichier package.json. Dans le fichier package.json pour glob, la section dependencies répertorie les dépendances directes du package publié. La section devDepdencies répertorie les dépendances pour le développement local et les tests par les responsables et contributeurs de glob.

  • Sur le site Web npm, la page global répertorie les dépendances directes et les dépendances de développement, mais n'indique pas si ces modules ont également leurs propres dépendances.

  • Vous trouverez des informations supplémentaires sur les dépendances glob sur le site Open Source Insights. La liste de dépendances pour le fichier glob inclut les dépendances directes et les dépendances indirectes (transitives).

    Une dépendance transitive peut se composer de plusieurs couches de profondeur dans l'arborescence des dépendances. Exemple :

    1. glob 8.0.2 dépend directement de minimatch 5.0.1.
    2. minimatch 5.0.1 a une dépendance directe brace-expression 2.0.1.
    3. brace-expression 2.0.1 dépend directement de balanced-match 1.0.2.

Sans visibilité sur les dépendances indirectes, il est très difficile d'identifier et de traiter les failles et autres problèmes provenant d'un composant auquel votre code ne fait pas directement référence.

Lorsque vous installez le package glob, npm résout l'intégralité de l'arborescence des dépendances et enregistre la liste des versions téléchargées spécifiques dans le fichier package.lock.json afin que vous disposiez d'un enregistrement de toutes les dépendances. Les installations ultérieures effectuées dans le même environnement récupèrent les mêmes versions.

Outils d'analyse des dépendances

Vous pouvez utiliser les outils suivants pour comprendre vos dépendances Open Source et évaluer le niveau de sécurité de vos projets. Ces outils fournissent des informations dans tous les formats de package.

Bouclier de livraison de logiciels
Solution de sécurité de la chaîne d'approvisionnement logicielle entièrement gérée sur Google Cloud qui vous permet d'afficher des insights de sécurité pour vos artefacts dans Cloud Build, Cloud Run et GKE, y compris les failles, les informations de dépendance (aperçu privé) et la provenance des compilations. Software Delivery Shield propose également d'autres services et fonctionnalités permettant d'améliorer votre stratégie de sécurité tout au long du cycle de vie du développement logiciel.
Outils Open Source

Plusieurs outils Open Source sont disponibles, parmi lesquels:

  • Open Source Insights : site Web fournissant des informations sur les dépendances directes et indirectes connues, les failles connues et les informations sur les licences des logiciels Open Source. Le projet Open Source Insights met également ces données à disposition en tant qu'ensemble de données Google Cloud. Vous pouvez utiliser BigQuery pour explorer et analyser les données.

  • Base de données Open Source pour les failles : base de données des failles consultables regroupant les failles d'autres bases de données en un seul emplacement.

  • Tableaux de données : outil automatisé que vous pouvez utiliser pour identifier les pratiques risquées de la chaîne d'approvisionnement logicielle dans vos projets GitHub. Il effectue des vérifications sur les dépôts et attribue une note de 0 à 10 à chaque vérification. Vous pouvez ensuite utiliser les scores pour évaluer le niveau de sécurité de votre projet.

  • Allstar : application GitHub qui surveille en permanence les organisations ou les dépôts GitHub pour vérifier qu'ils respectent les règles configurées. Par exemple, vous pouvez appliquer à votre organisation GitHub une stratégie qui recherche les collaborateurs externes à l'organisation disposant d'un accès administrateur ou push.

Méthodes d'inclusion des dépendances

Il existe plusieurs méthodes courantes pour inclure des dépendances avec votre application:

Installer directement à partir de sources publiques
Installez des dépendances Open Source directement à partir de dépôts publics tels que Docker Hub, npm, PyPI ou Maven Central. Cette approche est pratique, car vous n'avez pas besoin de gérer vos dépendances externes. Toutefois, comme vous ne contrôlez pas ces dépendances externes, votre chaîne d'approvisionnement logicielle est plus susceptible de faire l'objet d'attaques en Open Source.
Stocker des copies des dépendances dans votre dépôt source
Cette approche est également appelée vendoring. Au lieu d'installer une dépendance externe à partir d'un dépôt public pendant vos compilations, vous la téléchargez et la copiez dans l'arborescence source de votre projet. Vous avez plus de contrôle sur les dépendances intégrées que vous utilisez, mais il existe plusieurs inconvénients :
  • Les dépendances fournies augmentent la taille de votre dépôt source et augmentent le taux de perte d'utilisateurs.
  • Vous devez fournir les mêmes dépendances dans chaque application distincte. Si votre dépôt source ou votre processus de compilation n'est pas compatible avec les modules sources réutilisables, vous devrez peut-être conserver plusieurs copies de vos dépendances.
  • Il peut être plus difficile de mettre à niveau les dépendances fournies par des fournisseurs.
Stocker des dépendances dans un registre privé
Un registre privé, tel que Artifact Registry, permet d'effectuer l'installation à partir d'un dépôt public tout en contrôlant vos dépendances. Avec Artifact Registry, vous pouvez :
  • Centralisez vos dépendances et artefacts de compilation pour toutes vos applications.
  • Configurez vos clients de package Docker et de langage pour qu'ils interagissent avec les dépôts privés dans Artifact Registry de la même manière qu'avec les dépôts publics.
  • Contrôlez mieux vos dépendances dans les dépôts privés:
  • Limitez l'accès à chaque dépôt avec Identity and Access Management.
  • Utilisez des dépôts distants pour mettre en cache les dépendances de sources publiques en amont et les rechercher pour détecter les failles (aperçu privé).
  • Utilisez des dépôts virtuels pour regrouper les dépôts distants et privés situés derrière un seul point de terminaison. Définissez une priorité sur chaque dépôt pour contrôler l'ordre de recherche lors du téléchargement ou de l'installation d'un artefact (aperçu privé).
  • Utilisez Artifact Registry facilement avec d'autres services Google Cloud de Software Delivery Shield, tels que Cloud Build, Cloud Run et Google Kubernetes Engine. Utilisez l'analyse automatique des failles tout au long du cycle de développement logiciel, générez la provenance des builds, contrôlez les déploiements et consultez des insights sur votre stratégie de sécurité.

Si possible, utilisez un registre privé pour vos dépendances. Dans les cas où vous ne pouvez pas utiliser de registre privé, envisagez de fournisseurer vos dépendances pour pouvoir contrôler le contenu de votre chaîne d'approvisionnement logicielle.

Épinglage

Le blocage de la version consiste à limiter une dépendance d'application à une version ou une plage de versions spécifique. Idéalement, vous épinglez une seule version d'une dépendance.

Épingler la version d'une dépendance permet de garantir que vos versions d'application sont reproductibles. Toutefois, cela signifie également que vos builds n'incluent pas de mises à jour des dépendances, y compris les correctifs de sécurité, les corrections de bugs et les améliorations.

Vous pouvez atténuer ce problème à l'aide d'outils de gestion des dépendances qui surveillent automatiquement les dépendances dans vos dépôts sources pour les nouvelles versions. Ces outils mettent à jour vos fichiers d'exigences pour mettre à niveau les dépendances si nécessaire, y compris des informations du journal des modifications ou des détails supplémentaires.

Le blocage des versions ne s'applique qu'aux dépendances directes, et non aux dépendances transitives. Par exemple, si vous épinglez la version du package my-library, celle-ci restreint la version de my-library, mais ne limite pas les versions du logiciel dont my-library dépend. Vous pouvez limiter l'arborescence des dépendances pour un package dans certaines langues à l'aide d'un fichier de verrouillage.

Validation de la signature et du hachage

Il existe plusieurs méthodes que vous pouvez utiliser pour vérifier l'authenticité d'un artefact que vous utilisez en tant que dépendance.

Validation du hachage

Un hachage est une valeur générée pour un fichier qui agit comme un identifiant unique. Vous pouvez comparer le hachage d'un artefact avec la valeur de hachage calculée par le fournisseur de l'artefact pour confirmer l'intégrité du fichier. La vérification du hachage vous aide à identifier le remplacement, la manipulation ou la corruption des dépendances par le biais d'une attaque MITM ("man in the middle") ou d'un piratage du dépôt d'artefacts.

La validation du hachage nécessite de vous assurer que le hachage que vous recevez du dépôt d'artefacts n'est pas compromis.

Validation de la signature

La validation de signature renforce la sécurité du processus de validation. Le dépôt d'artefacts, les responsables de la maintenance logicielle ou les deux peuvent signer des artefacts.

Des services tels que sigstore permettent aux mainteneurs de signer les artefacts logiciels et aux consommateurs de valider ces signatures.

L'autorisation binaire permet de vérifier que les images de conteneurs déployées dans les environnements d'exécution Google Cloud sont signées avec des attestations pour différents critères.

Verrouiller les fichiers et les dépendances compilées

Les fichiers de verrouillage sont des fichiers d'exigences entièrement résolus, spécifiant précisément la version de chaque dépendance à installer pour une application. Généralement produits automatiquement par les outils d'installation, les fichiers de verrouillage associent l'épinglage de version et la validation de la signature ou du hachage à une arborescence de dépendances complète pour votre application.

Les outils d'installation créent des arborescences de dépendances en résolvant entièrement toutes les dépendances transitives de vos dépendances de niveau supérieur, puis incluent l'arborescence de dépendances dans votre fichier de verrouillage. Par conséquent, seules ces dépendances peuvent être installées, ce qui rend les builds plus reproductibles et cohérents.

Combiner des dépendances privées et publiques

Les applications cloud natives modernes dépendent souvent à la fois d'un code Open Source et tiers, ainsi que de bibliothèques internes Open Source. Artifact Registry vous permet de partager votre logique métier entre plusieurs applications et de réutiliser les mêmes outils pour installer des bibliothèques externes et internes.

Toutefois, lorsque vous mélangez des dépendances privées et publiques, votre chaîne d'approvisionnement logicielle est plus vulnérable aux attaques par dépendance de dépendance. En publiant des projets portant le même nom que votre projet interne dans des dépôts Open Source, les pirates informatiques peuvent exploiter des programmes d'installation mal configurés pour installer leur code malveillant au lieu de leur dépendance interne.

Pour éviter une attaque par confusion des dépendances, vous pouvez prendre plusieurs mesures:

  • Vérifiez la signature ou les hachages de vos dépendances en les incluant dans un fichier de verrouillage.
  • Séparez l'installation des dépendances tierces et des dépendances internes en deux étapes distinctes.
  • Mettez explicitement en miroir les dépendances tierces dont vous avez besoin dans votre dépôt privé, manuellement ou avec un proxy intermédiaire. Les dépôts distants Artifact Registry sont des proxys de transfert pour les dépôts publics en amont.
  • Utilisez des dépôts virtuels pour consolider les dépôts Artifact Registry distants et standards à distance, derrière un seul point de terminaison. Vous pouvez configurer les priorités des dépôts en amont afin que les versions de vos artefacts privés soient toujours prioritaires sur les artefacts publics portant le même nom.
  • Utilisez des sources de confiance pour les packages publics et les images de base.

Supprimer les dépendances inutilisées

À mesure que vos besoins évoluent et que votre application évolue, vous pouvez modifier ou cesser d'utiliser certaines de vos dépendances. Le fait d'installer des dépendances non utilisées avec votre application augmente votre empreinte de dépendance et augmente le risque de compromission de la vulnérabilité de ces dépendances.

Une fois que votre application fonctionne localement, il est courant de copier toutes les dépendances installées lors du processus de développement dans le fichier des exigences de votre application. Vous déployez ensuite l'application avec toutes ces dépendances. Cette approche permet de garantir le fonctionnement de l'application déployée, mais elle risque également d'introduire des dépendances dont vous n'avez pas besoin en production.

Soyez prudent lorsque vous ajoutez des dépendances à votre application. Chacune d'entre elles peut présenter davantage de code que vous n'avez pas le contrôle total. Dans votre pipeline d'analyse lint et de test standard, intégrez des outils qui auditent vos fichiers d'exigences pour déterminer si vous utilisez ou importez réellement vos dépendances.

Certains langages disposent d'outils pour vous aider à gérer vos dépendances. Par exemple, vous pouvez utiliser le plug-in Maven Dependency pour analyser et gérer les dépendances Java.

Analyse des failles

Réagir rapidement aux failles de vos dépendances vous aide à protéger votre chaîne d'approvisionnement logicielle.

L'analyse des failles vous permet d'évaluer automatiquement et de manière cohérente si vos dépendances introduisent des failles dans votre application. Les outils d'analyse des failles consomment les fichiers de verrouillage pour déterminer exactement les artefacts dont vous dépendez et vous avertissent en cas de nouvelles failles, parfois même avec les suggestions de chemins de mise à niveau.

Par exemple, Container Analysis identifie les failles du package OS dans les images de conteneurs. Il peut analyser les images importées dans Artifact Registry et les surveille en permanence afin de détecter de nouvelles failles pendant 30 jours maximum après le transfert de l'image.

Vous pouvez également utiliser l'analyse à la demande pour analyser les images de conteneurs en local afin de détecter les failles OS, Go et Java. Cela vous permet d'identifier les failles de manière anticipée afin de les corriger avant de les stocker dans Artifact Registry.

Étapes suivantes