Gestion des dépendances

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, ainsi que les étapes à suivre pour réduire votre empreinte des dépendances et la compatibilité des versions reproductibles.

Les dépendances d'application sont des technologies requises pour créer ou exécuter une application. Les systèmes d'exploitation, les bibliothèques logicielles, les plug-ins, les bases de données ou les plates-formes constituent des exemples de dépendances logicielles.

Les dépendances peuvent inclure des composants que vous créez et des logiciels tiers. L'approche que vous choisissez pour gérer les dépendances peut affecter la sécurité et la fiabilité de vos applications.

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

Méthodes d'inclusion des dépendances

Il existe plusieurs méthodes courantes pour inclure des dépendances dans 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, étant donné que vous ne contrôlez pas ces dépendances externes, votre chaîne d'approvisionnement logicielle est plus sujette aux attaques de chaîne d'approvisionnement 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 contrôlez davantage les dépendances fournisseurs que vous utilisez, mais présentent certains inconvénients :
  • Les dépendances fournisseurs augmentent la taille de votre dépôt source et entraînent une perte d'utilisateurs plus importante.
  • Vous devez fournir les mêmes dépendances dans chaque application distincte. Si votre dépôt source ou processus de compilation n'accepte pas les modules sources réutilisables, vous devrez peut-être conserver plusieurs copies de vos dépendances.
  • La mise à niveau des dépendances fournisseurs peut s'avérer plus difficile.
Stocker les dépendances dans un registre privé
Artifact Registry facilite l'installation à partir d'un dépôt public et permet de contrôler vos dépendances.
  • Vous pouvez configurer vos clients Docker et de package de langage pour interagir avec les dépôts privés dans Artifact Registry de la même manière qu'avec les dépôts publics.
  • Vous contrôlez les dépendances de vos dépôts privés et pouvez restreindre l'accès à chaque dépôt.
  • Vos dépendances sont centralisées pour toutes vos applications.
  • Vos dépôts sont étroitement intégrés à des environnements d'exécution Cloud Build et Google Cloud tels que Google Kubernetes Engine et Cloud Run.
  • Vous pouvez tirer parti des workflows de gestion des métadonnées, d'analyse des failles et d'approbation des déploiements grâce à Container Analysis et à l'autorisation binaire.

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

Épinglage

Le blocage de version consiste à limiter une dépendance à une version ou une plage de versions spécifique. Dans l'idéal, vous devez épingler une seule version d'une dépendance.

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

Vous pouvez limiter ce problème à l'aide d'outils automatisés de gestion des dépendances qui surveillent les dépendances de vos dépôts sources pour les nouvelles versions. Ces outils modifient vos fichiers d'exigences pour mettre à jour les dépendances si nécessaire, souvent avec des informations de journal des modifications ou des détails supplémentaires.

Le blocage de la version s'applique uniquement aux dépendances directes, et non aux dépendances transitives. Par exemple, si vous épinglez la version du package my-library, l'épinglage limite la version de my-library, mais pas les versions du logiciel dont my-library a une dépendance. Vous pouvez restreindre l'arborescence de dépendances pour un package dans certaines langues à l'aide d'un fichier de verrouillage.

Validation de la signature et du hachage

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

Validation de 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 à la valeur de hachage calculée par le fournisseur de l'artefact pour confirmer l'intégrité du fichier. La validation du hachage vous aide à identifier le remplacement, la falsification ou la corruption des dépendances, par le biais d'une attaque MITM ("man in the middle") ou du piratage du dépôt d'artefacts.

L'utilisation de la validation de hachage nécessite que le hachage reçu du dépôt d'artefacts au moment de la validation (ou au moment de la première récupération) soit compromis.

Validation des signatures

La validation de signatures renforce la procédure de validation. Le dépôt d'artefacts, les responsables du logiciel ou les deux peuvent signer des artefacts. Des services tels que sigstore permettent aux responsables de signer des artefacts logiciels et aux clients de vérifier ces signatures.

Verrouiller des fichiers et des dépendances compilées

Les fichiers de verrouillage sont des fichiers d'exigences entièrement résolus, qui spécifient exactement la version de chaque dépendance à installer pour une application. Habituellement produit automatiquement par des outils d'installation, les fichiers de verrouillage combinent le blocage de la version et la signature ou la vérification de hachage avec une arborescence de dépendances complète pour votre application.

Les outils d'installation créent des arborescences de dépendances en résolvant toutes les dépendances transitives en aval de vos dépendances de niveau supérieur, puis incluez 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 compilations plus reproductibles et cohérentes.

Combiner des dépendances privées et publiques

Les applications cloud natives modernes dépendent souvent à la fois de 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.

Cependant, lorsque vous combinez des dépendances privées et publiques, votre chaîne d'approvisionnement logicielle est plus vulnérable aux attaques par conflit 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 plutôt que votre dépendance interne.

Pour éviter une attaque de confusion de dépendance, vous pouvez prendre un certain nombre d'étapes:

  • Valider 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 en miroir explicitement les dépendances tierces dont vous avez besoin dans votre dépôt privé, manuellement ou à l'aide d'un proxy de récupération.
  • Pour le développement basé sur des conteneurs, utilisez des sources de confiance pour vos images de base. Google fournit des images de base gérées que vous pouvez utiliser directement et un pipeline d'images sécurisé pour générer vos propres images de base.

Supprimer les dépendances inutilisées

Selon l'évolution de vos besoins et de l'application, vous pouvez modifier ou cesser d'utiliser certaines de vos dépendances. Le fait d'installer les dépendances inutilisées avec votre application augmente l'empreinte de vos dépendances et augmente le risque que vous soyez compromis par une faille dans ces dépendances.

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

Soyez prudent lorsque vous ajoutez des dépendances à votre application. Chacun d'entre eux peut introduire davantage de code que vous ne contrôlez pas entièrement. Dans le cadre de votre pipeline de linting et de test standard, intégrez des outils qui auditent vos fichiers de exigences pour déterminer si vous utilisez ou importez réellement vos dépendances.

Analyse des failles

Le fait de 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 des fichiers de verrouillage pour déterminer exactement les artefacts dont vous avez besoin et vous avertir lorsque de nouvelles failles apparaissent, même avec des suggestions de processus de mise à niveau.

Des outils tels que Container Analysis peuvent fournir un large éventail d'analyses des failles pour les images de conteneurs, ainsi que des artefacts de langage tels que l'analyse de packages Java. Lorsqu'elle est activée, cette fonctionnalité identifie les failles de package de vos images de conteneurs. Les images sont analysées lors de leur importation dans Artifact Registry et les données sont surveillées en permanence pour détecter de nouvelles failles pendant un maximum de 30 jours après le transfert de l'image.

Vous pouvez également utiliser l'analyse à la demande pour analyser les images de conteneurs en local. Cela vous permet d'identifier les failles rapidement afin de les corriger avant de les stocker dans Artifact Registry.