5 minutes. C’est le temps qu’il a fallu.

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. Bien plus rapides que vous ne vous rendez compte que vous avez merdé.

Les chiffres font peur

Selon GitHub, en 2024, 39 millions de secrets ont fuité dans des dépôts publics. 67% de plus que l’année précédente.

GitGuardian, qui se spécialise dans le scan de ce type de problèmes, 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. En attente que quelqu’un les utilise.

Ce n’est pas que du tout-venant

Toyota a eu des identifiants AWS exposés sur GitHub qui donnaient accès à son système télématique de véhicules. Pearson a perdu des données parce que quelqu’un a laissé un token GitLab dans un fichier de configuration. Otelier, une entreprise hôtelière, a vu 8TB de données S3 exfiltrées à cause d’identifiants exposés sur Bitbucket.

Ça n’arrive pas qu’au stagiaire. Ç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 d’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 de vraies données 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 arrivé).

Et là vous découvrez que votre facture AWS est passée de 20 francs à 2000 francs. En une nuit.

“Mais je l’ai effacé immédiatement”

Encore un classique.

Git est un système de contrôle de versions. Son boulot littéral c’est de se souvenir de tout ce qui s’est passé. Effacer le commit n’efface pas le secret de l’historique. Faire un force push ne l’efface pas des forks. Et ça ne l’efface 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 final. 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

1
2
3
# 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

1
2
3
# .env (dans .gitignore, soi-disant)
AWS_KEY=AKIAIOSFODNN7EXAMPLE
AWS_SECRET=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

Mieux, mais ce .env finit dans une sauvegarde, dans un zip que vous envoyez par Slack, sur un disque dur que vous vendez sur Ricardo…

Niveau 3 : Les limbes

1
2
# Secrets dans les variables d'environnement du système
export AWS_KEY=...

D’accord, mais où vous les stockez ? 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 foutre en l’air quelques 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 :

  1. Les secrets vivent dans 1Password, pas sur mon disque
  2. Le code a des références aux secrets, pas les secrets en tant que tels
  3. Les secrets sont injectés à l’exécution

Le pattern .env.template + op inject

Dans chaque projet, au lieu d’un .env avec des vraies valeurs, j’ai un .env.template avec des références :

1
2
3
4
5
6
7
# .env.template - ÇA 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 Qinqin/url
SUPABASE_SERVICE_KEY=op://FRR DEV/Supabase Qinqin/service-key
DATABASE_URL=postgres://localhost/mydb  # valeurs non secrètes vont direct

Quand j’ai besoin du vrai .env, j’exécute :

1
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 un post-it (ne me jugez pas).

Maintenant tout est dans un coffre-fort 1Password. Un seul endroit. Chiffré. Avec historique des modifications.

2. Rotation des 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 lui faut. Il n’a qu’à les avoir dans son propre 1Password (ou 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 envoyer quoi que ce soit 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 :

1
2
3
4
5
6
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. À partir de là, la variable est chargée dans la session.

Le seul inconvénient

Oui, il y en a un : vous devez autoriser avec Touch ID ou mot de passe de temps en temps.

J’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 sonne parano. “Ça ne m’arrivera pas à 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 font pas la différence 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 best practice. C’est de l’hygiène de base.

Comme se laver les mains. Vous ne le faites pas parce que c’est amusant. Vous le faites parce que l’alternative c’est choper une infection.

Vos secrets dans git sont une infection qui attend d’arriver.


Résumé exécutable :

  1. Installez 1Password et son CLI (brew install 1password-cli)
  2. Créez un coffre-fort pour le développement
  3. Migrez vos secrets des fichiers .env vers le coffre-fort
  4. Créez .env.template avec des références op://
  5. Ajoutez .env.local à .gitignore
  6. Régénérez avec op inject quand nécessaire

Et voilà. Trente minutes de configuration 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. Tant 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.