La règle tient en une phrase : ce qui part en production doit être exactement ce qui a été validé en staging. Cela interdit de reconstruire entre les deux étapes, et impose de désigner l'artefact par son digest plutôt que par un tag. Cette page construit la chaîne de promotion correspondante, avec la vérification de provenance juste avant le déploiement.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Identifier l'anti-pattern du rebuild par environnement et ce qu'il casse
- Promouvoir une image par son digest immuable, de staging à production
- Transporter un artefact de fichiers entre deux workflows distincts
- Vérifier l'attestation de l'artefact avant de le déployer
- Paramétrer un redéploiement manuel sur une version précise
L'anti-pattern : reconstruire à chaque étape
Section intitulée « L'anti-pattern : reconstruire à chaque étape »Le pipeline naïf reconstruit à chaque cible, parce que c'est ce que produit l'assemblage successif de workflows :
# ❌ Chaque environnement reconstruit son imagejobs: deploy-staging: environment: staging steps: - run: docker build -t mon-app:staging . && ./deploy.sh staging
deploy-production: needs: deploy-staging environment: production steps: - run: docker build -t mon-app:prod . && ./deploy.sh productionTrois garanties tombent d'un coup. D'abord la reproductibilité : les deux builds résolvent leurs dépendances à des instants différents, donc rien ne prouve qu'ils produisent le même binaire. Ensuite la valeur de la validation : les tests de staging ont porté sur une image que plus personne ne possède. Enfin la provenance : l'attestation signée lors de la release ne couvre pas l'image reconstruite, la vérification en production échouera ou, pire, sera retirée du pipeline pour que ça passe.
Le digest, seule adresse fiable
Section intitulée « Le digest, seule adresse fiable »Un tag de conteneur est mutable : mon-app:1.4.2 peut être republié. Un
digest est l'empreinte cryptographique du contenu, de la forme
sha256:... : il désigne un et un seul assemblage d'octets.
mon-app:latest -> peut changer à tout momentmon-app:1.4.2 -> peut être republié sur le même tagmon-app@sha256:9f2a... -> immuable, c'est l'artefact lui-mêmeLa chaîne de promotion transporte donc un digest, jamais un tag. Le tag reste utile pour les humains, il ne sert jamais de référence d'exécution.
Construire une fois, exposer le digest
Section intitulée « Construire une fois, exposer le digest »Le job de build publie l'image et exporte son digest comme sortie de job. C'est ce que fait déjà le workflow de release du dépôt de référence, et c'est ce qui rend la suite possible :
jobs: build: runs-on: ubuntu-24.04 timeout-minutes: 20 permissions: packages: write # push vers GHCR id-token: write # OIDC keyless pour la provenance attestations: write # attestation native outputs: digest: ${{ steps.build.outputs.digest }} env: IMAGE: ghcr.io/mon-org/mon-app steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - name: Login GHCR uses: docker/login-action@06fb636fac595d6fb4b28a5dfcb21a6f5091859c # v4.5.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build et push id: build uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 with: context: . push: true tags: ${{ env.IMAGE }}:${{ github.sha }} - name: Attestation de provenance uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1 with: subject-name: ${{ env.IMAGE }} subject-digest: ${{ steps.build.outputs.digest }} push-to-registry: trueLa ligne qui compte est outputs.digest. Sans elle, les jobs suivants n'ont
aucun moyen de désigner l'image produite autrement que par un tag, et toute la
chaîne retombe sur une référence mutable.
Promouvoir vers staging, puis vers production
Section intitulée « Promouvoir vers staging, puis vers production »Les deux jobs de déploiement consomment le même digest, et se distinguent uniquement par leur environnement. Le job de production dépend du staging, ce qui garantit l'ordre, et déclenche les règles de protection de son environnement.
deploy-staging: needs: build runs-on: ubuntu-24.04 environment: name: staging url: https://staging.mon-app.example.com env: IMAGE: ghcr.io/mon-org/mon-app DIGEST: ${{ needs.build.outputs.digest }} steps: - name: Vérifier la provenance avant de déployer env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: gh attestation verify "oci://${IMAGE}@${DIGEST}" --owner mon-org - name: Déployer sur staging run: ./deploy.sh "${IMAGE}@${DIGEST}" env: DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
deploy-production: needs: [build, deploy-staging] runs-on: ubuntu-24.04 environment: name: production # approbation requise sur cet environnement url: https://mon-app.example.com env: IMAGE: ghcr.io/mon-org/mon-app DIGEST: ${{ needs.build.outputs.digest }} steps: - name: Vérifier la provenance avant de déployer env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: gh attestation verify "oci://${IMAGE}@${DIGEST}" --owner mon-org - name: Déployer en production run: ./deploy.sh "${IMAGE}@${DIGEST}" env: DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}Le DEPLOY_TOKEN n'est pas le même dans les deux jobs : chacun lit celui de
son environnement. Le workflow, lui, est écrit une seule fois.
Transporter un artefact de fichiers entre workflows
Section intitulée « Transporter un artefact de fichiers entre workflows »Tout ne se déploie pas sous forme d'image. Pour un site statique, un binaire ou
une archive, l'artefact voyage via upload-artifact puis download-artifact.
À l'intérieur d'un même workflow, le téléchargement est direct. D'un workflow
à l'autre, il faut désigner l'exécution d'origine et fournir un jeton :
- name: Récupérer l'artefact du workflow de build uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: dist path: dist/ run-id: ${{ github.event.workflow_run.id }} github-token: ${{ secrets.GITHUB_TOKEN }}Deux limites à garder en tête. Les artefacts ont une rétention par défaut de 90 jours : au-delà, l'artefact promu n'existe plus, et un rollback tardif devra passer par un rebuild. Et un artefact n'est pas signé par le simple fait d'être stocké : c'est l'attestation produite au build qui le rend vérifiable, pas son emplacement.
Redéployer une version précise
Section intitulée « Redéployer une version précise »La chaîne automatique couvre le cas nominal. Il faut aussi pouvoir choisir la version déployée, pour rejouer une mise en production ou revenir en arrière. Un déclencheur manuel paramétré par le digest suffit :
on: workflow_dispatch: inputs: digest: description: "Digest de l'image à déployer (sha256:...)" required: true type: string
permissions: {}
jobs: deploy: runs-on: ubuntu-24.04 environment: name: production url: https://mon-app.example.com permissions: contents: read env: IMAGE: ghcr.io/mon-org/mon-app DIGEST: ${{ inputs.digest }} steps: - name: Vérifier la provenance du digest demandé env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: gh attestation verify "oci://${IMAGE}@${DIGEST}" --owner mon-org - name: Déployer run: ./deploy.sh "${IMAGE}@${DIGEST}" env: DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}L'entrée est une donnée fournie par un humain, donc non fiable par
principe : elle transite par un bloc env: et n'est jamais interpolée
directement dans la commande. La vérification d'attestation joue ici un second
rôle, elle refuse un digest qui ne proviendrait pas de vos workflows.
La chaîne complète
Section intitulée « La chaîne complète »-
Construire une fois et publier l'artefact avec son attestation de provenance.
-
Exporter le digest comme sortie de job, seule référence transportée ensuite.
-
Déployer sur staging en vérifiant la provenance juste avant.
-
Attendre l'approbation portée par les règles de l'environnement de production.
-
Déployer le même digest en production, après une nouvelle vérification.
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
À retenir
Section intitulée « À retenir »- Reconstruire entre staging et production casse la reproductibilité, annule la valeur des tests et invalide l'attestation de provenance.
- Le digest
sha256:...est la seule adresse immuable d'un artefact ; le tag sert aux humains, jamais à l'exécution. - Le job de build exporte son digest en sortie, et tous les jobs de déploiement consomment cette même valeur.
- Un workflow de déploiement unique sert les deux cibles : c'est l'
environment:qui change les secrets lus. - Vérifier l'attestation juste avant chaque déploiement, y compris en production, parce qu'une approbation a pu durer longtemps.
- Les artefacts de fichiers se transportent entre workflows avec
run-idet un jeton, et disparaissent après 90 jours par défaut. - Le redéploiement manuel se paramètre par le digest, traité comme une entrée non fiable, via
env:.
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Rollback et concurrence : Rejouer le digest précédent, et empêcher deux déploiements de se marcher dessus.
- Lab : promouvoir un déploiement approuvé : La chaîne complète montée sur le dépôt de référence, image attestée comprise.
- Partager entre jobs (Artifacts) : Le mécanisme de transport détaillé, quand l'artefact promu est un jeu de fichiers plutôt qu'une image.