Ce document décrit les dépendances des applications et les bonnes pratiques pour les gérer, y compris la surveillance des failles, la vérification des artefacts, la réduction de l'empreinte de vos dépendances et la prise en charge des builds reproductibles.
Une dépendance logicielle est un élément 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 lorsque vous compilez, créez, exécutez, téléchargez ou installez votre logiciel.
Les dépendances peuvent inclure des composants que vous créez, des logiciels propriétaires tiers 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 l'implémentation des bonnes pratiques peuvent varier en fonction du format des artefacts et des outils que vous utilisez, mais les principes généraux restent applicables.
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 dont les dépendances directes d'une application ont besoin pour fonctionner. Chaque dépendance peut avoir ses propres dépendances directes et indirectes, ce qui crée un arbre récursif de dépendances transitives qui ont toutes un impact sur l'application.
Différents langages de programmation offrent différents niveaux de visibilité sur les dépendances et leurs relations. De plus, 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 des dépendances permettant de créer un module, ainsi que les versions des dépendances qu'un gestionnaire de packages télécharge pour une installation spécifique du module. Dans d'autres écosystèmes linguistiques comme Java, la prise en charge de l'introspection des dépendances est plus limitée. De plus, 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 les dépendances directes pour les modules npm dans le fichier package.json
. Dans le fichier package.json pour glob, la section dependencies
liste les dépendances directes du package publié.
La section devDepdencies
liste les dépendances pour le développement et les tests locaux par les responsables et les contributeurs de glob
.
Sur le site Web npm, la page glob liste 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 de
glob
sur le site Open Source Insights. La liste des dépendances pour glob inclut les dépendances directes et indirectes (transitives).Une dépendance transitive peut se trouver à plusieurs niveaux de profondeur dans l'arborescence des dépendances. Exemple :
glob
8.0.2 a une dépendance directe surminimatch
5.0.1.minimatch
5.0.1 a une dépendance directe surbrace-expression
2.0.1.brace-expression
2.0.1 a une dépendance directe surbalanced-match
1.0.2.
Sans visibilité sur les dépendances indirectes, il est très difficile d'identifier les failles et autres problèmes provenant d'un composant auquel votre code ne fait pas directement référence, et d'y répondre.
Lorsque vous installez le package glob
, npm résout l'intégralité de l'arborescence des dépendances et enregistre la liste des versions spécifiques téléchargées dans le fichier package.lock.json afin que vous disposiez d'un enregistrement de toutes les dépendances. Les installations ultérieures dans le même environnement récupéreront les mêmes versions.
Outils pour obtenir des insights sur les dépendances
Vous pouvez utiliser les outils suivants pour comprendre vos dépendances Open Source et évaluer la stratégie de sécurité de vos projets. Ces outils fournissent des informations sur les différents formats de package.
- Insights sur la sécurité dans la console Google Cloud
- Google Cloud fournit des informations sur la sécurité de vos artefacts dans Cloud Build, Cloud Run et GKE, y compris les failles, les informations sur les dépendances, la nomenclature logicielle (SBOM) et la provenance des compilations. D'autres services Google Cloud proposent également des fonctionnalités qui améliorent votre stratégie de sécurité tout au long du cycle de développement logiciel. Pour en savoir plus, consultez la présentation de la sécurité de la chaîne d'approvisionnement logicielle.
- Outils Open Source
Plusieurs outils Open Source sont disponibles, y compris :
Open Source Insights : site Web qui fournit 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 sous la forme d'un ensemble de donnéesGoogle Cloud . Vous pouvez utiliser BigQuery pour explorer et analyser les données.
Base de données des failles Open Source : base de données de failles consultable qui regroupe les failles d'autres bases de données en un seul endroit.
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 à chaque vérification un score compris entre 0 et 10. Vous pouvez ensuite utiliser les scores pour évaluer la posture de sécurité de votre projet.
Allstar : application GitHub qui surveille en continu les organisations ou les dépôts GitHub pour vérifier qu'ils respectent les règles configurées. Par exemple, vous pouvez appliquer une règle à votre organisation GitHub qui recherche les collaborateurs externes à l'organisation disposant d'un accès administrateur ou push.
Approches pour inclure les dépendances
Il existe plusieurs méthodes courantes pour inclure des dépendances avec votre application :
- Installer directement à partir de sources publiques
- Installez les 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 sujette aux attaques de la chaîne d'approvisionnement Open Source.
- Stocker des copies des dépendances dans votre dépôt source
- Cette approche est également appelée fournisseur. Au lieu d'installer une dépendance externe à partir d'un dépôt public lors de 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 fournies que vous utilisez, mais il existe plusieurs inconvénients :
- Les dépendances fournies par le fournisseur augmentent la taille de votre dépôt de code source et introduisent davantage de changements.
- Vous devez fournir les mêmes dépendances dans chaque application distincte. Si votre dépôt source ou votre processus de compilation ne sont pas compatibles avec les modules sources réutilisables, vous devrez peut-être gérer plusieurs copies de vos dépendances.
- La mise à niveau des dépendances fournies par le fournisseur peut être plus difficile.
- Stocker les dépendances dans un registre privé
Un registre privé, tel qu'Artifact Registry, offre la facilité d'installation à partir d'un dépôt public ainsi que le contrôle de vos dépendances. Artifact Registry vous permet :
- Centralisez vos artefacts et dépendances de compilation pour toutes vos applications.
- Configurez vos clients de packages Docker et linguistiques pour qu'ils interagissent avec les dépôts privés d'Artifact Registry de la même manière qu'avec les dépôts publics.
Contrôlez davantage 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 provenant de sources publiques en amont et les analyser pour détecter les failles (preview privée).
- Utilisez des dépôts virtuels pour regrouper les dépôts distants et privés derrière un seul point de terminaison. Définissez une priorité pour chaque dépôt afin de contrôler l'ordre de recherche lors du téléchargement ou de l'installation d'un artefact (aperçu privé).
Utilisez Artifact Registry avec d'autres services Google Cloud , y compris 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 compilations, contrôlez les déploiements et consultez des insights sur votre niveau de sécurité.
Dans la mesure du possible, utilisez un registre privé pour vos dépendances. Dans les situations où vous ne pouvez pas utiliser de registre privé, envisagez de fournir vos dépendances afin de contrôler le contenu de votre chaîne d'approvisionnement logicielle.
Épinglage
L'épinglage de version consiste à limiter une dépendance d'application à une version ou une plage de versions spécifiques. Idéalement, vous épinglez une seule version d'une dépendance.
Épingler la version d'une dépendance permet de s'assurer que les compilations de votre application sont reproductibles. Toutefois, cela signifie également que vos builds n'incluent pas les mises à jour de la dépendance, y compris les correctifs de sécurité, les corrections de bugs ou les améliorations.
Vous pouvez atténuer ce problème à l'aide d'outils de gestion des dépendances automatisés qui surveillent 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, en incluant souvent des informations sur le journal des modifications ou des détails supplémentaires.
L'épinglage de version ne s'applique qu'aux dépendances directes, et non aux dépendances transitives. Par exemple, si vous épinglez la version my-library
du package, l'épingle limite la version de my-library
, mais pas les versions des logiciels dont my-library
dépend. Dans certaines langues, vous pouvez limiter l'arborescence des dépendances d'un package à l'aide d'un fichier de verrouillage.
Validation de la signature et du hachage
Il existe plusieurs méthodes permettant de vérifier l'authenticité d'un artefact que vous utilisez comme dépendance.
- Validation du hachage
Un hachage est une valeur générée pour un fichier, qui sert d'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 de l'homme du milieu ou d'une compromission du dépôt d'artefacts.
Pour utiliser la validation du hachage, vous devez être sûr que le hachage que vous recevez du dépôt d'artefacts n'a pas été compromis.
- Validation de la signature
La vérification de la signature ajoute un niveau de sécurité supplémentaire à la procédure de validation. Le dépôt d'artefacts, les responsables du logiciel ou les deux peuvent signer les artefacts.
Des services tels que sigstore permettent aux responsables de signer des artefacts logiciels et aux consommateurs de vérifier ces signatures.
L'autorisation binaire peut vérifier que les images de conteneurs déployées dans des environnements d'exécution Google Cloud sont signées avec des attestations pour différents critères.
Fichiers de verrouillage et 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. Généralement produits automatiquement par les outils d'installation, les fichiers de verrouillage combinent l'épinglage de version et la vérification de la signature ou du hachage avec un arbre de dépendances complet pour votre application.
Les outils d'installation créent des arborescences de dépendances en résolvant entièrement toutes les dépendances transitives en aval de vos dépendances de premier niveau, 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 compilations plus reproductibles et cohérentes.
Combiner des dépendances privées et publiques
Les applications cloud natives modernes dépendent souvent à la fois du code Open Source et tiers, ainsi que des bibliothèques internes à code source fermé. 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 confusion de dépendances. En publiant des projets portant le même nom que votre projet interne dans des dépôts Open Source, des pirates informatiques peuvent profiter de programmes d'installation mal configurés pour installer leur code malveillant à la place de votre dépendance interne.
Pour éviter une attaque par confusion de 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 en miroir explicitement les dépendances tierces dont vous avez besoin dans votre dépôt privé, manuellement ou avec un proxy pull-through. Les dépôts distants Artifact Registry sont des proxys pull-through pour les dépôts publics en amont.
- Utilisez des dépôts virtuels pour regrouper les dépôts Artifact Registry standards et distants derrière un seul point de terminaison. Vous pouvez configurer des priorités pour les 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 fiables pour les packages publics et les images de base.
- Utilisez Assured Open Source Software pour accéder aux images Java et Python populaires que Google a testées et vérifiées.
- Utilisez des images de base fournies par Google ou un pipeline d'images sécurisé pour générer vos propres images de base.
Supprimer les dépendances inutilisées
À mesure que vos besoins évoluent et que votre application se développe, vous pouvez modifier ou cesser d'utiliser certaines de vos dépendances. Si vous continuez à installer des dépendances inutilisées avec votre application, vous augmentez l'empreinte de vos dépendances et le risque d'être compromis par une faille de sécurité dans ces dépendances.
Une fois que votre application fonctionne en local, une pratique courante consiste à copier toutes les dépendances que vous avez installées pendant le 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 s'assurer que l'application déployée fonctionne, mais elle est également susceptible d'introduire des dépendances dont vous n'avez pas besoin en production.
Faites preuve de prudence lorsque vous ajoutez de nouvelles dépendances à votre application. Chacun d'eux peut potentiellement introduire du code sur lequel vous n'avez pas un contrôle total. Dans le cadre de votre pipeline de linting et de test régulier, intégrez des outils qui auditent vos fichiers d'exigences pour déterminer si vous utilisez ou importez réellement vos dépendances.
Certaines langues 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 des fichiers de verrouillage pour déterminer exactement les artefacts dont vous dépendez et vous avertir lorsque de nouvelles failles apparaissent, parfois même avec des suggestions de mise à niveau.
Par exemple, Artifact Analysis identifie les failles des packages OS dans les images de conteneurs. Il peut analyser les images lorsqu'elles sont importées dans Artifact Registry et les surveiller 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 localement les images de conteneurs et détecter les failles OS, Go et Java. Cela vous permet d'identifier les failles tôt afin de pouvoir les corriger avant de stocker les images dans Artifact Registry.
Étapes suivantes
- Découvrez les composants de la sécurité de la chaîne d'approvisionnement logicielle et comment les servicesGoogle Cloud vous aident à protéger vos logiciels.
- En savoir plus sur Artifact Registry
- Découvrez Artifact Analysis et les types d'analyse.