Skip to main content

Suppression de données sensibles dans un dépôt

Les données sensibles peuvent être supprimées de l’historique d’un référentiel si vous pouvez vous coordonner soigneusement avec tous ceux qui l’ont cloné et si vous êtes prêt à en gérer les effets secondaires.

À propos de la suppression de données sensibles dans un référentiel

Lorsque vous modifiez l’historique de votre référentiel à l’aide d’outils comme git filter-repo, il est essentiel de comprendre les implications. L’historique de réécriture nécessite une coordination minutieuse avec les collaborateurs pour s’exécuter avec succès et a un certain nombre d’effets secondaires qui doivent être gérés.

Il est important de noter que si les données sensibles que vous devez supprimer sont secrètes (par exemple, un mot de passe, un jeton ou un identifiant), comme c’est souvent le cas, vous devez d’abord révoquer et/ou renouveler ce secret. Une fois le secret révoqué ou renouvelé, il ne peut plus être utilisé pour l’accès, et cela peut suffire à résoudre votre problème. Dans ce cas, il peut ne pas être nécessaire d’effectuer les étapes supplémentaires de réécriture de l’historique et de suppression du secret.

Effets secondaires de la réécriture de l’historique

Réécrire l’historique comporte de nombreux effets secondaires, notamment :

  • Risque élevé de recontamination : malheureusement, il est facile d’envoyer à nouveau les données sensibles dans le référentiel et d’aggraver la situation. Si un autre développeur dispose d’un clone antérieur à votre réécriture, et qu’après votre réécriture, il exécute simplement git pull suivi de git push, les données sensibles réapparaîtront. Il doit soit abandonner son clone et le recréer, soit suivre attentivement plusieurs étapes pour nettoyer d’abord son clone.
  • Risque de perdre le travail d'autres développeurs : si d’autres développeurs continuent à mettre à jour des branches contenant des données sensibles pendant que vous essayez de procéder au nettoyage, vous devrez soit recommencer le nettoyage, soit abandonner leur travail.
  • Modification des hachages de commit : la réécriture de l’historique modifiera les hachages des commits qui ont introduit les données sensibles_et_ de tous les commits ultérieurs. Tout outil ou automatisation qui dépend de l’invariabilité des hachages de commit sera défaillant ou présentera des problèmes.
  • Défis liés à la protection des branches : si des protections de branche empêchent le passage en force, ces protections devront être désactivées (au moins temporairement) pour que les données sensibles soient supprimées.
  • Vue diff cassée pour les demandes de tirage (pull request) fermées : la suppression des données sensibles nécessitera la suppression des références internes utilisées pour l’affichage de la vue diff dans les demandes de tirage. Vous ne serez donc plus en mesure de voir ces différences. Cela est vrai non seulement pour la demande de tirage qui a introduit les données sensibles, mais aussi pour toutes les demandes de tirage qui s’appuient sur une version de l’historique postérieure à la fusion de la demande de tirage contenant les données sensibles (même si ces demandes de tirage ultérieures n’ont pas ajouté ou modifié de fichier contenant des données sensibles).
  • Mauvaise interaction avec les demandes de tirage ouvertes : les modifications des SHA de commit se traduiront par un diff de demande de tirage (PR) différent, et les commentaires sur l’ancien diff de PR peuvent être invalidés et perdus, ce qui peut être source de confusion pour les auteurs et les réviseurs. Nous vous recommandons de fusionner ou de fermer toutes les demandes de tirage ouvertes avant de supprimer des fichiers de votre dépôt.
  • Perte des signatures sur les commits et les balises : les signatures des commits ou des balises dépendent des hachages de commit. Comme les hachages de commit sont modifiés par les réécritures de l’historique, les signatures ne seraient plus valides et de nombreux outils de réécriture de l’historique (y compris git filter-repo) supprimeraient simplement les signatures. En fait, git filter-repo supprimera également les signatures de commit et les signatures de balise pour les commits antérieurs à la suppression des données sensibles. (Techniquement, il est possible de contourner ce problème en ajoutant l’option --refs à git filter-repo si nécessaire, mais vous devrez alors veiller à spécifier tous les refs qui contiennent des données sensibles dans leur historique et qui incluent les commits qui ont introduit les données sensibles dans votre plage.)
  • Diriger les autres directement vers les données sensibles : Git a été conçu avec des contrôles cryptographiques intégrés dans les identificateurs de commit afin que des individus malveillants ne puissent pas pénétrer dans un serveur et modifier l’historique sans être détectés. C’est utile du point de vue de la sécurité, mais du point de vue des données sensibles, cela signifie que leur suppression est un processus de coordination très complexe. Cela signifie également que lorsque vous modifiez l’historique, les utilisateurs prudents possédant un clone existant remarqueront la divergence de l’historique et pourront l’utiliser pour trouver rapidement et facilement les données sensibles encore présentes dans leur clone et que vous avez supprimées du référentiel central.

À propos de l’exposition aux données sensibles

La suppression des données sensibles d'un référentiel comporte quatre étapes principales :

  • Réécrire le référentiel localement à l’aide de git-filter-repo
  • Mettre à jour le référentiel sur GitHub à l’aide de votre historique réécrit localement
  • Se coordonner avec des collègues pour nettoyer d’autres clones qui existent
  • Empêcher les répétitions et éviter les futures fuites de données sensibles

Si vous réécrivez seulement votre historique et que vous le poussez de force, les commits contenant des données sensibles peuvent toujours être accessibles ailleurs :

  • Dans tous les clones ou duplications de votre référentiel
  • Directement via leurs hachages SHA-1 dans les vues mises en cache sur GitHub
  • Par le biais de toutes les demandes de tirage qui les référencent

Vous ne pouvez pas supprimer les données sensibles des clones d’autres utilisateurs de votre référentiel ; vous devrez leur envoyer les instructions de Assurez-vous que d’autres copies sont nettoyées : clones de collègues dans le manuel git filter-repo pour qu’ils le fassent eux-mêmes. Cependant, vous pouvez supprimer les vues en cache et les références aux données sensibles dans les demandes de tirage sur GitHub en contactant nous via le portail de support GitHub.

Important

Support GitHub ne supprime pas les données non sensibles et vous aide à supprimer des données sensibles uniquement si nous jugeons que la rotation des identifiants affectés ne permettrait pas d’atténuer le risque.

Si le commit qui a introduit les données sensibles existe dans une duplication, elles continueront d'y être accessibles. Vous devrez vous coordonner avec les propriétaires des duplications, en leur demandant de supprimer les données sensibles ou de supprimer entièrement la duplication. GitHub ne peut pas fournir les coordonnées de ces propriétaires.

Tenez compte de ces limitations et de ces problématiques dans votre décision de réécrire l’historique de votre dépôt.

Supprimer définitivement un fichier de l’historique de votre référentiel local à l’aide de git-filter-repo

  1. Installez la dernière version del’git filter-repooutil. Vous avez besoin d’une version avec l’indicateur --sensitive-data-removal, à savoir au moins la version 2.47. Vous pouvez installer git filter-repo manuellement ou en utilisant un gestionnaire de package. Par exemple, pour installer l’outil avec HomeBrew, utilisez la commande brew install.

    brew install git-filter-repo
    

    Pour plus d’informations, consultez INSTALL.md dans le dépôt newren/git-filter-repo.

  2. Clonez le référentiel sur votre machine locale. Consultez Clonage d’un dépôt.

    git clone https://github.com/YOUR-USERNAME/YOUR-REPOSITORY
    
  3. Accédez au répertoire de travail du dépôt.

    cd YOUR-REPOSITORY
    
  4. Exécutez une commande git filter-repo pour nettoyer les données sensibles.

    Si vous souhaitez supprimer un fichier spécifique de toutes les branches/balises/refs, exécutez la commande suivante en remplaçant PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA par le chemin git vers le fichier que vous souhaitez supprimer, et pas seulement son nom de fichier (par exemple, src/module/phone-numbers.txt) :

    git filter-repo --sensitive-data-removal --invert-paths --path PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA
    

    Important

    Si le fichier contenant des données sensibles existait auparavant à d'autres emplacements (car il a été déplacé ou renommé), vous devez soit ajouter un argument de --path supplémentaire pour ce fichier, soit exécuter cette commande une deuxième fois en indiquant le chemin d’accès alternatif.

    Si vous souhaitez remplacer tout le texte répertorié dans ../passwords.txt à partir de fichiers non binaires trouvés n’importe où dans l’historique de votre référentiel, exécutez la commande suivante :

    git filter-repo --sensitive-data-removal --replace-text ../passwords.txt
    
  5. Vérifiez bien que vous avez supprimé tout ce que vous vouliez de l’historique de votre référentiel.

  6. Découvrez le nombre de demandes de tirage qui seront affectées par cette réécriture de l’historique. Vous aurez besoin de ces informations ci-dessous.

    $ grep -c '^refs/pull/.*/head$' .git/filter-repo/changed-refs
    4
    

    Vous pouvez supprimer le -c pour voir quelles demandes de tirage sont affectées :

    $ grep '^refs/pull/.*/head$' .git/filter-repo/changed-refs
    refs/pull/589/head
    refs/pull/602/head
    refs/pull/604/head
    refs/pull/605/head
    

    Cette sortie inclut le numéro de demande de tirage (pull request) entre les deuxième et troisième barres obliques. Si le nombre de demandes de tirage affectées est supérieur à ce que vous attendiez, vous pouvez ignorer ce clone sans effets incorrects et rétablir la réécriture ou abandonner la suppression des données sensibles. En passant à l'étape suivante, la réécriture devient irréversible.

  7. Une fois satisfait(e) de l’état de votre référentiel, effectuez une poussée forcée de vos modifications locales pour écraser votre référentiel sur GitHub.com. Bien que --force soit implicite par --mirror, nous l’incluons ci-dessous, comme rappel du fait que vous effectuez une mise à jour forcée de toutes les branches, balises et refs et que vous ignorez les modifications effectuées par d'autres personnes sur ces refs lors du nettoyage du référentiel.

    git push --force --mirror origin
    

    Cette commande ne parvient pas à envoyer (push) toutes les références commençant par refs/pull/, car GitHub marque ces données en lecture seule. Ces échecs push sont gérés dans la section suivante. Si d’autres références ne parviennent pas à envoyer (push), il est probable que la protection des branches soit activée pour cette branche et qu’il soit nécessaire de la désactiver temporairement et rétablir l’envoi( push). Répétez l'opération jusqu'à ce que les seules défaillances à mettre à jour soient des refs commençant par refs/pull/.

Suppression complète des données de GitHub

Après avoir utilisé git filter-repo pour supprimer les données sensibles et envoyé (push) vos modifications sur GitHub, vous devez effectuer quelques étapes supplémentaires pour supprimer entièrement les données de GitHub.

  1. Contactez nous via le portail de support GitHub, puis fournissez les informations suivantes :

    • Nom du propriétaire et du référentiel en question (par exemple, VOTRE-NOM D’UTILISATEUR/VOTRE-RÉFÉRENTIEL).
    • Nombre de demandes de tirage affectées, trouvées à l’étape précédente. Ceci est utilisé par le support pour vérifier que vous comprenez la quantité qui sera affectée.
    • La ou les premières validations modifiées signalées par git filter-repo (Recherchez NOTE: First Changed Commit(s) dans sa sortie.)
    • Si NOTE: There were LFS Objects Orphaned by this rewrite apparaît dans la sortie git-filter-repo (juste après la validation modifiée), mentionnez que vous avez également des objets LFS orphelins et chargez le fichier nommé dans le ticket.

    Si vous avez correctement nettoyé toutes les références autres que les PR et qu’aucune duplication n’a de références aux données sensibles, la prise en charge effectuera alors les opérations suivantes :

    • Déréférencer ou supprimer tout PR affecté sur GitHub.

    • Exécuter un GC sur le serveur pour effacer les données sensibles du stockage.

    • Supprimer les vues mises en cache.

    • Si des objets LFS sont impliqués, supprimez et/ou videz les objets LFS orphelins.

    Important

    Support GitHub ne supprimera pas les données non sensibles et vous aidera à supprimer des données sensibles uniquement si nous jugeons que la rotation des identifiants affectés ne permettrait pas d’atténuer le risque.

  2. Les collaborateurs doivent rebaser, _et non pas_fusionner les branches qu'ils ont créées à partir de l’ancien historique de votre dépôt (compromis). Un commit de fusion pourrait réintroduire une partie ou l’ensemble de l’histoire compromis que vous vous êtes donné la peine de supprimer. Ils peuvent également avoir besoin de prendre des mesures supplémentaires ; consultez Vérifiez que d’autres copies sont nettoyées : clones de collègues dans le manuel git filter-repo.

Éviter les commits accidentels à l’avenir

En empêchant les contributeurs d’effectuer des commits accidentels, vous contribuez à empêcher l’exposition des informations sensibles. Pour plus d’informations, consultez Bonnes pratiques pour empêcher les fuites de données dans votre organisation.

Il existe plusieurs moyens d’éviter de commettre ou d'envoyer (push) des éléments qui ne devraient pas être partagés :

  • Si les données sensibles sont susceptibles de se trouver dans un fichier qui ne devrait pas être suivi par git, ajoutez ce nom de fichier à .gitignore (et assurez-vous de commiter et d’envoyer (push) cette modification à .gitignore pour que les autres développeurs soient protégés).
  • Évitez de coder en dur des secrets dans le code. Utilisez des variables d’environnement ou des services de gestion des secrets comme Azure Key Vault, AWS Secrets Manager ou HashiCorp Vault pour gérer et injecter des secrets au moment de l’exécution.
  • Créez un hook de pré-commit pour vérifier les données sensibles avant qu’elles ne soient commitées ou envoyées (push) n’importe où, ou utilisez un outil bien connu dans un hook de pré-commit comme git-secrets ou gitleaks. (Veillez à demander à chaque collaborateur de mettre en place le hook de pré-commit que vous avez choisi.)
  • Utilisez un programme visuel comme GitHub Desktop ou gitk pour commiter les modifications. Généralement, les programmes visuels permettent de voir plus facilement les fichiers exacts qui seront ajoutés, supprimés et modifiés avec chaque commit.
  • Évitez les commandes génériques git add . et git commit -a dans la ligne de commande : utilisez plutôt git add filename et git rm filename pour indexer les fichiers individuellement.
  • Utilisez git add --interactive pour vérifier et indexer les modifications dans chaque fichier.
  • Utilisez git diff --cached pour vérifier les modifications que vous avez indexées pour le commit. Il s’agit de la différence exacte que git commit produira tant que vous n’utilisez pas l’indicateur -a.
  • Activez la protection Push pour votre référentiel afin de détecter et d’empêcher les envois qui contiennent des secrets codés en dur d’être validés dans votre codebase. Pour plus d’informations, consultez « À propos de la protection push ».

Pour aller plus loin