Aller au contenu

CICD-SEC-6 : hygiène des identifiants insuffisante

CICD-SEC-6 : hygiène des identifiants insuffisante

Section intitulée « CICD-SEC-6 : hygiène des identifiants insuffisante »

Sixième entrée du Top 10 OWASP CI/CD. Libellé officiel : Insufficient Credential Hygiene. Le risque ne tient pas à un mécanisme cassé mais à la variété des contextes où un secret peut se trouver dans une chaîne de livraison : identifiants de l’application à l’exécution, identifiants de production employés par les pipelines, identifiants manipulés par les développeurs dans leurs environnements de test, identifiants embarqués dans le code et les artefacts.

→ Lire l’explication complète de la marmotte

Le mécanisme : cinq endroits où les secrets finissent

Section intitulée « Le mécanisme : cinq endroits où les secrets finissent »

Le référentiel nomme cinq défauts, et leur liste est moins une typologie d’attaque qu’un inventaire de lieux.

Du code contenant des identifiants poussé sur une branche. Par mégarde, ou délibérément sans mesurer le risque. Dès cet instant, le secret est exposé à quiconque a un accès en lecture au dépôt, et surtout il subsiste dans l’historique des commits même retiré de la branche. Défaut le plus documenté du domaine : prévenir les secrets codés en dur dans Git et l’éditorial sur les secrets dans les dépôts. Son canal le plus récent n’existait pas en 2022 : la fuite de secrets dans les prompts.

Des identifiants employés de façon non sûre dans la construction et le déploiement. Le référentiel ne décrit pas un défaut : il pose quatre questions, le meilleur questionnaire d’audit du document. Dans quel contexte et par quelle méthode chaque jeu est-il employé ; chaque pipeline n’accède-t-il qu’à ce dont il a besoin ; du code non relu traversant le pipeline peut-il y accéder ; ces identifiants ne sont-ils disponibles qu’à l’exécution, depuis les seuls contextes requis. La troisième question est le point de jonction exact avec l’exécution de pipeline empoisonnée et les contrôles d’accès du pipeline.

Des identifiants dans les couches d’une image de conteneur. Un secret nécessaire à la seule construction reste présent dans l’une des couches, disponible à quiconque télécharge l’image. Le défaut survit aux bonnes intentions : effacer le fichier dans une couche ultérieure ne retire rien de la couche qui l’a introduit, ce que détaille la généalogie des images de base.

Des identifiants imprimés dans la sortie console, volontairement pour mettre au point ou par accident. Ils restent en clair dans les journaux de construction, visibles de quiconque accède aux résultats, et ces journaux partent ensuite vers les systèmes de gestion de journaux, ce qui élargit l’exposition à un public qui n’a rien demandé. Au sens du catalogue CWE, une exposition d’information sensible par un canal que personne ne tient pour une sortie.

Des identifiants jamais renouvelés. Les secrets étant répartis dans tout l’écosystème d’ingénierie, ils sont exposés à un grand nombre de salariés et de prestataires, et ne pas les renouveler fait croître continûment le nombre de détenteurs d’un identifiant valide. Le référentiel décrit avec exactitude la doctrine en vigueur pour les clés de déploiement : « si ce n’est pas cassé, n’y touche pas ».

Le référentiel est direct : les identifiants sont l’objet le plus recherché par les adversaires, pour atteindre des ressources de grande valeur ou déployer des artefacts malveillants. Le fort potentiel d’erreur humaine s’y combine avec une crainte très répandue, celle de casser un processus en renouvelant un secret ; c’est cette crainte, plus que l’ignorance, qui laisse les identifiants en place. La tactique ATT&CK d’accès aux identifiants en donne le versant adverse, dont la leçon s’applique mot pour mot : l’essentiel ne consiste pas à casser des secrets, mais à les ramasser là où ils traînent.

Les précédents cités couvrent les cinq lieux. Codecov, où des milliers d’identifiants stockés en variables d’environnement ont été volés. Travis CI, qui injectait les variables sécurisées de dépôts publics dans les constructions de demandes de fusion, les exposant à des inconnus. Le serveur TeamCity de Stack Overflow, dont le stockage des secrets a permis leur vol. Samsung, qui a exposé dans des dépôts GitLab publics des secrets aux permissions excessives. Uber, dont les dépôts privés contenaient des jetons cloud permissifs et partagés, d’où l’exfiltration de données de millions de conducteurs et de passagers. Et Homebrew, dont l’instance Jenkins révélait les variables d’environnement des constructions, dont un jeton permettant de modifier le projet.

Les secrets dans le code, à trois moments que le référentiel recommande tous : un greffon d’éditeur qui repère les secrets dans les modifications locales, une analyse automatique à chaque envoi, des analyses périodiques du dépôt et de son historique. Ils ne détectent pas la même chose : le greffon évite la faute, l’analyse à l’envoi évite la publication, celle de l’historique mesure la dette déjà contractée. Le même inventaire vaut pour les sorties de construction et les artefacts déjà publiés, couches d’images, binaires, chartes : travail fini, qu’on fait une fois.

L’usage d’un identifiant hors de ses conditions. Quand un secret est conditionné à une adresse source ou à une identité, toute tentative ailleurs est un signal sans ambiguïté, et le seul de la liste qui détecte une compromission plutôt qu’une exposition.

Cartographier les identifiants en continu, du code au déploiement, et vérifier pour chacun qu’il porte le jeu de permissions exact du service qui l’emploie : le travail de CICD-SEC-2, appliqué aux secrets plutôt qu’aux comptes. Et ne pas partager un même jeu entre plusieurs contextes, ce qui rend le moindre privilège inatteignable et détruit la responsabilité nominative lors d’une enquête.

Préférer l’identifiant temporaire au statique. La recommandation structurante, dont la mise en œuvre est décrite dans sécuriser les identifiants CI/CD avec OIDC : le pipeline échange une preuve d’identité contre un jeton de courte durée, et il n’y a plus de secret à faire fuir. Quand le statique est inévitable, une rotation périodique et une détection des identifiants dormants : exploiter une rotation de clés, la durée de vie des jetons.

Conditionner l’usage des identifiants à une adresse source ou à une identité, pour qu’un secret exfiltré soit inutilisable ailleurs. La forme forte de cette idée est la liaison cryptographique des jetons liés au certificat client.

Centraliser dans un coffre : déployer un coffre-fort de secrets, l’architecture de gestion des secrets distribués, et l’enregistrement des accès de coffre à secrets et enregistrement.

Empêcher l’impression des secrets dans les sorties console, cadrer les secrets par pipeline et par étape, vérifier qu’aucun secret ne subsiste dans les artefacts : trois mesures de nettoyage, dont la dernière suppose qu’on sache ce qu’on publie. Et un indicateur à présenter à une direction : la distribution des âges des clés de déploiement en service.

La première conséquence est arithmétique : le nombre de personnes et de machines détenant un identifiant valide ne fait que croître, puisque rien ne le fait décroître. Au bout de quelques années, « qui détient aujourd’hui une clé de déploiement valide » n’a plus de réponse, ou plutôt a pour réponse honnête la liste de tous ceux qui ont travaillé sur le projet depuis sa création.

La seconde est la paralysie au moment de l’incident. Les identifiants étant partagés entre contextes, on ne peut pas renouveler celui qui a fuité sans casser des processus dont on ignore la liste, et comme rien n’a jamais été renouvelé, personne n’a la procédure. L’organisation choisit donc d’attendre, pire décision possible et la plus compréhensible. Et comme les secrets ont transité par l’historique du dépôt, les couches d’images et les journaux, la remédiation ne consiste pas à changer un mot de passe mais à nettoyer trois systèmes dont deux sont immuables par conception.

Une chaîne de fabrication logicielle a besoin de mots de passe : pour lire le code, déposer les paquets fabriqués, installer le résultat sur les serveurs. On les appelle des identifiants, et le problème décrit ici n’est pas qu’ils soient faibles, mais qu’il en traîne des copies partout.

Cinq endroits reviennent toujours. Le code lui-même, où un mot de passe est écrit en dur, parfois par inadvertance ; une fois envoyé, il reste visible dans l’historique du projet même effacé ensuite, ce que beaucoup ignorent. Les réglages de la chaîne, où le même mot de passe sert à plusieurs étapes dont certaines manipulent du code non relu. Les images de conteneurs, où un mot de passe utile à la seule fabrication reste enfermé dans une des épaisseurs de l’image, consultable par tous ceux qui la téléchargent. Les comptes rendus d’exécution, où un mot de passe s’affiche parce qu’un développeur voulait vérifier quelque chose, puis part dans l’archivage des journaux. Et le temps : les mots de passe qu’on ne change jamais, au nom du principe qu’on ne touche pas à ce qui fonctionne. Ce dernier cas est le plus coûteux parce qu’il est cumulatif : chaque année, un peu plus de gens et de machines détiennent une copie valide, sans que personne vole rien ni se trompe.

Deux mesures changent la nature du problème. La première est de n’avoir plus aucun mot de passe permanent : la chaîne prouve son identité à chaque usage et reçoit un laissez-passer valable quelques minutes, qui ne vaut rien s’il est volé. La seconde, pour ce qui ne peut pas s’y plier, est de lier le mot de passe à une condition d’usage, l’adresse d’où il est présenté par exemple, de sorte qu’une copie volée soit inutilisable ailleurs.

À lire aussi

Pages voisines

: les deux pages se citent l’une l’autre.