Options de dépôts PyPI privés et leurs limites respectives

Les correctifs php2shell (CVE-2026-109618 et CVE-2026-109619) pour les versions de PHP en fin de vie sont désormais disponibles. Les réponses du service commercial étant plus lentes que d'habitude en raison d'une forte demande, le moyen le plus rapide d'obtenir les paquets corrigés est d'acheter ELS for Runtimes en ligne (s'ouvre dans un nouvel onglet). Consulter la FAQ sur les correctifs

Accédez directement au résumé généré par l'IA de cet article de blog

  • Résumez cet article avec Perplexity
  • Résume cet article avec Gemini

Principaux enseignements

  • Un dépôt PyPI privé permet de savoir d'où proviennent les paquets, mais ne garantit pas qu'ils puissent être installés en toute sécurité.
  • L’ajout de –extra-index-url au lieu de pointer –index-url vers un seul index rouvre la faille que le dépôt privé était censé combler.
  • Un miroir ou un cache diffuse tout ce qui est publié en amont, y compris les versions malveillantes.
  • Pour associer un paquet installable à une source vérifiée, il faut effectuer une étape de vérification explicite, et non pas modifier la configuration.

Mettre en place un dépôt PyPI privé semble être une opération assez simple. Il suffit de lancer DevPI ou Artifactory, d’indiquer l’URL interne dans la documentation d’intégration, puis de clore le ticket. Les développeurs ne se connectent plus directement au PyPI public. L’auditeur obtient une réponse. Le cauchemar est terminé.

Sauf que le référentiel privé ne fait que reproduire le PyPI public. La question initiale a désormais une réponse : la mise en cache fonctionne, il existe un point de contrôle au niveau de la politique. Mais la question de savoir si un paquet donné est fiable n'a pas été abordée. Elle a simplement été déplacée.

C'est cet aspect qu'il convient d'approfondir avant de choisir une architecture. Les quatre approches courantes pour un dépôt PyPI privé diffèrent considérablement quant aux éléments qu'elles vérifient, et la vérification est absente des modèles de base que sont le miroir et le proxy.

Ce qu'un dépôt PyPI privé permet réellement de résoudre

Quatre problèmes, et ils sont bien réels.

Disponibilité, afin qu’une panne de PyPI n’entraîne pas l’interruption de vos déploiements. Bande passante et vitesse, car récupérer les mêmes « wheels » mille fois par jour sur Internet est un gaspillage. Distribution interne des paquets, afin que les bibliothèques privées aient un emplacement où résider autre qu’une URL Git enfouie dans le fichier requirements.txt. Et un point de contrôle des politiques, ce qui est en réalité l'élément essentiel pour la sécurité.

Ce que cela ne résout pas en soi, c’est la question de l’intégrité des paquets. Un cache « pull-through » récupère les données en amont, stocke le résultat et le fournit. Si la source en amont fournissait un logiciel malveillant pendant trois heures, le cache conserverait fidèlement ce logiciel malveillant et continuerait à le diffuser à tout le monde par la suite, avec une excellente latence.

Un dépôt PyPI privé modifie la provenance de vos paquets. Il ne modifie en rien leur nature. Considérer le dépôt lui-même comme un contrôle de sécurité est une erreur architecturale courante dans ce domaine.

Le nombre de paquets malveillants déposés dans les registres publics n'a cessé d'augmenter d'année en année, et un miroir situé en aval de cette croissance en hérite intégralement, de par sa conception même. Le mécanisme de mise en miroir ne comporte aucun filtre permettant de distinguer les intentions.

L'erreur « extra-index-url » qui réduit tous vos efforts à néant

pip dispose de deux options qui semblent interchangeables. Elles ne le sont pas, et la distinction est facile à manquer – jusqu'au jour où quelqu'un en tire parti.

# Remplace l'index par défaut. Seul votre dépôt est consulté.
pip install –index-url https://pypi.internal.example.com/simple/ mypackage

# Ajoute un deuxième index. pip effectue une recherche dans les deux, sans priorité entre eux.
pip install –extra-index-url https://pypi.internal.example.com/simple/ mypackage

–extra-index-url apparaît généralement parce que l'option –index-url seule a d'abord provoqué un problème. Un paquet n'a pas été trouvé, la compilation a échoué, et l'ajout d'un deuxième index a permis de résoudre l'erreur.

Voici pourquoi c'est important. pip ne tient pas compte de l'index d'où un paquet est censé provenir. Sa propre documentation est très claire à ce sujet : il n'y a pas d'ordre de priorité entre les emplacements qu'il explore ; ils sont donc tous vérifiés et c'est la meilleure correspondance avec la dépendance qui l'emporte, ce qui, dans la pratique, correspond à la version compatible la plus récente. Si un attaquant publie la version 99.0.0 de `internal-billing-utils` sur le PyPI public, pip la privilégiera sans hésiter par rapport à votre version interne 2.4.1.

C'est une confusion de dépendances, et c'est par le biais de l'option –extra-index-url qu'elle s'introduit.

Vérifiez la configuration réelle de vos agents de compilation, et non celle indiquée dans la documentation. Les variables d’environnement PIP_INDEX_URL et PIP_EXTRA_INDEX_URL remplacent silencieusement le fichier pip.conf, et une image de base héritée d’une autre équipe est un moyen courant de les introduire sans que cela soit remarqué.

python -m pip config debug
pip config get global.index-url

La commande `pip config debug` indique de quel fichier ou de quelle variable provient chaque paramètre, ce qui est généralement plus rapide que de deviner. Profitez-en pour vérifier l'environnement des deux variables PIP tant que vous y êtes.

La solution consiste à utiliser exclusivement l'option –index-url et à faire en sorte que votre dépôt privé soit le seul index connu de pip, les paquets internes et en amont étant tous deux fournis par ce biais. La PEP 708 proposait des métadonnées de dépôt permettant aux index de signaler ces relations et d’éliminer toute incertitude lors de leur fusion, mais après trois ans en statut provisoire, cette proposition a été rejetée en 2026 car les implémentations requises n’ont jamais vu le jour. C’est donc la règle de l’index unique qui prévaut aujourd’hui.

Quatre façons de gérer un dépôt PyPI privé

Les options se distinguent par la manière dont elles traitent les paquets en amont, et non par le nom du produit figurant sur l'emballage.

Approche Manutention en amont Vérifie les artefacts Charge opérationnelle
Miroir en pied Copie l'intégralité de PyPI en local Non Élevé, le stockage ne cesse de croître
Proxy « pull-through » Récupération et mise en cache à la demande Non Faible à modéré
Liste blanche sélectionnée Seuls les paquets approuvés sont résolus Uniquement ce qui a été vérifié par un humain Évaluation approfondie et continue
Registre géré et certifié (par exemple, SecureChain) Vérification et remise en état avant le service Oui Faible, externalisé

Mise en miroir complète avec Bandersnatch est la solution traditionnelle et, de loin, celle qui nécessite le plus d'espace de stockage. Au moment où nous écrivons ces lignes, l'ensemble de PyPI héberge environ 44 To de fichiers de publication, selon page de statistiques de PyPI, et ce chiffre ne cesse d’augmenter. Le stockage est la partie la plus simple : c’est le maintien d’une synchronisation fiable sur un volume de données aussi important qui représente le véritable coût.

Les proxys de type « pull-through » constituent le choix le plus courant. devpi, proxpi, Nexus Repository, Artifactory, AWS CodeArtifact, Azure Artifacts, Google Artifact Registry : des produits différents, mais une architecture sous-jacente identique. La fonction de proxy et de mise en cache résout efficacement les problèmes de disponibilité et de mise en cache, mais elle ne permet en rien de garantir la fiabilité d’un artefact en amont, car cela n’a jamais été sa mission.

Les listes d'autorisation préétablies constituent l'un des contrôles les plus efficaces qu'une équipe puisse mettre en place en interne sans avoir à développer un pipeline de vérification complet. C'est aussi celui qui échoue discrètement, car la file d'attente des révisions devient la tâche que tout le monde redoute le plus et les validations finissent par être effectuées par lots afin de débloquer une mise en production.

Les registres gérés et vérifiés sont conçus autour de la vérification plutôt que de la disponibilité. SecureChain pour Python fonctionne de cette manière. Les paquets sont recompilés à partir du code source et contrôlés avant même d’être disponibles à l’installation ; ils ne sont pas mis en cache a posteriori pour être analysés plus tard.

Avant de choisir une approche, exécutez la commande `pip download -r requirements.txt` et comptez le nombre de paquets distincts renvoyés, y compris les paquets transitifs. Évaluer la taille d’une liste blanche sélectionnée par rapport à vos dépendance directe peut considérablement sous-estimer la charge de révision, car c’est dans l’arborescence transitive que réside l’essentiel du volume.

La duplication n'est pas une vérification

Une configuration de packaging Python permet de répondre à trois questions distinctes, et il est important de les distinguer car les produits brouillent souvent la frontière entre elles.

Cet artefact est-il arrivé intact ? Les hachages permettent de répondre à cette question, et pip prend bien en charge cette fonctionnalité.

Cet objet provient-il réellement de l'endroit qu'il est censé provenir ? La provenance et la signature apportent une réponse partielle à cette question, lorsque les éditeurs s'en chargent.

Cet artefact correspond-il au code source à partir duquel il est censé avoir été généré ? Presque aucun élément de la chaîne d'outils par défaut ne permet de répondre à cette question.

La troisième question permet de détecter les roues trafiquées. Une wheel est un produit de la compilation, et rien dans le système de paquets n’exige qu’elle corresponde au dépôt auquel le paquet fait référence. Une prise de contrôle du compte d’un responsable de paquet peut donner lieu à un « wheel » dont le hachage reste constant, qui s’installe sans problème et qui contient du code que le dépôt n’a jamais vu.

pip-compile –generate-hashes requirements.in
pip install –require-hashes -r requirements.txt

Activez le mode de vérification par hachage, quelles que soient les autres actions que vous effectuez. Cela oblige toutes les dépendances, y compris les dépendances transitives, à être verrouillées à l’aide d’un hachage, ce qui empêche les substitutions silencieuses et rend les installations reproductibles. Cela ne garantit toutefois en rien que l’artefact verrouillé ait jamais été légitime. Ce mode conserve simplement ce qui a été résolu lors de la première tentative.

Répondre à la troisième question revient à établir un lien fiable entre le code source et l’artefact installable, ce qui, dans la pratique, implique de recompiler à partir d’un code source vérifié dans un environnement contrôlé, puis d’installer cette version plutôt qu’un binaire en amont dont l’origine est incertaine. Il s’agit là d’un travail d’ingénierie délibéré, et non d’un simple paramètre de configuration.

« Trusted Publishing » et ce que « durabletask » a révélé

Publication sécurisée remplace les jetons API PyPI à longue durée de vie par des identifiants à courte durée de vie émis via OIDC pour un workflow d’intégration continue (CI) spécifique. Le jeton qu’il génère expire au bout de 15 minutes ; ainsi, aucun identifiant à longue durée de vie ne reste stocké dans un magasin de secrets, exposé au risque de vol.

Le SDK « durabletask » de Microsoft n'était pas activé lorsque la campagne TeamPCP a diffusé trois versions malveillantes sur PyPI le 19 mai 2026. Les versions 1.4.1 à 1.4.3 ont été publiées en l’espace de 35 minutes, directement sur PyPI à l’aide d’un jeton API à longue durée de vie volé qui se trouvait dans les secrets GitHub Actions du projet. Aucune balise correspondante, aucun workflow de publication exécuté, rien dans l’historique du dépôt permettant d’expliquer comment ces versions sont arrivées là. C’est précisément ce type de vol de jeton que Trusted Publishing a pour mission d’empêcher.

Telnyx et LiteLLM avaient déjà appris cette leçon environ huit semaines plus tôt, et ce à leurs dépens. Les deux avaient vu des versions malveillantes publiées sur PyPI en mars 2026 sans balises correspondantes dans leurs dépôts, et les deux sont ensuite passées à Trusted Publishing, comme le documente le rapport d’incident de PyPI. durabletask ne l’avait toujours pas adopté lorsque TeamPCP est revenu à la charge en mai. Au moment de la rédaction de cet article, PyPI indiquait toujours, pour la version la plus récente (1.9.0, datée du 30 juillet 2026), que ces fichiers avaient été publiés sans le système « Trusted Publishing ».

C'est cet écart qui constitue l'élément le plus instructif de cette histoire, bien plus que n'importe quel incident pris isolément. La solution existe depuis des années. Deux violations très médiatisées ont poussé deux projets à l'adopter. Quelques semaines plus tard, cette même campagne a compromis un troisième projet grâce à un autre identifiant de publication volé.

Trusted Publishing est véritablement efficace contre le vol d'identifiants, mais il présente deux limites qu'il convient de souligner clairement. Il protège les paquets que vous publiez, et non ceux que vous utilisez ; son activation n'a donc aucun effet sur les dépendances déjà présentes dans votre arborescence. De plus, son efficacité dépend du fait que tous les responsables en amont de votre chaîne de maintenance fassent le même choix, ce sur quoi vous ne pouvez pas compter.

Contrôle Protège Ne protège pas
Édition de confiance Les paquets que vous publiez Tout ce que vous installez
Fixation par hachage Contre la substitution après la première résolution Face à une première résolution compromise
Dépôt privé Source, disponibilité et politique relatives aux colis contrôlés Intégrité des artefacts
Dépistage au niveau du registre Les artefacts avant leur résolution Du code que vous avez écrit vous-même

Si votre organisation publie des paquets, activez la fonctionnalité « Trusted Publishing » cette semaine. Il s'agit d'une modification de configuration mineure qui permet de colmater une faille de sécurité importante.

Renforcement de la sécurité côté client

C'est l'architecture du référentiel qui retient l'attention. Or, c'est au niveau de la configuration du client que s'effectue réellement l'application des règles, et celle-ci manque généralement de cohérence.

Il convient de vérifier quatre éléments dans chaque environnement où pip est exécuté. Premièrement, la présence d’une seule URL d’index dans le fichier pip.conf au niveau du système, sans aucune URL d’index supplémentaire nulle part. Deuxièmement, que les variables PIP_INDEX_URL et PIP_EXTRA_INDEX_URL ne soient pas définies dans les images de base et la configuration CI. Troisièmement, que le mode de vérification des hachages soit activé dans l’environnement CI, même si les développeurs ne l’utilisent pas localement. Quatrièmement, le trafic sortant des agents de build doit être restreint afin qu'un client mal configuré ne puisse en aucun cas accéder au PyPI public.

C'est ce dernier élément qui transforme la politique en mesure d'application effective. Les configurations dérivent, les images de base sont héritées, et il y a toujours quelqu’un pour activer un indicateur afin de débloquer un déploiement. Une politique de sortie qui autorise les agents de build à accéder uniquement au dépôt privé approuvé permet de contrer tout cela sans dépendre de la discipline de quiconque. Bloquer un seul nom d’hôte ne suffit pas, car l’index et le fichier qu’il pointe sont distincts.

Choisir une approche

Adaptez l'approche au problème à résoudre, et non à ce qui est le plus rapide à mettre en place.

Un proxy « pull-through » est le choix idéal lorsque l'objectif est la disponibilité et la mise en cache. C'est une bonne infrastructure, mais elle cesse d'être utile dès lors qu'elle est considérée comme une barrière de sécurité. Une liste blanche soigneusement établie ajoute un point de contrôle de la politique qu'un audit peut mettre en évidence, à condition que quelqu'un veille à ce que la file d'attente de révision ne se transforme pas en simple formalité. La mise en miroir complète justifie rarement son coût de stockage en dehors des environnements isolés physiquement. Aucune de ces trois solutions ne garantit intrinsèquement l’intégrité des artefacts, et une liste blanche soigneusement gérée n’offre qu’une assurance à la hauteur de ce que son processus de révision permet réellement d’établir.

Si l’intégrité des artefacts fait véritablement partie du périmètre, et pas seulement la disponibilité ou la piste d’audit, ce dont vous avez besoin, c’est d’une couche de vérification qui reconstitue les paquets à partir d’une source fiable et les contrôle avant leur résolution. Un registre géré et vérifié offre cette garantie sans que vous ayez à mettre en place et à exploiter le pipeline, ce qui, en interne, représente un engagement technique s’étalant sur plusieurs trimestres plutôt qu’un simple sprint.

Le rôle de SecureChain pour Python

Revenons aux trois questions posées précédemment : « intact », « provenant de la source indiquée », et « correspond à sa source ». La plupart des configurations de dépôts privés s'arrêtent à la première. SecureChain est conçu pour répondre à ces trois questions. Chaque paquet est recompilé à partir du code source dans des environnements sécurisés et soumis à un filtrage avant même d’être disponible à l’installation, accompagné de données de provenance SLSA de niveau 3, d’une SBOM et de données VEX, ainsi que d’un processus de correction des failles qui se poursuit même après le départ du responsable de maintenance.

Si vous souhaitez comparer cela à votre propre arborescence de dépendances, demandez à nos experts à propos de SecureChain pour Python et de l'approche la mieux adaptée à votre pile technologique.

FAQ

Qu'est-ce qu'un dépôt PyPI privé ?

Un index de paquets Python hébergé en interne qui met les paquets à la disposition de vos développeurs et de vos systèmes de compilation, au lieu de les rediriger directement vers le PyPI public. Il peut servir de miroir au dépôt en amont, de proxy et de cache à la demande, ne proposer qu’un ensemble de paquets approuvés ou filtrer les paquets avant de les mettre à disposition.

Un dépôt PyPI privé rend-il les installations plus sûres ?

Uniquement s'il vérifie les paquets. Un miroir ou un cache « pull-through » diffuse tout ce que l'amont a publié, y compris les versions malveillantes. L'avantage en matière de sécurité provient des mécanismes de filtrage ou de modération mis en place en amont, et non du dépôt lui-même.

Quelle est la différence entre « index-url » et « extra-index-url » ?

–index-url remplace l'index par défaut, de sorte que seul votre référentiel est consulté. –extra-index-url ajoute un autre index, et pip effectue une recherche dans tous les index configurés sans les classer par ordre de priorité ; c'est ainsi qu'un paquet public malveillant peut s'imposer lors de la résolution et vous exposer à une attaque par confusion de dépendances.

Comment éviter les problèmes de dépendances avec pip ?

Utilisez exclusivement –index-url, diffusez les paquets internes et en amont via cet index unique, désactivez PIP_EXTRA_INDEX_URL partout, et limitez les sorties des agents de compilation afin que seul le référentiel approuvé soit accessible.

Dois-je mettre en place un miroir complet de PyPI ?

Rarement. Une mise en miroir complète implique de stocker environ 44 To, un volume qui ne cesse d'augmenter, et n'apporte aucun avantage en termes de vérification par rapport à un proxy « pull-through ». La mise en miroir complète est particulièrement indiquée pour les environnements isolés physiquement.

Qu'est-ce que la publication certifiée sur PyPI ?

Un mécanisme de publication basé sur l'OIDC qui délivre des identifiants à durée de vie limitée à un flux de travail CI spécifique, plutôt que de s'appuyer sur des jetons API à durée de vie prolongée. Il protège les paquets que vous publiez. Il n'intervient pas sur les paquets que vous installez.

 

Résumé
Options de dépôts PyPI privés et leurs limites respectives
Nom de l'article
Options de dépôts PyPI privés et leurs limites respectives
Description
Un référentiel PyPI privé permet de contrôler la provenance des paquets, mais pas leur sécurité. Comparez les miroirs, les proxys et les registres modérés.
Auteur
Nom de l'éditeur
de TuxCare
Logo de l'éditeur

Rejoignez plus de 4 500 professionnels de Linux et de l'Open Source!

2 fois par mois. Pas de spam.

Table des matières
Obtenez les réponses à vos questions sur la sécurité des logiciels libres

Rejoignez plus de 4 500 professionnels de Linux et de l'Open Source!

2 fois par mois. Pas de spam.