Les variables et secrets permettent de paramétrer vos workflows sans hardcoder les valeurs. Les variables servent aux configurations non sensibles ; les secrets aux données confidentielles — tokens, mots de passe, clés API.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Distinguer variables et secrets et savoir lequel utiliser
- Définir des variables aux quatre niveaux : workflow, job, step, configuration
- Consommer un secret sans jamais l'exposer dans les logs
- Comprendre le
GITHUB_TOKENet les secrets d'environnement - Faire circuler des valeurs entre steps et entre jobs via les outputs
- Éviter les pièges : injection par
GITHUB_ENV, secret vide sur les forks
Ce guide suppose que vous savez déjà écrire un workflow. Sinon, commencez par Workflows GitHub Actions.
Variables vs Secrets
Section intitulée « Variables vs Secrets »Variables et secrets se déclarent au même endroit et s'utilisent de façon similaire, mais leur traitement diffère radicalement : une variable s'affiche en clair, un secret est masqué par GitHub partout où il apparaîtrait. Le choix de l'un ou l'autre dépend donc de la sensibilité de la donnée.
| Aspect | Variables | Secrets |
|---|---|---|
| Visibilité | En clair dans les logs | Masquées (***) |
| Modification | UI, API, CLI | UI, API, CLI |
| Accès | ${{ vars.NAME }} | ${{ secrets.NAME }} |
| Usage | Config, feature flags | Tokens, passwords, keys |
Variables d'environnement
Section intitulée « Variables d'environnement »Une variable d'environnement rend une valeur disponible pour les commandes shell d'un step. GitHub Actions permet de les déclarer à plusieurs niveaux de portée, et propose aussi des variables de configuration persistantes.
Niveaux de définition
Section intitulée « Niveaux de définition »Les variables peuvent être définies à quatre niveaux, du plus large au plus précis. Le niveau le plus précis surcharge les niveaux supérieurs.
# 1. Niveau workflowenv: GLOBAL_VAR: 'workflow-level'
jobs: build: # 2. Niveau job env: JOB_VAR: 'job-level' runs-on: ubuntu-24.04 steps: # 3. Niveau step - name: Étape avec variables env: STEP_VAR: 'step-level' run: | echo "Global : $GLOBAL_VAR" echo "Job : $JOB_VAR" echo "Step : $STEP_VAR"Variables de configuration (vars)
Section intitulée « Variables de configuration (vars) »Les variables de configuration (vars) sont définies dans les paramètres
du repository, de l'environnement ou de l'organisation. Elles
persistent d'une exécution à l'autre — idéales pour une URL d'API ou un
feature flag.
steps: - name: Lire une variable de configuration run: | echo "Environnement : ${{ vars.ENVIRONMENT }}" echo "URL API : ${{ vars.API_URL }}" echo "Feature flag : ${{ vars.ENABLE_NEW_FEATURE }}"Configurer une variable :
- Repository → Settings → Secrets and variables → Actions
- Onglet « Variables »
- « New repository variable »
Variables dynamiques (outputs)
Section intitulée « Variables dynamiques (outputs) »Quand une valeur n'est connue qu'à l'exécution — version, hash de commit,
horodatage — un step la calcule et l'écrit dans $GITHUB_OUTPUT. Les steps
suivants la lisent via steps.<id>.outputs.<nom>.
steps: - name: Générer les variables id: vars run: | echo "version=$(cat VERSION)" >> "$GITHUB_OUTPUT" echo "sha_short=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT" echo "timestamp=$(date +%Y%m%d%H%M%S)" >> "$GITHUB_OUTPUT"
- name: Réutiliser les variables run: | echo "Version : ${{ steps.vars.outputs.version }}" echo "SHA : ${{ steps.vars.outputs.sha_short }}" echo "Horodatage : ${{ steps.vars.outputs.timestamp }}"Variables entre jobs
Section intitulée « Variables entre jobs »Pour qu'un job transmette une valeur à un autre, il l'expose dans son bloc
outputs:. Le job destinataire le déclare en needs: et lit la valeur via
needs.<job>.outputs.<nom>.
jobs: setup: runs-on: ubuntu-24.04 outputs: version: ${{ steps.version.outputs.value }} steps: - name: Déterminer la version id: version run: echo "value=1.2.3" >> "$GITHUB_OUTPUT"
build: needs: setup runs-on: ubuntu-24.04 steps: - run: echo "Build de la version ${{ needs.setup.outputs.version }}"Un secret est une valeur confidentielle que GitHub chiffre au repos et
masque dans les logs. Cette section couvre leurs niveaux de portée, la
façon de les consommer et le cas particulier du GITHUB_TOKEN.
Types de secrets
Section intitulée « Types de secrets »Comme les variables, les secrets se déclarent à trois portées. Plus la portée est large, plus la surface d'exposition augmente — choisissez la plus restreinte qui répond au besoin.
| Niveau | Accès | Configuration |
|---|---|---|
| Repository | Ce repo uniquement | Settings → Secrets |
| Environment | Jobs avec cet environment | Settings → Environments |
| Organization | Tous les repos de l'org | Org Settings → Secrets |
Utiliser un secret
Section intitulée « Utiliser un secret »Un secret se consomme toujours via un bloc env: : la valeur devient une
variable d'environnement que le script lit sans jamais apparaître dans la
définition du workflow. Certaines actions acceptent aussi un jeton comme
paramètre with:.
steps: # Méthode recommandée : passer le secret par un bloc env: - name: Déployer l'application env: API_KEY: ${{ secrets.API_KEY }} run: ./deploy.sh
# Certaines actions attendent un jeton comme paramètre with: - name: Cloner un dépôt privé uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: repository: mon-org/depot-prive token: ${{ secrets.REPO_ACCESS_TOKEN }} persist-credentials: falseLe secret GITHUB_TOKEN
Section intitulée « Le secret GITHUB_TOKEN »Le GITHUB_TOKEN est un secret automatique, généré pour chaque exécution
de workflow et révoqué à la fin. Inutile de le créer : il est toujours
disponible dans secrets.GITHUB_TOKEN.
steps: - name: Récupérer le code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false
- name: Créer une issue env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | gh issue create \ --title "Incident détecté par le workflow" \ --body "Issue ouverte automatiquement par la CI."Ses permissions dépendent de la configuration du workflow et du repository —
déclarez-les explicitement avec un bloc permissions:.
Secrets d'environnement
Section intitulée « Secrets d'environnement »Pour les déploiements, les secrets liés à un environment sont plus sûrs : ils ne sont injectés que dans les jobs rattachés à cet environnement, et peuvent exiger une approbation manuelle avant exécution.
jobs: deploy-staging: environment: staging runs-on: ubuntu-24.04 steps: - name: Déployer en staging env: # Secret spécifique à l'environnement "staging" DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }} run: ./deploy.sh
deploy-production: environment: production runs-on: ubuntu-24.04 steps: - name: Déployer en production env: # Secret différent, rattaché à l'environnement "production" DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }} run: ./deploy.shBonnes pratiques de sécurité
Section intitulée « Bonnes pratiques de sécurité »Quelques réflexes évitent les fuites les plus courantes. Le principe de fond —
ne jamais interpoler un secret dans un run: — est introduit dans
Sécuriser GitHub Actions : les secrets ;
les pratiques ci-dessous l'appliquent au quotidien.
Ne jamais exposer un secret
Section intitulée « Ne jamais exposer un secret »Un secret interpolé directement dans une commande apparaît dans les logs —
même masqué, une transformation suffit à le révéler. Passez-le par env: et
laissez le script le lire.
# ❌ DANGEREUX : secret visible dans les logs- run: echo ${{ secrets.API_KEY }}- run: curl -H "Authorization: Bearer ${{ secrets.NPM_TOKEN }}" https://registry.npmjs.org/-/whoami
# ❌ DANGEREUX : secret copié dans une variable shell affichée- run: | KEY=${{ secrets.API_KEY }} echo "Clé utilisée : $KEY"
# ✅ SÉCURISÉ : passer le secret via env, le script le lit- name: Appeler l'API env: API_KEY: ${{ secrets.API_KEY }} run: ./script.shMasquer les valeurs dynamiques
Section intitulée « Masquer les valeurs dynamiques »Une valeur sensible générée à l'exécution n'est pas connue de GitHub : elle
n'est donc pas masquée automatiquement. La commande ::add-mask:: l'ajoute à
la liste des valeurs censurées dans les logs.
- name: Générer le jeton id: token run: | TOKEN=$(./generate-token.sh) echo "::add-mask::$TOKEN" echo "token=$TOKEN" >> "$GITHUB_OUTPUT"
- name: Utiliser le jeton env: TOKEN: ${{ steps.token.outputs.token }} run: ./use-token.shLimiter l'accès aux secrets
Section intitulée « Limiter l'accès aux secrets »Les secrets ne sont pas exposés aux PR de forks — un contributeur externe ne peut pas les exfiltrer. Pour les jobs sensibles, vérifiez explicitement que l'exécution ne vient pas d'un fork.
jobs: build: # Ce job s'exécute sur le dépôt principal : secrets disponibles runs-on: ubuntu-24.04 steps: - name: Étape avec secret env: SECRET: ${{ secrets.MY_SECRET }} run: echo "Secret disponible"
build-fork: # On vérifie que la PR ne provient pas d'un fork if: github.event.pull_request.head.repo.fork == false runs-on: ubuntu-24.04 steps: - name: Étape conditionnée env: SECRET: ${{ secrets.MY_SECRET }} run: echo "Origine sûre, secret disponible"Planifier la rotation des secrets
Section intitulée « Planifier la rotation des secrets »Un secret qui ne tourne jamais finit par fuiter. Un workflow planifié peut
rappeler l'échéance en ouvrant une issue. Comme il écrit dans le dépôt, il
déclare la permission minimale issues: write — rien de plus.
name: Rappel de rotation des secrets
on: schedule: - cron: '0 9 1 */3 *' # Le 1er de chaque trimestre, à 9h
permissions: {}
jobs: remind: runs-on: ubuntu-24.04 permissions: issues: write steps: - name: Créer l'issue de rappel env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | gh issue create \ --title "Rotation des secrets requise" \ --body "Il est temps de faire tourner les secrets du dépôt."Patterns courants
Section intitulée « Patterns courants »Variables et secrets se combinent dans quelques schémas récurrents : configuration par environnement, feature flags, secrets multi-lignes et chargement depuis un fichier.
Configuration par environnement
Section intitulée « Configuration par environnement »Une matrice sur les environnements permet de déployer staging et production
avec le même job, chacun recevant ses propres vars et secrets.
env: APP_NAME: my-app
jobs: deploy: runs-on: ubuntu-24.04 strategy: matrix: environment: [staging, production] environment: ${{ matrix.environment }} steps: - name: Déployer sur la cible env: TARGET_ENV: ${{ matrix.environment }} # Variables spécifiques à l'environnement (définies dans vars) API_URL: ${{ vars.API_URL }} REPLICAS: ${{ vars.REPLICAS }} # Secret spécifique à l'environnement DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }} run: | echo "Déploiement de $APP_NAME vers $TARGET_ENV" echo "URL API : $API_URL" echo "Replicas : $REPLICAS"Feature flags
Section intitulée « Feature flags »Des variables de configuration servent d'interrupteurs de build : on les
lit via env:, puis le script compose les options en conséquence.
jobs: build: runs-on: ubuntu-24.04 steps: - name: Récupérer le code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false
- name: Construire avec les options actives env: ENABLE_FEATURE_X: ${{ vars.ENABLE_FEATURE_X }} ENABLE_FEATURE_Y: ${{ vars.ENABLE_FEATURE_Y }} run: | BUILD_FLAGS="" if [ "$ENABLE_FEATURE_X" = "true" ]; then BUILD_FLAGS="$BUILD_FLAGS --feature-x" fi if [ "$ENABLE_FEATURE_Y" = "true" ]; then BUILD_FLAGS="$BUILD_FLAGS --feature-y" fi npm run build -- $BUILD_FLAGSSecrets multi-lignes
Section intitulée « Secrets multi-lignes »Une clé SSH, un certificat ou un JSON se collent tels quels dans
l'interface GitHub. Dans le workflow, on les écrit dans un fichier via env:,
avec des permissions strictes.
- name: Préparer la clé SSH env: SSH_KEY: ${{ secrets.SSH_PRIVATE_KEY }} run: | mkdir -p ~/.ssh echo "$SSH_KEY" > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa
- name: Préparer les identifiants GCP env: GCP_CREDENTIALS: ${{ secrets.GCP_CREDENTIALS }} run: | echo "$GCP_CREDENTIALS" > /tmp/gcp-key.json chmod 600 /tmp/gcp-key.json export GOOGLE_APPLICATION_CREDENTIALS=/tmp/gcp-key.jsonCharger des variables depuis un fichier
Section intitulée « Charger des variables depuis un fichier »Un fichier .env versionné peut alimenter $GITHUB_ENV. Mais ne le copiez
jamais en aveugle : un contenu non maîtrisé peut y glisser des variables
sensibles (PATH, NODE_OPTIONS) et faire exécuter du code au runner.
# ❌ Dangereux : tout le fichier injecté sans contrôle- run: cat .env >> "$GITHUB_ENV"
# ✅ Sûr : lire explicitement les clés attendues- name: Charger la version depuis le fichier run: | VERSION=$(grep '^VERSION=' .env | cut -d= -f2) echo "APP_VERSION=$VERSION" >> "$GITHUB_ENV"Alimenter GITHUB_ENV avec des données non fiables est une injection
d'environnement — le mécanisme et ses parades sont détaillés dans
Contexts et expressions.
Débogage
Section intitulée « Débogage »Quand une variable arrive vide ou inattendue, deux réflexes aident : inspecter l'environnement du runner et activer les logs détaillés.
Inspecter les variables disponibles
Section intitulée « Inspecter les variables disponibles »Un step de diagnostic affiche le contexte GitHub et les variables
d'environnement. Les valeurs du contexte transitent par env: — c'est aussi la
règle pour ne pas exposer le runner à une injection.
- name: Inspecter l'environnement env: GH_REPOSITORY: ${{ github.repository }} GH_REF: ${{ github.ref }} GH_EVENT: ${{ github.event_name }} ALL_VARS: ${{ toJSON(vars) }} run: | echo "=== Contexte GitHub ===" echo "Dépôt : $GH_REPOSITORY" echo "Ref : $GH_REF" echo "Événement : $GH_EVENT" echo "=== Variables de configuration ===" echo "$ALL_VARS" echo "=== Variables d'environnement ===" env | sortActiver les logs détaillés
Section intitulée « Activer les logs détaillés »Deux variables font passer GitHub Actions en mode verbeux : l'une pour le runner, l'autre pour les steps. Réservez-les au diagnostic — elles alourdissent fortement les logs.
env: ACTIONS_RUNNER_DEBUG: true # Logs détaillés du runner ACTIONS_STEP_DEBUG: true # Logs détaillés des stepsErreurs courantes
Section intitulée « Erreurs courantes »Trois confusions reviennent sans cesse autour des variables et des secrets. Les reconnaître évite des heures de débogage.
Secret non disponible
Section intitulée « Secret non disponible »Sur une PR de fork, les secrets sont volontairement vides. Un step qui en dépend doit le vérifier plutôt que d'échouer silencieusement.
# ❌ Le secret est vide sur les PR de forks- run: echo "Secret : ${{ secrets.MY_SECRET }}" # Résultat : "Secret : " (vide)
# ✅ Vérifier la présence avant utilisation- name: Vérifier la présence du secret if: secrets.MY_SECRET != '' run: echo "Secret disponible"Variable non définie
Section intitulée « Variable non définie »Une variable de configuration absente renvoie une chaîne vide, pas une
erreur. Prévoyez une valeur par défaut avec l'opérateur ||.
# ❌ Chaîne vide si vars.OPTIONAL n'existe pas- run: echo "${{ vars.OPTIONAL }}"
# ✅ Valeur par défaut explicite- run: echo "${{ vars.OPTIONAL || 'default-value' }}"Confondre env et vars
Section intitulée « Confondre env et vars »vars désigne la configuration du repository (onglet Settings) ; env
désigne une variable d'environnement déclarée dans le workflow. Les deux
notations se ressemblent mais ne pointent pas vers la même chose.
# vars = configuration repository (définie dans Settings)- run: echo "${{ vars.API_URL }}"
# env = variable d'environnement du workflowenv: MY_VAR: valuesteps: - run: echo "${{ env.MY_VAR }}" - run: echo "$MY_VAR" # Accès shell directÀ retenir
Section intitulée « À retenir »- Variables = configuration non sensible, visible dans les logs ; secrets = données confidentielles, masquées automatiquement par GitHub.
- Les variables se définissent à quatre niveaux — workflow, job, step, configuration (
vars) — le plus précis l'emporte. - Un secret se consomme toujours via un bloc
env:, jamais interpolé en clair dansrun:ni passé en argument visible. - Le
GITHUB_TOKENest généré automatiquement pour chaque exécution ; déclarez ses permissions explicitement. - Ne jamais faire
cat fichier >> $GITHUB_ENVen aveugle : un contenu non maîtrisé injecte des variables et peut exécuter du code. - Sur les PR de forks, les secrets sont vides — préférez les secrets d'environnement et conditionnez les jobs sensibles.
Prochaines étapes
Section intitulée « Prochaines étapes »Pour la référence complète, consultez la documentation officielle sur les variables.