Un client nous a contactés après avoir constaté que la clé SSH utilisée pour déployer son site de recette avait aussi accès à son serveur de production. Personne ne l’avait fait exprès : la clé avait été ajoutée une fois, dans les secrets globaux du dépôt GitHub, « pour aller plus vite », et jamais séparée ensuite. Ce genre de raccourci se paie cher le jour où un pipeline de recette mal configuré modifie la mauvaise base de données.
GitHub Actions propose depuis plusieurs années un mécanisme précis pour éviter ce genre de confusion : les environnements protégés (environments), avec leurs propres secrets et leurs propres règles de validation. C’est la structure que nous mettons en place systématiquement sur les projets qui déploient vers plusieurs cibles.
Secrets de dépôt contre secrets d’environnement
GitHub distingue deux niveaux de secrets : les secrets de dépôt (repository secrets), accessibles par tous les workflows du dépôt, et les secrets d’environnement, rattachés à un environnement nommé (staging, production) et accessibles uniquement aux jobs qui déclarent explicitement cet environnement.
La règle qu’on applique : aucun secret sensible ne reste au niveau du dépôt. Les identifiants de déploiement, les clés SSH, les jetons d’API vont systématiquement dans un environnement dédié. Un secret partagé entre recette et production, même par accident, annule tout l’intérêt de la séparation.
Déclarer les environnements dans le workflow
jobs:
deploiement-staging:
runs-on: ubuntu-latest
environment: staging
steps:
- uses: actions/checkout@v4
- name: Déployer vers la recette
env:
SSH_KEY: ${{ secrets.SSH_KEY_STAGING }}
run: |
echo "$SSH_KEY" > cle_deploiement
chmod 600 cle_deploiement
rsync -avz -e "ssh -i cle_deploiement" ./build/ deploiement@recette.exemple.test:/var/www/html/
deploiement-production:
needs: deploiement-staging
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- name: Déployer en production
env:
SSH_KEY: ${{ secrets.SSH_KEY_PRODUCTION }}
run: |
echo "$SSH_KEY" > cle_deploiement
chmod 600 cle_deploiement
rsync -avz -e "ssh -i cle_deploiement" ./build/ deploiement@prod.exemple.test:/var/www/html/
Chaque job référence son propre environnement via environment: staging ou environment: production, et récupère uniquement les secrets déclarés pour cet environnement précis. Le secret SSH_KEY_PRODUCTION reste invisible pour le job de recette.

Exiger une validation manuelle avant la production
Les environnements GitHub Actions permettent aussi d’ajouter des règles de protection (protection rules), configurables depuis les paramètres du dépôt. La plus utile pour un déploiement WordPress : exiger l’approbation manuelle d’un ou plusieurs réviseurs désignés avant que le job ne s’exécute réellement.
Une fois configuré, le workflow ci-dessus s’arrête après le déploiement en recette et attend qu’une personne autorisée clique sur « Approve and deploy » dans l’interface GitHub avant de lancer le job de production. Le pipeline reste automatisé de bout en bout, mais un humain garde la main sur le moment précis de la bascule en production.
Autres règles de protection utiles
- Restreindre l’environnement
productionà certaines branches seulement (typiquementmain), pour empêcher un déploiement accidentel depuis une branche de fonctionnalité ; - Ajouter un délai d’attente (wait timer) avant l’exécution, utile pour laisser une fenêtre d’annulation après une fusion de pull request ;
- Limiter la liste des réviseurs autorisés à approuver un déploiement, distincte de la liste des personnes qui peuvent pousser du code.
Une clé SSH de déploiement dédiée, jamais partagée
Au-delà de la séparation des secrets par environnement, chaque pipeline de déploiement devrait utiliser sa propre paire de clés SSH, générée spécifiquement pour cet usage et n’ayant accès qu’au serveur ciblé. Cela permet, en cas de compromission du dépôt ou de fuite d’un secret, de révoquer une seule clé sans devoir changer les accès de toute l’équipe.
ssh-keygen -t ed25519 -C "deploiement-ci-production" -f cle_deploiement_prod -N ""
# clé publique ajoutée à ~/.ssh/authorized_keys du serveur de production, avec des droits restreints
# clé privée collée dans le secret SSH_KEY_PRODUCTION de l'environnement GitHub
Une clé de déploiement ne devrait jamais avoir de mot de passe interactif ni servir à autre chose qu’au pipeline qui la porte. Le jour où elle fuite, on la révoque et on en génère une nouvelle, sans toucher aux accès des développeurs.
En résumé
Séparer les secrets par environnement, exiger une validation manuelle avant la production et dédier une clé de déploiement par pipeline ne sont pas des mesures compliquées à mettre en place. Elles demandent surtout de la discipline dès le premier jour, car revenir en arrière sur un dépôt où tout est mélangé — secrets globaux, clé unique partagée — demande de tout réorganiser sous pression, généralement après un incident.