Secrets GitHub Actions : du risque de fuite au déploiement OIDC sans clé

Un week-end de mars 2025, l’équipe sécurité de GitHub a envoyé un e-mail urgent à plus de 23 000 propriétaires de dépôts.
Leurs secrets avaient peut-être fuité.
Le coupable : l’action tj-actions/changed-files — un outil très utilisé, compromis par des attaquants qui volaient discrètement toutes les variables d’environnement et les secrets du workflow. Vous vous demandez peut-être : mon projet l’utilise aussi, suis-je concerné ?
Cet incident a mis sur la table une question que beaucoup ignorent : comment gérer correctement les secrets dans GitHub Actions ?
Dans cet article, nous abordons trois sujets : comment choisir l’architecture à trois niveaux des secrets, comment appliquer les 8 règles de sécurité, et comment OIDC vous permet d’échapper au cauchemar des credentials statiques qui fuient.
1. L’architecture à trois niveaux des Secrets GitHub Actions
GitHub propose trois niveaux pour stocker les secrets : Repository, Environment et Organization. Lequel choisir ? La réponse dépend de votre scénario.
Repository Secrets : le choix des projets personnels
C’est le niveau le plus simple. Les secrets vivent au niveau du dépôt ; tous les workflows y accèdent. Projet perso, dépôt monolithique, pas de déploiement multi-environnement — ce niveau suffit en général.
Seul inconvénient : impossible de distinguer un secret homonyme entre staging et production. Par exemple un DATABASE_URL différent selon l’environnement — là, il faut Environment Secrets.
Environment Secrets : indispensable pour le multi-environnement
Les secrets d’environnement s’isolent par environnement et supportent des flux d’approbation. Dans les paramètres du dépôt, créez par exemple staging et production, chacun avec ses secrets.
Point clé : seul le job qui référence cet environnement accède aux secrets correspondants. Les frontières de sécurité sont plus nettes.
jobs:
deploy-staging:
runs-on: ubuntu-latest
environment: staging # référence l'environnement staging
steps:
- run: echo "Deploying to staging..."
- env:
API_KEY: ${{ secrets.API_KEY }} # secret de l'environnement staging
deploy-production:
runs-on: ubuntu-latest
environment: production # référence production (approbation possible)
steps:
- run: echo "Deploying to production..."
- env:
API_KEY: ${{ secrets.API_KEY }} # secret de l'environnement production
Dans cette config, deploy-staging n’accède qu’aux secrets de staging, et deploy-production qu’à ceux de production. Aucune interférence entre les deux.
Les Environment supportent aussi des règles de protection — par exemple exiger une approbation manuelle avant d’exécuter production. Très utile en équipe.
Organization Secrets : partage d’équipe, gestion centralisée
Votre équipe a des dizaines de dépôts, chacun avec le même AWS_ACCESS_KEY — copier-coller des dizaines de fois, puis tout refaire à chaque rotation : épuisant.
Les Organization secrets règlent ça : une configuration au niveau organisation, réutilisable par tous les dépôts. Vous contrôlez l’accès : tous les dépôts, ou une liste ciblée.
# Dans le workflow du dépôt, même syntaxe que les repository secrets
steps:
- env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
Comment choisir ?
En résumé :
| Scénario | Niveau recommandé |
|---|---|
| Projet perso, environnement unique | Repository Secrets |
| Déploiement multi-environnement (staging/production) | Environment Secrets |
| Équipe, plusieurs dépôts, credentials partagés | Organization Secrets |
D’après mon expérience, beaucoup de projets démarrent avec Repository Secrets puis migrent vers Environment Secrets quand le multi-env arrive — la migration reste légère, mais mieux vaut anticiper.
2. Bonnes pratiques de sécurité des Secrets — 8 règles
Nous avons vu où stocker les secrets ; voyons comment les utiliser. Voici 8 règles tirées du terrain, chacune avec sa leçon.
1. Nommage cohérent
MAJUSCULES + underscores, par ex. AWS_ACCESS_KEY_ID. Pas de minuscules, pas de camelCase. On reconnaît immédiatement un secret, sans confusion avec une variable ordinaire.
2. Ne pas stocker un JSON entier dans un seul secret
Piège classique : tout un fichier de config dans un secret :
{"api_key": "xxx", "db_url": "yyy", "token": "zzz"}
Puis parsing avec fromJson dans le workflow. Si ce secret fuit, tout part ensemble. Mieux : une valeur par secret.
3. Passage explicite, pas d’inlining
# Mauvais ❌
- run: my-cli --token ${{ secrets.MY_TOKEN }}
# Bon ✅
- env:
MY_TOKEN: ${{ secrets.MY_TOKEN }}
run: my-cli --token $MY_TOKEN
Pourquoi ? Selon GitGuardian, les arguments de ligne de commande sont visibles par d’autres processus sur la même machine via ps x -w. Les variables d’environnement sont nettement plus sûres.
4. Rotation régulière
Tous les 30 à 90 jours. La rotation est pénible — mais bien moins que la réponse à incident après fuite. L’équipe Blacksmith recommande, avec AWS/GCP, d’envisager OIDC pour éviter cette corvée.
5. Épingler les Actions par SHA
Première ligne de défense contre la supply chain.
# Mauvais ❌
- uses: tj-actions/changed-files@v45
# Bon ✅
- uses: tj-actions/changed-files@b827595e0a7e97537d7c7a2f458b5a8e6d5c8e39
Utilisez le SHA du commit, pas un tag de version. Un tag peut être détourné ; un SHA est immuable.
6. GITHUB_TOKEN avec le moindre privilège
GitHub fournit automatiquement un GITHUB_TOKEN par workflow. Par défaut, les droits sont trop larges — écriture de code, modification d’issues. Passez-le en read-only dans le workflow ou les paramètres du dépôt :
permissions:
contents: read
7. Vérifier le masquage des secrets dans les logs
GitHub remplace ${{ secrets.XXX }} par *** dans les logs. Mais si vous écrivez :
- run: echo "Token is $MY_TOKEN"
la valeur réelle peut apparaître. Testez vos workflows pour confirmer l’absence d’exposition accidentelle.
8. Enregistrer les valeurs sensibles dérivées
Si le workflow génère une nouvelle donnée sensible à partir d’un secret (par ex. un JWT à partir d’une clé API), enregistrez-la aussi comme secret — ne la faites pas transiter uniquement en mémoire.
Ces 8 règles ne sont pas théoriques : après tj-actions, l’équipe StepSecurity a audité des milliers de dépôts publics — une part significative en violait plusieurs. Les corriger demande du temps, mais reste faisable.
3. OIDC — authentification cloud sans secrets stockés
Les règles ci-dessus évoquent la rotation. Honnêtement, c’est fastidieux — modifier la console AWS, mettre à jour les secrets GitHub, prévenir l’équipe.
OIDC (OpenID Connect) ouvre une autre voie : ne plus stocker de secrets du tout.
Comment fonctionne OIDC ?
Méthode classique : créer un utilisateur IAM AWS, générer des access keys, les mettre dans les secrets GitHub. À chaque run, le workflow utilise ces clés statiques.
Méthode OIDC : GitHub agit comme fournisseur d’identité et prouve à AWS que « ce workflow vient du dépôt eastondev/my-repo ». AWS valide et délivre un JWT court (quelques minutes à quelques heures). Le workflow l’utilise puis le jeton expire.
Pas de credential longue durée, pas de rotation, pas de risque de fuite de clé statique.
Exemple de configuration OIDC sur AWS
Deux parties : confiance côté AWS, demande de jeton côté GitHub.
Côté AWS (console) :
- Créer un IAM Identity Provider, URL
https://token.actions.githubusercontent.com - Créer un IAM Role avec une politique de confiance limitée à votre dépôt :
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
"token.actions.githubusercontent.com:sub": "repo:eastondev/my-repo:ref:refs/heads/main"
}
}
}]
}
Seuls les workflows du dépôt eastondev/my-repo sur la branche main peuvent assumer ce rôle.
Côté GitHub (workflow) :
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
id-token: write # requis pour demander le jeton OIDC
contents: read
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789:role/GitHubActionsRole
aws-region: us-east-1
- run: aws s3 sync ./dist s3://my-bucket
Aucun secrets.AWS_ACCESS_KEY — authentification directe via le rôle.
GCP et Azure
Les trois grands clouds supportent OIDC, avec des variantes similaires :
| Plateforme | Action GitHub | Mots-clés doc officielle |
|---|---|---|
| AWS | aws-actions/configure-aws-credentials | OIDC federation |
| GCP | google-github-actions/auth | Workload Identity Federation |
| Azure | azure/login | Federated Identity Credentials |
Un avantage inattendu d’OIDC
Selon des tests sur johal.in, la latence d’authentification OIDC est environ 87 % plus basse qu’avec des secrets classiques : pas d’appel à l’API des secrets GitHub, échange local du JWT contre un jeton temporaire.
Pour le déploiement cloud, OIDC est mon choix par défaut. La configuration est un peu plus lourde au départ — ensuite, plus rien à maintenir côté credentials.
4. Protection supply chain — retour sur l’incident tj-actions
Revenons à tj-actions/changed-files. Comment c’est arrivé ? Qu’en tirer ?
Déroulement
En mars 2025, des attaquants ont obtenu les droits de mainteneur sur le dépôt tj-actions (fuite de credentials ou compromission de compte — enquête en cours). Dans la v45, un script malveillant lisait toutes les variables d’environnement et secrets, puis les envoyait vers un serveur contrôlé par l’attaquant.
L’analyse Semgrep indique que tous les workflows utilisant tj-actions/changed-files@v45 étaient touchés — secrets GitHub ou OIDC : dès que l’action voit les variables d’environnement, elles peuvent être exfiltrées.
Le rapport Unit42 (Palo Alto) cite plus de 23 000 dépôts utilisant cette action, dont des forks de projets connus.
Leçons
L’incident a mis en lumière :
- Les tags de version d’Actions ne sont pas fiables — un attaquant peut faire pointer un tag vers un commit malveillant
- Une Action tierce accède à vos secrets — une compromission expose tout
- Les logs historiques peuvent garder des traces — même après correction, d’anciens runs peuvent contenir des fuites
Votre checklist
Si vous avez déjà utilisé tj-actions/changed-files, parcourez point par point :
□ Vérifier les logs workflow : pas de secrets dans la sortie
□ Rotation de tous les secrets potentiellement exposés (API keys, tokens, etc.)
□ Épingler l'action sur un SHA de commit, pas sur un numéro de version
□ Auditer la provenance des mainteneurs des autres Actions tierces
□ Envisager Dependabot ou Renovate pour surveiller les mises à jour d'Actions
Pour les projets non encore compromis, le pinning SHA est la mesure la plus importante. Moins lisible qu’un tag, mais seule protection fiable contre la modification de tag.
Par ailleurs, la feuille de route sécurité GitHub 2026 évoque une direction importante : séparer les droits de contribution au code et la gestion des credentials. Des contrôles plus fins pourraient limiter les secrets accessibles aux Actions tierces — bonne nouvelle, mais pour l’instant la défense reste entre vos mains.
Conclusion
La gestion des Secrets GitHub Actions n’est pas un problème technique insurmontable — c’est une pratique de sécurité à entretenir. En résumé :
Architecture : Repository Secrets pour le perso, Environment Secrets pour le multi-env, Organization Secrets pour le partage d’équipe.
Sécurité : épinglage SHA, passage explicite, rotation régulière — les trois priorités.
Cloud : OIDC en premier choix — pas de stockage de secrets, pas de rotation de clés statiques.
Supply chain : limiter l’accès des Actions tierces aux secrets, auditer les mainteneurs.
Après tj-actions, ma routine : toutes les Actions épinglées par SHA, déploiements cloud en OIDC, audit mensuel des secrets. Deux semaines pour mettre en place, puis faible coût de maintenance.
Si vous n’avez pas encore fait ces vérifications, lancez la checklist de cet article aujourd’hui. Prévenir coûte bien moins cher que réparer.
Configurer un déploiement GitHub Actions OIDC sans clé
Configurer l'authentification OIDC pour AWS et déployer sans stocker de credentials statiques
⏱️ Estimated time: 30 min
- 1
Step 1: Créer un IAM Identity Provider
Dans la console IAM AWS, créez un fournisseur d'identité :
• Provider URL : https://token.actions.githubusercontent.com
• Audience : sts.amazonaws.com
• Notez l'ARN du Provider généré - 2
Step 2: Créer un IAM Role et la politique de confiance
Créez un IAM Role limité à votre dépôt GitHub :
```json
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::ACCOUNT_ID:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
"token.actions.githubusercontent.com:sub": "repo:OWNER/REPO:ref:refs/heads/main"
}
}
}]
}
```
• Remplacez ACCOUNT_ID par votre ID de compte AWS
• Remplacez OWNER/REPO par votre dépôt GitHub
• Vous pouvez retirer :ref:refs/heads/main pour autoriser toutes les branches - 3
Step 3: Configurer le workflow pour OIDC
Demandez un jeton OIDC dans le workflow GitHub Actions :
```yaml
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
id-token: write # requis pour le jeton OIDC
contents: read
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::ACCOUNT_ID:role/GitHubActionsRole
aws-region: us-east-1
- run: aws s3 sync ./dist s3://my-bucket
```
• id-token: write est une permission obligatoire
• Aucun secrets.AWS_ACCESS_KEY_ID n'est nécessaire - 4
Step 4: Tester et valider
Exécutez le workflow pour valider OIDC :
• Vérifiez dans les logs que l'authentification réussit
• Confirmez que role-to-assume est correct
• Validez l'accès aux ressources AWS sans credential statique
• Testez l'opération cible (sync S3, push ECR, etc.)
FAQ
Quelle différence entre Repository Secrets et Environment Secrets ?
Comment utiliser les secrets en toute sécurité dans un workflow ?
• Passage explicite : injecter via env, ne pas inliner ${{ secrets.XXX }}
• Moindre privilège : ne passer qu'aux steps nécessaires ; pour GITHUB_TOKEN, permissions: contents: read
• Rotation régulière : tous les 30-90 jours ; pour le cloud, OIDC évite la rotation de clés statiques
Qu'est-ce que OIDC ? Pourquoi est-ce plus sûr que les secrets classiques ?
Comment se protéger des attaques supply chain (comme tj-actions) ?
• Épingler les Actions sur le SHA du commit, pas sur un tag de version
• Limiter les secrets aux seules Actions de confiance
• Auditer la provenance des mainteneurs des Actions tierces
• Faire tourner Dependabot ou Renovate pour surveiller les mises à jour
Les secrets peuvent-ils apparaître dans les logs ?
Dans quels cas utiliser Organization Secrets ?
8 min de lecture · Publié le: 18 avr. 2026 · Mis à jour le: 27 juil. 2026
Guide complet GitHub Actions
Si vous arrivez depuis la recherche, le plus rapide est de passer à l’article précédent ou suivant de cette série.
Précédent
Stratégies de déploiement GitHub Actions : du VPS aux plateformes cloud
Trois stratégies de déploiement avec GitHub Actions : SSH vers VPS, hébergement managé (Vercel/Cloudflare/Netlify) et architecture hybride, avec workflows complets et guide de dépannage
Partie 6 sur 10
Suivant
Runners auto-hébergés GitHub Actions : guide complet pour un déploiement privé
Guide complet du déploiement de runners auto-hébergés GitHub Actions en environnement privé : analyse des changements tarifaires 2026, comparaison de trois schémas de déploiement, bonnes pratiques de sécurité et solution open source Runner Fleet.
Partie 8 sur 10



Commentaires
Connectez-vous avec GitHub pour laisser un commentaire