5 minutes. C’est le temps que ça a pris.
Un chercheur en sécurité publie une clé d’accès AWS dans un dépôt public GitHub. Il le fait exprès, comme expérience.
Cinq minutes plus tard, quelqu’un l’utilisait déjà pour miner des cryptomonnaies.
Cinq. Minutes.
Il y a des bots qui scannent GitHub 24h/24 et 7j/7 en cherchant exactement ça : des identifiants exposés. Et ils sont rapides. Beaucoup plus rapides que vous ne vous rendez compte que vous avez fait une bêtise.
Les chiffres font peur
Selon GitHub, en 2024, 39 millions de secrets ont été divulgués dans des dépôts publics. 67% de plus que l’année précédente.
GitGuardian, qui se spécialise dans ce type de scan, a trouvé 23,7 millions de nouveaux secrets rien que dans les dépôts publics. Et le pire : 70% des secrets détectés en 2022 étaient encore actifs en 2024.
Deux ans après. Toujours fonctionnels. Attendant que quelqu’un les utilise.
Ce ne sont pas que des gens lambda
Toyota a eu des identifiants AWS exposés sur GitHub qui donnaient accès à leur système télématique de véhicules. Pearson a perdu des données parce que quelqu’un avait laissé un token GitLab dans un fichier de configuration. Otelier, une entreprise d’hôtellerie, a vu 8TB de données S3 exfiltrées à cause d’identifiants exposés sur Bitbucket.
Ça n’arrive pas qu’aux stagiaires. Ça arrive aux entreprises du Fortune 500.
Le classique : “C’est juste mon projet personnel”
Ouais, bien sûr.
Le problème c’est que ce projet personnel a la même clé API OpenAI que vous utilisez en production. Ou le token de votre bot Telegram. Ou les identifiants de votre base de données de staging qui, oh surprise, contient des données réelles parce que “c’est plus facile pour tester”.
Et un jour vous faites git push sans réfléchir. Ou vous changez le dépôt de privé à public parce que vous voulez le montrer à quelqu’un. Ou GitHub a un bug et expose temporairement des dépôts privés (c’est déjà arrivé).
Et là vous découvrez que votre facture AWS est passée de 20 CHF à 2000 CHF. En une nuit.
“Mais je l’ai supprimé immédiatement”
Autre classique.
Git est un système de contrôle de versions. Son travail littéral est de se souvenir de tout ce qui s’est passé. Supprimer le commit ne supprime pas le secret de l’historique. Faire un force push ne le supprime pas des forks. Et ça ne le supprime définitivement pas des bots qui l’ont déjà copié.
Une fois qu’un secret touche un dépôt public, il est compromis. Point. Il faut le faire tourner.
La pyramide du désastre
Voici comment évolue généralement la gestion des secrets dans un projet typique :
Niveau 1 : L’enfer
# config.py
AWS_KEY = "AKIAIOSFODNN7EXAMPLE"
AWS_SECRET = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
Directement dans le code. Commité. En production. Ne riez pas, ça existe.
Niveau 2 : Le purgatoire
# .env (dans .gitignore, supposément)
AWS_KEY=AKIAIOSFODNN7EXAMPLE
AWS_SECRET=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Mieux, mais ce .env finit dans un backup, dans un zip qu’on envoie par Slack, sur un disque dur qu’on revend…
Niveau 3 : Les limbes
# Secrets dans les variables d'environnement système
export AWS_KEY=...
D’accord, mais où les stockez-vous ? Sur un post-it ? Dans un fichier secrets.txt sur le bureau ? Dans un message Slack à vous-même ?
La solution : secrets hors du code, hors du disque
Après avoir vu comment j’ai failli tout foirer plusieurs fois, j’ai décidé de tout centraliser dans 1Password et d’utiliser son CLI pour injecter les secrets quand nécessaire.
Le concept est simple :
- Les secrets vivent dans 1Password, pas sur mon disque
- Le code a des références aux secrets, pas les secrets eux-mêmes
- Les secrets sont injectés à l’exécution
Le pattern .env.template + op inject
Dans chaque projet, au lieu d’un .env avec des valeurs réelles, j’ai un .env.template avec des références :
# .env.template - CECI VA DANS GIT
# Régénérer avec : op inject -i .env.template -o .env.local
OPENAI_API_KEY=op://FRR DEV/OpenAI/api-key
SUPABASE_URL=op://FRR DEV/Supabase Personal/url
SUPABASE_SERVICE_KEY=op://FRR DEV/Supabase Personal/service-key
DATABASE_URL=postgres://localhost/mydb # valeurs non-secrètes vont direct
Quand j’ai besoin du .env réel, j’exécute :
op inject -i .env.template -o .env.local
1Password lit les références op://, les résout avec les vraies valeurs, et génère le fichier. Le .env.local est dans .gitignore, il ne touche jamais git.
Qu’est-ce que j’y gagne ?
1. Un seul endroit pour tous les secrets
Avant j’avais des identifiants éparpillés dans des fichiers .env de 15 projets, des variables d’environnement dans .bashrc, des tokens dans des messages Slack, et quelques-uns sur des post-its (ne me jugez pas).
Maintenant tout est dans un coffre 1Password. Un endroit. Chiffré. Avec historique des modifications.
2. Rotation de secrets triviale
Avant : changer une clé API signifiait la chercher dans tous les projets, mettre à jour les fichiers, prier pour n’en oublier aucun.
Maintenant : je mets à jour la valeur dans 1Password, j’exécute op inject dans chaque projet, c’est fini.
3. Le code documente ce dont il a besoin
Le .env.template est de la documentation vivante. Quiconque clone le projet sait exactement quels secrets il faut. Il suffit de les avoir dans son propre 1Password (ou de vous les demander).
4. Impossible de commiter des secrets par accident
Le fichier qui va dans git n’a que des références op://. Même si vous faites git add . sans réfléchir, vous n’exposez rien.
5. Synchronisation entre machines gratuite
Nouveau Mac ? Installez 1Password, connectez-vous, op inject. Tous vos secrets disponibles sans copier de fichiers ni rien envoyer par Slack.
Pour le quotidien : lazy loading dans Fish
Pour les commandes qui ont besoin d’identifiants (comme oco pour les commits avec IA), j’ai ça dans ma config Fish :
function oco
if not set -q OPENAI_API_KEY
set -gx OPENAI_API_KEY (op read "op://FRR DEV/OpenAI/api-key")
end
command oco $argv
end
La première fois que j’exécute oco, il me demande Touch ID. Après ça, la variable est chargée dans la session.
Le seul inconvénient
Oui, il y en a un : il faut s’autoriser avec Touch ID ou mot de passe de temps en temps.
Je l’ai optimisé en configurant 1Password pour qu’il se souvienne des autorisations 24 heures et ne se verrouille qu’à la mise en veille du Mac. Mais oui, de temps en temps il faut mettre le doigt.
C’est un petit prix à payer pour ne pas apparaître dans les statistiques de GitGuardian.
Ce n’est pas optionnel
Écoutez, je comprends que tout ça puisse sembler paranoïaque. “Ça ne va pas m’arriver à moi”. “C’est juste un petit projet”. “Je n’ai rien d’important”.
Mais pensez à ça : avez-vous une clé API payante ? OpenAI ? AWS ? N’importe quel service qui facture à l’usage ?
Alors vous avez quelque chose que quelqu’un peut exploiter.
Et les bots ne se reposent pas. Ils ne distinguent pas entre le projet d’une startup et les devoirs de programmation d’un étudiant. Ils scannent tout, testent tout, exploitent tout.
39 millions de secrets divulgués en 2024. 70% de ceux de 2022 sont encore actifs.
La gestion correcte des secrets n’est pas une bonne pratique. C’est de l’hygiène de base.
Comme se laver les mains. On ne le fait pas parce que c’est amusant. On le fait parce que l’alternative c’est attraper une infection.
Vos secrets dans git sont une infection qui attend de se produire.
Résumé exécutable :
- Installez 1Password et son CLI (
brew install 1password-cli) - Créez un coffre pour le développement
- Migrez vos secrets des fichiers
.envvers le coffre - Créez
.env.templateavec des référencesop:// - Ajoutez
.env.localà.gitignore - Régénérez avec
op injectquand nécessaire
Et voilà. Trente minutes de setup qui vous évitent d’apparaître dans le prochain rapport de GitGuardian.
Vos identifiants AWS vous remercieront.
Mise à jour : Après avoir implémenté tout ça, j’ai découvert que 1Password me demandait Touch ID trop souvent. Tellement que j’ai commencé à approuver sans regarder. Ça a un nom en sécurité et ce n’est pas bon. Lisez Quand la sécurité vous demande permission si souvent que vous arrêtez de lire pour voir comment on a résolu ça.
Cet article a été rédigé en espagnol et traduit avec l’aide de l’IA.