
PyPI sans jeton permanent : OIDC réduit le secret, pas le risque du workflow

Pour publier sur PyPI depuis GitHub Actions sans conserver de jeton API permanent, enregistrez le dépôt et son workflow comme Trusted Publisher, puis accordez id-token: write au seul job de publication. La procédure de publication de PyPI permet alors à l’action de PyPA d’utiliser l’identité OIDC du job, sans identifiant, mot de passe ni jeton enregistré dans les secrets GitHub.
Cette configuration supprime le secret durable du dépôt, mais laisse au workflow autorisé la capacité de publier. Il faut donc contrôler qui peut modifier ce fichier, déclencher une release et approuver le job associé à l’environnement. La procédure qui suit concerne un projet PyPI existant et une publication lancée lorsqu’une release GitHub est publiée.
Remplacer le jeton en quatre étapes
Inventorier la publication actuelle. Repérez le fichier dans .github/workflows/, le job qui envoie les distributions et chaque référence au secret PyPI. Vérifiez si d’autres workflows ou services utilisent encore le même jeton : sa révocation doit attendre que leurs besoins soient traités. Relevez aussi les personnes qui peuvent modifier le workflow, créer une release ou changer les règles du dépôt.
Enregistrer le publisher dans PyPI. Sur le projet existant, ouvrez Manage puis Publishing et ajoutez un publisher GitHub Actions. La configuration du Trusted Publisher demande le propriétaire, le dépôt et le nom exact du fichier de workflow autorisé ; le nom d’un environnement GitHub est facultatif, mais fortement recommandé. Si vous choisissez pypi, inscrivez ce même nom dans la configuration PyPI et dans le job GitHub Actions. Pour un fichier .github/workflows/release.yml, le nom à renseigner est release.yml.
Modifier GitHub Actions. Placez environment: pypi et permissions: {id-token: write} sur le job de publication. Faites-lui récupérer des distributions construites dans un autre job, puis appelez pypa/gh-action-pypi-publish@release/v1 sans paramètres username ou password. Configurez des approbateurs requis pour l’environnement dans GitHub : écrire simplement environment: pypi dans le workflow ne crée pas une validation manuelle.
Vérifier la bascule, puis révoquer. Lors d’une release prévue, constatez que le job attend l’approbation configurée, qu’il publie dans le bon projet PyPI et que les fichiers attendus y apparaissent. Vérifiez ensuite qu’aucun autre chemin de publication ne dépend du jeton historique. Supprimez sa valeur des secrets GitHub et révoquez le jeton dans PyPI : effacer une copie stockée dans le dépôt ne désactive pas les autres copies éventuelles.
Un workflow minimal à deux jobs
Le squelette ci-dessous indique les valeurs à reporter dans release.yml. Les noms build, publish, dist et pypi sont des exemples ; le nom du fichier et celui de l’environnement doivent correspondre aux valeurs enregistrées dans PyPI. La séparation des jobs limite les étapes capables de demander une identité OIDC.
- Déclencheur : on: {release: {types: [published]}}. Ce choix réserve l’exécution à la publication d’une release GitHub, sous réserve des droits accordés pour créer cette release.
- Job build : runs-on: ubuntu-latest et permissions: {contents: read}. Il récupère le dépôt, prépare l’outil de construction, exécute python -m build, puis transmet dist/ avec actions/upload-artifact. Donnez à cet artefact le nom dist et faites échouer l’étape si aucun fichier n’a été produit.
- Job publish : needs: build, runs-on: ubuntu-latest, environment: pypi et permissions: {id-token: write}. Ses seules étapes récupèrent l’artefact dist avec actions/download-artifact dans dist/, puis appellent pypa/gh-action-pypi-publish@release/v1 sans secret PyPI.
Dans le fichier réel, indiquez des versions compatibles pour les actions qui transfèrent l’artefact entre les jobs et conservez le même nom d’artefact des deux côtés. Le job publish ne doit ni reconstruire le paquet ni exécuter un script du dépôt : ces opérations appartiennent au job build. Le jeton obtenu pendant la publication reste une donnée sensible, même s’il est de courte durée.
Protéger le workflow qui peut publier
Le modèle de sécurité de PyPI indique qu’un workflow autorisé compromis peut avoir des conséquences comparables à une compromission d’identifiants. Il précise aussi que les Trusted Publishers sont attachés aux projets : retirer un utilisateur d’un projet PyPI ne retire pas les publishers qu’il avait configurés. L’identité OIDC établit quel workflow demande l’accès ; elle ne garantit pas la sûreté du code ou des distributions qu’il transmet.
- Faites examiner les changements de release.yml et des scripts exécutés pendant la construction. Limitez les personnes capables de modifier directement la branche qui porte le workflow ; une modification de ses déclencheurs ou de ses étapes peut ouvrir une nouvelle voie de publication.
- Réservez l’environnement pypi au job publish et activez ses approbateurs requis lorsque cette protection est disponible pour votre dépôt. Tenez leur liste à jour et activez la prévention de l’auto-approbation si votre configuration GitHub le permet. Vérifiez effectivement qu’une release reste en attente avant l’envoi à PyPI.
- Gardez id-token: write au niveau du seul job publish. Le job build lit le dépôt et produit des fichiers, mais n’a aucune raison de demander un jeton OIDC destiné à la publication. Évitez aussi d’ajouter au job publish des étapes ou dépendances qui n’interviennent pas dans la récupération et l’envoi des distributions.
- Contrôlez qui peut créer ou modifier les tags de version et publier une release. Une approbation de l’environnement ajoute un contrôle avant l’envoi, mais elle ne remplace pas l’examen du contenu choisi pour la release.
- Lors du départ d’un mainteneur, revoyez ses accès au dépôt, ses droits sur les releases, la liste des approbateurs et tous les Trusted Publishers du projet PyPI. Cet audit porte sur les chemins encore capables de publier, y compris ceux qui n’utilisent plus l’ancien jeton.
Une migration est achevée lorsque la publication attend les contrôles prévus, aboutit sans secret permanent et que l’ancien jeton a été révoqué. Par la suite, tout changement du workflow, de ses déclencheurs ou des droits des mainteneurs mérite le même examen qu’une modification de l’accès à PyPI.
À lire aussi :
Articles similaires


npm ajoute un jeton qui prépare la publication sans pouvoir la déclencher

npm accepte dix éditeurs OIDC, avec validation humaine après le scan

Dependabot lit GitHub Packages privés sans jeton personnel

GitHub Actions bloquera pull_request_target par défaut le 2 novembre

GitHub exige une présence humaine, mais seulement pour certains comptes
Abonnez-vous à notre newsletter
Recevez directement les dernières actualités sur le Web3, l’IA et les cryptomonnaies.