Gestion des secrets : arrêtez de coder vos clés API en dur
Chaque postmortem de compromission contient le même chapitre : quelqu'un a trouvé un identifiant. Voici comment sortir définitivement les secrets statiques de votre code, de vos images et de vos pipelines.
Par Innovation T Team
Chaque postmortem de compromission comporte un chapitre familier : quelqu'un a trouvé un identifiant. Dans un dépôt, dans une couche Docker, dans un log de CI, dans une capture d'écran collée sur Slack. La gestion des secrets n'est pas de l'hygiène pour la forme. C'est ce qui sépare un incident contenu d'un attaquant qui détient les clés de votre base de données de production.
Pourquoi un secret codé en dur ne reste jamais secret
Un secret commité dans le code n'est pas un secret. C'est une bombe à retardement dont la visibilité est réglée sur public.
Voici où ils fuient réellement :
- L'historique git. Supprimer la clé dans un nouveau commit ne change rien. L'ancien blob survit dans le magasin d'objets, dans chaque clone, dans chaque fork et dans les caches de vos runners CI. Un
git log -ple retrouve en quelques secondes. - Les couches d'images Docker.
COPY .env .suivi d'unRUN rm .envembarque quand même le secret. Les couches sont additives. Quiconque dispose d'un droit de pull peut lancerdocker historyet l'extraire. - Les logs de CI. Un
env | sortoublié dans une étape de debug, un framework qui affiche sa configuration au démarrage, un lanceur de tests qui déverse l'environnement en cas d'échec. Les logs sont conservés, transférés et indexés. - Les bundles côté client. Les builds frontend inlinent tout ce qui porte un préfixe d'exposition publique. Nous voyons régulièrement des clés serveur expédiées jusqu'au navigateur parce que quelqu'un a renommé une variable pour faire passer le build.
- Les synchronisations tierces. Extensions d'éditeur, outils de sauvegarde et assistants de code IA qui indexent votre espace de travail indexeront votre
.envavec le même entrain.
Des scanners automatisés surveillent en continu le flux d'événements public de GitHub. D'après notre expérience, une clé cloud poussée dans un dépôt public est sondée en quelques minutes, pas en quelques jours. C'est souvent une facture AWS gonflée par des cryptomineurs qui sert de premier signal d'alerte.
Le modèle de menace, énoncé simplement
Vous vous défendez contre trois choses :
- L'exfiltration : un attaquant lit le secret là où il a été consigné.
- Le rejeu : un attaquant qui détient le secret l'utilise, depuis n'importe où, aussi longtemps qu'il reste valide.
- Le rayon d'impact : un identifiant fuité ouvre bien plus de portes qu'il ne le devrait.
Chaque mesure ci-dessous s'attaque à l'une des trois. Le chiffrement au repos combat l'exfiltration. Les TTL courts combattent le rejeu. Des identifiants restreints, propres à chaque service, réduisent le rayon d'impact. Un outil qui ne se rattache clairement à aucun des trois relève de la décoration.
L'échelle de maturité
Ne vous précipitez pas sur un cluster Vault. Gravissez les échelons méthodiquement.
Niveau 0 : fichiers .env, exclus de git
Le plancher, pas l'objectif. Acceptable pour un prototype en solo. Les secrets sont en clair sur chaque poste de travail, il n'y a ni piste d'audit, ni rotation, et le départ d'un ingénieur se résume à espérer qu'il supprime le fichier.
Niveau 1 : le coffre de secrets de votre plateforme
Utilisez le coffre que votre plateforme fournit déjà : AWS Secrets Manager ou SSM Parameter Store, GCP Secret Manager, Azure Key Vault, ou les secrets chiffrés de Vercel, Fly.io ou GitHub Actions. Les secrets sont chiffrés au repos, injectés à l'exécution, et l'accès est gouverné par l'IAM. Pour la plupart des équipes de moins de 20 ingénieurs, ce niveau, bien opéré, vaut mieux qu'un Vault mal exploité.
La discipline clé à ce niveau : l'application lit ses secrets depuis l'environnement ou le SDK au démarrage. Jamais depuis un fichier du dépôt.
Niveau 2 : secrets centralisés, contrôle d'accès et audit
Un système de référence unique pour chaque secret, sur chaque environnement. HashiCorp Vault, OpenBao (le fork open source), Infisical ou Doppler. Ce que vous gagnez par rapport au niveau 1 :
- L'uniformité : une seule API et un seul langage de politiques sur AWS, GCP, l'on-premise et la CI.
- L'audit : chaque lecture est journalisée avec l'identité, le chemin et l'horodatage. Quand une clé fuit, c'est le journal d'audit qui permet de délimiter l'incident.
- La politique d'accès : le service de facturation peut lire
billing/*et rien d'autre, et c'est appliqué de façon centralisée.
Niveau 3 : identifiants dynamiques à courte durée de vie
L'aboutissement. Plus aucun secret statique n'existe. Les identifiants sont émis à la demande, rattachés à une identité unique, et expirent en quelques minutes ou quelques heures. À ce niveau, un identifiant fuité est un désagrément, pas une compromission.
Secrets dynamiques : tuer l'identifiant statique
Le moteur de secrets base de données de Vault illustre le mieux ce schéma. Au lieu d'un DB_PASSWORD partagé qui traîne à douze endroits, chaque instance de service demande son propre utilisateur au démarrage :
vault write database/roles/app-readonly \
db_name=postgres \
creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' \
VALID UNTIL '{{expiration}}'; \
GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
default_ttl="1h" max_ttl="24h"
Chaque lecture de database/creds/app-readonly crée un rôle Postgres neuf qui s'autodétruit au bout d'une heure. Les propriétés obtenues sans effort supplémentaire :
- L'attribution. Une requête lente signée
v-k8s-app-readonly-x7Hf? Vous savez exactement quel pod l'a émise. - La révocation immédiate. Révoquez le lease et l'identifiant meurt sur-le-champ, pas au prochain déploiement.
- Des fuites sans valeur. Un identifiant capturé dans une session de debug est expiré avant que quiconque puisse s'en servir.
Le même schéma existe pour les identifiants AWS STS, les clés de comptes de service GCP, les certificats SSH et la PKI. Le compromis est bien réel : votre base doit tolérer la rotation des rôles, vos poolers de connexions doivent savoir se ré-authentifier, et Vault devient une infrastructure de niveau zéro. Ce qui nous amène aux modes de défaillance.
Le problème du secret zéro, et autres pièges classiques
Les équipes qui adoptent un coffre trébuchent sur les quatre mêmes obstacles :
- Le secret zéro. L'application a besoin d'un identifiant pour parler au coffre. Si cet identifiant est un jeton statique dans une variable d'environnement, vous avez déplacé le problème, pas résolu. La solution, c'est l'identité de plateforme : jetons de compte de service Kubernetes, authentification IAM AWS, identité d'instance GCP. La charge de travail prouve qui elle est avec quelque chose que la plateforme atteste, pas quelque chose qu'un humain a collé quelque part.
- Le coffre comme point de défaillance unique. Si Vault est indisponible et que vos pods ne peuvent plus démarrer, vous avez transformé un outil de sécurité en incident de disponibilité. Exploitez-le en vraie haute disponibilité, mettez les leases en cache côté client, et fixez des TTL assez longs pour survivre à une courte panne.
- La rechute dans la prolifération. Sous la pression des délais, les ingénieurs recopient les secrets du coffre vers des fichiers
.env, « provisoirement ». Faites du chemin officiel le chemin le plus simple : intégration SDK, injection par sidecar, ou fichiers générés par gabarit au déploiement. - Des journaux d'audit en écriture seule. Un journal d'audit sur lequel personne n'alerte est une pièce de conformité, rien de plus. Alertez sur les lectures depuis des identités inhabituelles, les lectures en masse et l'usage du jeton root.
CI/CD : cessez de stocker des clés cloud dans vos pipelines
La CI est l'endroit où les identifiants statiques finissent volés. Une AWS_SECRET_ACCESS_KEY de longue durée dans les réglages de votre pipeline est lisible par chaque mainteneur, chaque action compromise et chaque dépendance dotée d'un script postinstall.
La réponse moderne, c'est la fédération OIDC. Le fournisseur de CI émet un jeton d'identité signé et de courte durée pour chaque job, et votre cloud fait directement confiance à ce jeton. Il n'existe plus aucune clé stockée à voler :
permissions:
id-token: write
contents: read
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/deploy-prod
aws-region: eu-west-1
Restreignez la politique de confiance IAM à votre organisation, votre dépôt et votre branche exacts. Un job sur main dans votre dépôt peut déployer ; un job sur un fork ne le peut pas, cryptographiquement. GitHub Actions, GitLab CI et CircleCI le prennent tous en charge face à AWS, GCP et Azure. Si vous travaillez plus largement la posture de sécurité de votre chaîne de livraison, notre guide du pipeline DevSecOps situe la gestion des secrets dans l'ensemble de la chaîne.
Intercepter les fuites avant la mise en production
La prévention vaut mieux que la réponse, et l'outillage est gratuit. Superposez trois filets :
1. Le scan en pre-commit. Gitleaks s'exécute en moins d'une seconde sur un diff indexé :
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.24.0
hooks:
- id: gitleaks
2. La push protection. Le secret scanning de GitHub avec push protection bloque le push côté serveur dès qu'un motif d'identifiant connu est détecté. Activez-le sur chaque dépôt, dépôts privés compris. GitLab propose un équivalent.
3. Les scans d'historique et d'artefacts. Lancez TruffleHog ou Gitleaks de façon planifiée sur l'historique git complet, les images de conteneurs et les artefacts de build. Les détections vérifiées (le scanner interroge réellement le fournisseur pour confirmer que la clé est active) réduisent radicalement le bruit des faux positifs.
Rien de tout cela ne remplace la conception d'API et de services où les secrets sont étroitement délimités dès le départ. Notre article sur les bonnes pratiques de sécurité des API approfondit la délimitation et la rotation des clés à la frontière de l'API.
Quand une clé fuite malgré tout : la première heure
Partez du principe que cela arrivera. Le plan d'action, dans l'ordre :
- Révoquer d'abord, enquêter ensuite. Dès que l'exposition est confirmée, tuez l'identifiant. N'attendez pas une fenêtre de maintenance. Une gêne de disponibilité se rattrape ; des données exfiltrées, non.
- Émettre le remplaçant. Créez le nouvel identifiant via votre gestionnaire de secrets, avec un périmètre plus serré que l'ancien. C'est le moment de corriger les permissions trop larges que vous remettiez à plus tard.
- Délimiter les dégâts. Extrayez les journaux d'audit sur toute la fenêtre d'exposition de l'identifiant, pas seulement depuis sa découverte. Sur AWS, cela signifie des requêtes CloudTrail sur l'ID de la clé d'accès. Cherchez les IP, régions et appels d'API inhabituels. Et si des données personnelles ont pu être consultées, le RGPD déclenche l'horloge des 72 heures pour la notification à la CNIL (l'INPDP joue ce rôle en Tunisie), à compter de la constatation de la violation.
- Purger, mais considérer la clé comme grillée. Réécrivez l'historique avec
git filter-repoet forcez le push, mais comprenez bien qu'il s'agit de nettoyage, pas de remédiation. Les clones et les forks la détiennent toujours. L'identifiant est mort dans tous les cas, c'est tout l'intérêt de l'étape 1. - Corriger le chemin, pas la personne. Le secret a été commité parce que le chemin sûr était plus pénible que le chemin dangereux. Ajoutez le hook de pre-commit, branchez le gestionnaire de secrets, refermez la brèche.
Si tout cela n'est pas écrit et répété avant d'en avoir besoin, commencez par notre plan de réponse aux incidents.
Un cadre de décision
Choisissez l'outil en fonction de l'équipe, pas de la conférence à la mode :
- Solo ou très petite équipe, un seul cloud : le gestionnaire de secrets de votre cloud plus l'OIDC en CI. Une après-midi de travail, l'essentiel de la valeur.
- Équipe en croissance, un ou deux clouds, Kubernetes : les gestionnaires de secrets cloud en backend, External Secrets Operator pour la synchronisation vers le cluster, la push protection sur chaque dépôt.
- Multi-cloud, exigences de conformité (RGPD, NIS2, PCI DSS), charges 24/7 : Vault ou OpenBao avec authentification par identité de plateforme, identifiants dynamiques pour les bases de données et l'accès cloud, alertes branchées sur le journal d'audit.
- Secteurs régulés ou cibles à forte valeur : tout ce qui précède, plus des TTL courts érigés en politique, des exercices de fuite trimestriels, et une rotation des secrets vérifiée par l'automatisation plutôt que par un rappel dans un agenda.
Quel que soit le niveau retenu, trois règles sont universelles. Aucun secret dans git, jamais. Aucun secret partagé entre deux services. Chaque secret doit avoir un propriétaire, un périmètre et une date d'expiration que quelqu'un est capable d'énoncer à voix haute.
Comment Innovation T peut vous aider
Innovation T conçoit et opère des infrastructures de secrets pour des équipes en Europe et en Afrique du Nord : déploiements Vault et OpenBao en vraie haute disponibilité, fédération OIDC pour la CI/CD, identifiants de base de données dynamiques, et détection de fuites intégrée au pipeline plutôt que rajoutée après un incident. Nous avons migré des équipes hors des clés codées en dur sans la moindre interruption de production, et nous laissons derrière nous des runbooks que vos ingénieurs utilisent vraiment.
Si vos fichiers .env ne sont qu'à un vol d'ordinateur portable du rapport d'incident, parlons-en. Consultez nos services ou contactez-nous pour une revue de votre posture de gestion des secrets.
Prêt à construire avec Innovation T ?
Qu'il s'agisse de sécurité, de croissance ou d'ingénierie, notre équipe peut vous aider à livrer dans les meilleures conditions.