{"id":545,"date":"2026-03-21T20:11:54","date_gmt":"2026-03-21T19:11:54","guid":{"rendered":"https:\/\/secure-pipelines.com\/?p=545"},"modified":"2026-03-24T12:59:16","modified_gmt":"2026-03-24T11:59:16","slug":"lab-secure-build-pipeline-tekton-tekton-chains","status":"publish","type":"post","link":"https:\/\/secure-pipelines.com\/fr\/ci-cd-security\/lab-secure-build-pipeline-tekton-tekton-chains\/","title":{"rendered":"Lab : Impl\u00e9mentation d&rsquo;un Pipeline de Build S\u00e9curis\u00e9 avec Tekton et Tekton Chains"},"content":{"rendered":"<h2>Pr\u00e9sentation<\/h2>\n<p>Tekton est un puissant framework open source natif de Kubernetes permettant de cr\u00e9er des syst\u00e8mes d&rsquo;int\u00e9gration continue et de livraison continue (CI\/CD). Il s&rsquo;ex\u00e9cute sous forme de Custom Resource Definitions (CRDs) sur n&rsquo;importe quel cluster Kubernetes, vous permettant de d\u00e9finir des pipelines sous forme de YAML d\u00e9claratif, portables d&rsquo;un environnement \u00e0 l&rsquo;autre.<\/p>\n<p><strong>Tekton Chains<\/strong> est un projet compl\u00e9mentaire qui ajoute automatiquement la s\u00e9curit\u00e9 de la cha\u00eene d&rsquo;approvisionnement \u00e0 vos pipelines Tekton. Une fois install\u00e9, Chains surveille les TaskRuns termin\u00e9s, signe automatiquement leurs r\u00e9sultats \u00e0 l&rsquo;aide de Cosign ou d&rsquo;autres outils de signature, et g\u00e9n\u00e8re des <a href=\"https:\/\/secure-pipelines.com\/fr\/ci-cd-security\/artifact-provenance-attestations-slsa-in-toto-2\/\">attestations de provenance SLSA<\/a> \u2014 le tout sans n\u00e9cessiter aucune modification de vos d\u00e9finitions de pipeline existantes.<\/p>\n<p>Dans ce lab pratique, vous allez :<\/p>\n<ul>\n<li>D\u00e9ployer Tekton Pipelines et Tekton Chains sur un cluster Kubernetes local<\/li>\n<li>Configurer Chains pour signer automatiquement les artefacts et g\u00e9n\u00e9rer la provenance in-toto<\/li>\n<li>Construire une image de conteneur via un Pipeline Tekton<\/li>\n<li>V\u00e9rifier la signature g\u00e9n\u00e9r\u00e9e automatiquement et la provenance SLSA<\/li>\n<li>Ajouter une \u00e9tape d&rsquo;analyse de vuln\u00e9rabilit\u00e9s au pipeline<\/li>\n<li>Explorer la signature sans cl\u00e9 avec Sigstore Fulcio<\/li>\n<li>Appliquer des politiques d&rsquo;images sign\u00e9es au moment du d\u00e9ploiement<\/li>\n<\/ul>\n<p>\u00c0 la fin de ce lab, vous disposerez d&rsquo;un pipeline de build s\u00e9curis\u00e9 enti\u00e8rement fonctionnel qui produit des images de conteneurs sign\u00e9es et attest\u00e9es avec une provenance v\u00e9rifiable \u2014 atteignant automatiquement la conformit\u00e9 SLSA Level 2.<\/p>\n<h2>Pr\u00e9requis<\/h2>\n<p>Avant de commencer ce lab, assurez-vous que les outils suivants sont install\u00e9s sur votre poste de travail :<\/p>\n<ul>\n<li><strong>Cluster Kubernetes<\/strong> \u2014 Nous utiliserons <a href=\"https:\/\/kind.sigs.k8s.io\/\" target=\"_blank\" rel=\"noopener\">kind<\/a> (Kubernetes in Docker) pour un cluster local. Alternativement, minikube fonctionne \u00e9galement.<\/li>\n<li><strong>kubectl<\/strong> \u2014 L&rsquo;interface en ligne de commande Kubernetes, version 1.26 ou ult\u00e9rieure.<\/li>\n<li><strong>Helm<\/strong> \u2014 Le gestionnaire de paquets Kubernetes, version 3.x.<\/li>\n<li><strong>tkn<\/strong> \u2014 Le <a href=\"https:\/\/tekton.dev\/docs\/cli\/\" target=\"_blank\" rel=\"noopener\">CLI Tekton<\/a>, utilis\u00e9 pour interagir avec les ressources Tekton.<\/li>\n<li><strong>Cosign<\/strong> \u2014 Fait partie du <a href=\"https:\/\/secure-pipelines.com\/fr\/ci-cd-security\/signing-verifying-container-images-sigstore-cosign\/\">projet Sigstore<\/a>, utilis\u00e9 pour signer et v\u00e9rifier les images de conteneurs.<\/li>\n<li><strong>jq<\/strong> \u2014 Un processeur JSON en ligne de commande pour inspecter les charges utiles de provenance.<\/li>\n<li><strong>Un registre de conteneurs<\/strong> \u2014 Un registre vers lequel vous pouvez pousser des images, tel que GitHub Container Registry (GHCR) ou Docker Hub. Vous aurez besoin d&rsquo;un acc\u00e8s en \u00e9criture et d&rsquo;identifiants valides.<\/li>\n<\/ul>\n<p>Ce lab suppose une familiarit\u00e9 avec les bases de Kubernetes (pods, namespaces, configmaps) et les concepts g\u00e9n\u00e9raux de CI\/CD.<\/p>\n<h2>Mise en Place de l&rsquo;Environnement<\/h2>\n<h3>\u00c9tape 1 : Cr\u00e9er un Cluster kind<\/h3>\n<p>Commencez par cr\u00e9er un cluster Kubernetes neuf avec kind :<\/p>\n<pre><code>kind create cluster --name tekton-lab\nkubectl cluster-info --context kind-tekton-lab<\/code><\/pre>\n<p>Confirmez que le cluster est en cours d&rsquo;ex\u00e9cution :<\/p>\n<pre><code>kubectl get nodes\n# NAME                       STATUS   ROLES           AGE   VERSION\n# tekton-lab-control-plane   Ready    control-plane   30s   v1.31.0<\/code><\/pre>\n<h3>\u00c9tape 2 : Installer Tekton Pipelines<\/h3>\n<p>Installez la derni\u00e8re version de Tekton Pipelines :<\/p>\n<pre><code>kubectl apply --filename https:\/\/storage.googleapis.com\/tekton-releases\/pipeline\/latest\/release.yaml<\/code><\/pre>\n<p>Attendez que les pods Tekton Pipelines soient pr\u00eats :<\/p>\n<pre><code>kubectl get pods -n tekton-pipelines --watch<\/code><\/pre>\n<p>Vous devriez voir les pods <code>tekton-pipelines-controller<\/code> et <code>tekton-pipelines-webhook<\/code> en cours d&rsquo;ex\u00e9cution :<\/p>\n<pre><code>NAME                                           READY   STATUS    RESTARTS   AGE\ntekton-pipelines-controller-7f6b9b5b95-xk2rj   1\/1     Running   0          45s\ntekton-pipelines-webhook-6c4f8b7d4f-m9nlp      1\/1     Running   0          45s<\/code><\/pre>\n<h3>\u00c9tape 3 : Installer Tekton Chains<\/h3>\n<p>Installez Tekton Chains dans son propre namespace :<\/p>\n<pre><code>kubectl apply --filename https:\/\/storage.googleapis.com\/tekton-releases\/chains\/latest\/release.yaml<\/code><\/pre>\n<p>V\u00e9rifiez que Chains est en cours d&rsquo;ex\u00e9cution :<\/p>\n<pre><code>kubectl get pods -n tekton-chains\n# NAME                                        READY   STATUS    RESTARTS   AGE\n# tekton-chains-controller-5f4b7c8d6f-r7t2x   1\/1     Running   0          30s<\/code><\/pre>\n<p>\u00c0 ce stade, Tekton Pipelines et Tekton Chains sont tous deux en cours d&rsquo;ex\u00e9cution sur votre cluster.<\/p>\n<h2>Exercice 1 : Configurer Tekton Chains pour la Signature avec Cosign<\/h2>\n<p>Tekton Chains a besoin d&rsquo;une cl\u00e9 de signature et d&rsquo;une configuration pour savoir comment et o\u00f9 stocker les signatures et les attestations. Dans cet exercice, vous allez g\u00e9n\u00e9rer une paire de cl\u00e9s Cosign et configurer Chains pour utiliser le stockage OCI avec le format d&rsquo;attestation in-toto.<\/p>\n<h3>G\u00e9n\u00e9rer une Paire de Cl\u00e9s Cosign<\/h3>\n<p>Cosign peut g\u00e9n\u00e9rer une paire de cl\u00e9s et la stocker directement comme un Secret Kubernetes dans le namespace <code>tekton-chains<\/code> :<\/p>\n<pre><code>cosign generate-key-pair k8s:\/\/tekton-chains\/signing-secrets<\/code><\/pre>\n<p>Vous serez invit\u00e9 \u00e0 entrer un mot de passe pour la cl\u00e9 priv\u00e9e. Pour ce lab, vous pouvez appuyer sur Entr\u00e9e pour le laisser vide. Cosign cr\u00e9e un Secret nomm\u00e9 <code>signing-secrets<\/code> contenant la cl\u00e9 priv\u00e9e, la cl\u00e9 publique et le mot de passe.<\/p>\n<p>V\u00e9rifiez que le secret a \u00e9t\u00e9 cr\u00e9\u00e9 :<\/p>\n<pre><code>kubectl get secret signing-secrets -n tekton-chains\n# NAME              TYPE     DATA   AGE\n# signing-secrets   Opaque   3      10s<\/code><\/pre>\n<h3>Configurer le Stockage et le Format de Chains<\/h3>\n<p>Ensuite, configurez Chains pour stocker les signatures dans le registre OCI aux c\u00f4t\u00e9s de l&rsquo;image et pour g\u00e9n\u00e9rer la provenance au format in-toto :<\/p>\n<pre><code>kubectl patch configmap chains-config -n tekton-chains \\\n  -p='{\"data\":{\"artifacts.oci.storage\":\"oci\",\"artifacts.taskrun.format\":\"in-toto\",\"artifacts.taskrun.storage\":\"oci\"}}'<\/code><\/pre>\n<p>Cette configuration indique \u00e0 Chains de :<\/p>\n<ul>\n<li><strong>artifacts.oci.storage: oci<\/strong> \u2014 Stocker les signatures d&rsquo;artefacts OCI dans le registre OCI<\/li>\n<li><strong>artifacts.taskrun.format: in-toto<\/strong> \u2014 G\u00e9n\u00e9rer les attestations au format <a href=\"https:\/\/in-toto.io\/\" target=\"_blank\" rel=\"noopener\">in-toto<\/a>, qui est le standard pour la provenance SLSA<\/li>\n<li><strong>artifacts.taskrun.storage: oci<\/strong> \u2014 Stocker les attestations de TaskRun dans le registre OCI<\/li>\n<\/ul>\n<h3>Red\u00e9marrer le Contr\u00f4leur Chains<\/h3>\n<p>Apr\u00e8s avoir modifi\u00e9 la configuration, red\u00e9marrez le contr\u00f4leur Chains pour qu&rsquo;il prenne en compte les nouveaux param\u00e8tres :<\/p>\n<pre><code>kubectl rollout restart deployment tekton-chains-controller -n tekton-chains\nkubectl rollout status deployment tekton-chains-controller -n tekton-chains<\/code><\/pre>\n<h3>Fonctionnement de Chains<\/h3>\n<p>Avec Chains configur\u00e9, voici ce qui se passe automatiquement chaque fois qu&rsquo;un TaskRun se termine :<\/p>\n<ol>\n<li>Le contr\u00f4leur Chains d\u00e9tecte le TaskRun termin\u00e9.<\/li>\n<li>Il inspecte les r\u00e9sultats du TaskRun pour trouver les r\u00e9f\u00e9rences d&rsquo;images OCI (sp\u00e9cifiquement les r\u00e9sultats nomm\u00e9s <code>IMAGE_URL<\/code> et <code>IMAGE_DIGEST<\/code>).<\/li>\n<li>Il signe l&rsquo;image \u00e0 l&rsquo;aide de la cl\u00e9 Cosign stock\u00e9e dans le Secret <code>signing-secrets<\/code>.<\/li>\n<li>Il g\u00e9n\u00e8re une attestation de provenance in-toto capturant les d\u00e9tails du build.<\/li>\n<li>Il pousse la signature et l&rsquo;attestation vers le registre OCI.<\/li>\n<li>Il annote le TaskRun avec <code>chains.tekton.dev\/signed=true<\/code>.<\/li>\n<\/ol>\n<p>Rien de tout cela ne n\u00e9cessite de modification de vos Tasks ou Pipelines.<\/p>\n<h2>Exercice 2 : Cr\u00e9er un Pipeline de Build<\/h2>\n<p>Vous allez maintenant cr\u00e9er un Pipeline Tekton qui clone un d\u00e9p\u00f4t Git et construit une image de conteneur \u00e0 l&rsquo;aide de Kaniko. Commencez par configurer les identifiants du registre pour que Tekton puisse pousser les images.<\/p>\n<h3>Configurer les Identifiants du Registre<\/h3>\n<p>Cr\u00e9ez un Secret Kubernetes avec vos identifiants de registre. Remplacez les valeurs de substitution par les d\u00e9tails r\u00e9els de votre registre :<\/p>\n<pre><code>export REGISTRY_SERVER=ghcr.io\nexport REGISTRY_USER=your-username\nexport REGISTRY_PASSWORD=your-token\n\nkubectl create secret docker-registry registry-credentials \\\n  --docker-server=$REGISTRY_SERVER \\\n  --docker-username=$REGISTRY_USER \\\n  --docker-password=$REGISTRY_PASSWORD\n\nkubectl patch serviceaccount default -p '{\"secrets\": [{\"name\": \"registry-credentials\"}]}'<\/code><\/pre>\n<h3>Cr\u00e9er la Task de Build<\/h3>\n<p>Cr\u00e9ez un fichier nomm\u00e9 <code>build-task.yaml<\/code>. Cette Task accepte une URL de d\u00e9p\u00f4t Git, un nom d&rsquo;image cible, et utilise Kaniko pour construire et pousser l&rsquo;image :<\/p>\n<pre><code>apiVersion: tekton.dev\/v1\nkind: Task\nmetadata:\n  name: git-clone-and-build\nspec:\n  params:\n    - name: repo-url\n      type: string\n      description: The Git repository URL to clone\n    - name: image\n      type: string\n      description: The image reference to build and push (e.g., ghcr.io\/user\/app:tag)\n  results:\n    - name: IMAGE_URL\n      description: The image URL that was built\n    - name: IMAGE_DIGEST\n      description: The digest of the built image\n  workspaces:\n    - name: source\n  steps:\n    - name: clone\n      image: alpine\/git:2.43.0\n      script: |\n        #!\/usr\/bin\/env sh\n        set -eu\n        git clone $(params.repo-url) $(workspaces.source.path)\/src\n        echo \"Repository cloned successfully\"\n    - name: build-and-push\n      image: gcr.io\/kaniko-project\/executor:latest\n      args:\n        - --dockerfile=$(workspaces.source.path)\/src\/Dockerfile\n        - --context=$(workspaces.source.path)\/src\n        - --destination=$(params.image)\n        - --digest-file=$(results.IMAGE_DIGEST.path)\n      securityContext:\n        runAsUser: 0\n    - name: write-url\n      image: alpine:3.19\n      script: |\n        #!\/usr\/bin\/env sh\n        set -eu\n        echo -n \"$(params.image)\" &gt; \"$(results.IMAGE_URL.path)\"\n        echo \"Image URL written: $(params.image)\"<\/code><\/pre>\n<p>Appliquez la Task :<\/p>\n<pre><code>kubectl apply -f build-task.yaml<\/code><\/pre>\n<h3>Cr\u00e9er la Task d&rsquo;Analyse de Vuln\u00e9rabilit\u00e9s (Pour Utilisation Ult\u00e9rieure)<\/h3>\n<p>Cr\u00e9ez <code>vuln-scan-task.yaml<\/code> \u2014 vous l&rsquo;ajouterez au pipeline dans un exercice ult\u00e9rieur :<\/p>\n<pre><code>apiVersion: tekton.dev\/v1\nkind: Task\nmetadata:\n  name: vulnerability-scan\nspec:\n  params:\n    - name: image\n      type: string\n      description: The image reference to scan\n  steps:\n    - name: scan\n      image: anchore\/grype:latest\n      args:\n        - $(params.image)\n        - --fail-on\n        - critical\n        - --output\n        - table<\/code><\/pre>\n<h3>Cr\u00e9er le Pipeline<\/h3>\n<p>Cr\u00e9ez <code>build-pipeline.yaml<\/code> qui encha\u00eene les \u00e9tapes de clonage et de build :<\/p>\n<pre><code>apiVersion: tekton.dev\/v1\nkind: Pipeline\nmetadata:\n  name: secure-build\nspec:\n  params:\n    - name: repo-url\n      type: string\n    - name: image\n      type: string\n  workspaces:\n    - name: shared-workspace\n  tasks:\n    - name: build\n      taskRef:\n        name: git-clone-and-build\n      params:\n        - name: repo-url\n          value: $(params.repo-url)\n        - name: image\n          value: $(params.image)\n      workspaces:\n        - name: source\n          workspace: shared-workspace<\/code><\/pre>\n<p>Appliquez le Pipeline :<\/p>\n<pre><code>kubectl apply -f build-pipeline.yaml<\/code><\/pre>\n<h3>Ex\u00e9cuter le Pipeline<\/h3>\n<p>Cr\u00e9ez un PipelineRun pour ex\u00e9cuter le pipeline. Remplacez la r\u00e9f\u00e9rence de l&rsquo;image par votre registre :<\/p>\n<pre><code>apiVersion: tekton.dev\/v1\nkind: PipelineRun\nmetadata:\n  generateName: secure-build-run-\nspec:\n  pipelineRef:\n    name: secure-build\n  params:\n    - name: repo-url\n      value: \"https:\/\/github.com\/GoogleContainerTools\/kaniko.git\"\n    - name: image\n      value: \"ghcr.io\/your-username\/tekton-lab:v1\"\n  workspaces:\n    - name: shared-workspace\n      volumeClaimTemplate:\n        spec:\n          accessModes:\n            - ReadWriteOnce\n          resources:\n            requests:\n              storage: 1Gi<\/code><\/pre>\n<p>Enregistrez ceci sous <code>pipelinerun.yaml<\/code> et cr\u00e9ez-le :<\/p>\n<pre><code>kubectl create -f pipelinerun.yaml<\/code><\/pre>\n<p>Surveillez l&rsquo;ex\u00e9cution du pipeline :<\/p>\n<pre><code>tkn pipelinerun logs -f --last\n# [build : clone] Cloning into '\/workspace\/source\/src'...\n# [build : clone] Repository cloned successfully\n# [build : build-and-push] INFO[0001] Resolved base image golang:1.22\n# [build : build-and-push] ...\n# [build : build-and-push] INFO[0045] Pushing image to ghcr.io\/your-username\/tekton-lab:v1\n# [build : write-url] Image URL written: ghcr.io\/your-username\/tekton-lab:v1<\/code><\/pre>\n<p>Le build devrait se terminer avec succ\u00e8s. Vous pouvez \u00e9galement v\u00e9rifier le statut du PipelineRun :<\/p>\n<pre><code>tkn pipelinerun list\n# NAME                     STARTED        DURATION   STATUS\n# secure-build-run-x7k2p   1 minute ago   1m 15s     Succeeded<\/code><\/pre>\n<h2>Exercice 3 : V\u00e9rifier la Signature Automatique<\/h2>\n<p>Une fois le PipelineRun termin\u00e9, Tekton Chains d\u00e9tecte automatiquement le TaskRun compl\u00e9t\u00e9, signe l&rsquo;image construite et annote le TaskRun. Tout cela se passe en arri\u00e8re-plan \u2014 aucune modification du pipeline n&rsquo;est n\u00e9cessaire.<\/p>\n<h3>Attendre la Signature par Chains<\/h3>\n<p>Chains traite les TaskRuns termin\u00e9s de mani\u00e8re asynchrone. Attendez quelques instants, puis v\u00e9rifiez les annotations du TaskRun :<\/p>\n<pre><code># Obtenir le nom du TaskRun \u00e0 partir du PipelineRun\nTASKRUN=$(kubectl get taskrun -l tekton.dev\/pipeline=secure-build -o name --sort-by=.metadata.creationTimestamp | tail -1)\necho $TASKRUN\n\n# V\u00e9rifier si Chains l'a sign\u00e9\nkubectl get $TASKRUN -o jsonpath='{.metadata.annotations.chains\\.tekton\\.dev\\\/signed}'<\/code><\/pre>\n<p>La sortie devrait \u00eatre :<\/p>\n<pre><code>true<\/code><\/pre>\n<p>Si elle est encore vide, attendez quelques secondes et r\u00e9essayez \u2014 Chains a besoin de temps pour traiter la signature.<\/p>\n<h3>V\u00e9rifier la Signature avec Cosign<\/h3>\n<p>V\u00e9rifiez maintenant la signature de l&rsquo;image en utilisant la cl\u00e9 publique de la paire de cl\u00e9s Cosign que vous avez g\u00e9n\u00e9r\u00e9e pr\u00e9c\u00e9demment :<\/p>\n<pre><code>cosign verify \\\n  --key k8s:\/\/tekton-chains\/signing-secrets \\\n  ghcr.io\/your-username\/tekton-lab:v1<\/code><\/pre>\n<p>Vous devriez voir une sortie confirmant que la v\u00e9rification a r\u00e9ussi :<\/p>\n<pre><code>Verification for ghcr.io\/your-username\/tekton-lab:v1 --\nThe following checks were performed on each of these signatures:\n  - The cosign claims were validated\n  - The signatures were verified against the specified public key\n\n[{\"critical\":{\"identity\":{\"docker-reference\":\"ghcr.io\/your-username\/tekton-lab\"},\"image\":{\"docker-manifest-digest\":\"sha256:abc123...\"},\"type\":\"cosign container image signature\"},\"optional\":{}}]<\/code><\/pre>\n<h3>Inspecter les Annotations du TaskRun<\/h3>\n<p>Chains annote le TaskRun avec des m\u00e9tadonn\u00e9es riches sur l&rsquo;op\u00e9ration de signature :<\/p>\n<pre><code>kubectl get $TASKRUN -o jsonpath='{.metadata.annotations}' | jq .<\/code><\/pre>\n<p>Les annotations cl\u00e9s incluent :<\/p>\n<pre><code>{\n  \"chains.tekton.dev\/signed\": \"true\",\n  \"chains.tekton.dev\/transparency\": \"https:\/\/rekor.sigstore.dev\/api\/v1\/log\/entries?logIndex=...\",\n  \"chains.tekton.dev\/signature-taskrun-...\": \"...\"\n}<\/code><\/pre>\n<p>L&rsquo;annotation <code>chains.tekton.dev\/signed=true<\/code> confirme que Chains a trait\u00e9 et sign\u00e9 ce TaskRun avec succ\u00e8s. Si un journal de transparence est configur\u00e9, vous verrez \u00e9galement une r\u00e9f\u00e9rence vers une entr\u00e9e du journal Rekor.<\/p>\n<h2>Exercice 4 : Inspecter la Provenance SLSA<\/h2>\n<p>Au-del\u00e0 des simples signatures, Tekton Chains g\u00e9n\u00e8re des attestations de provenance SLSA compl\u00e8tes. Ces attestations d\u00e9crivent <em>comment<\/em> l&rsquo;artefact a \u00e9t\u00e9 construit \u2014 quelle source a \u00e9t\u00e9 utilis\u00e9e, quelles \u00e9tapes de build ont \u00e9t\u00e9 ex\u00e9cut\u00e9es et quels outils ont \u00e9t\u00e9 impliqu\u00e9s.<\/p>\n<h3>R\u00e9cup\u00e9rer l&rsquo;Attestation de Provenance<\/h3>\n<p>Utilisez Cosign pour v\u00e9rifier et r\u00e9cup\u00e9rer l&rsquo;attestation in-toto :<\/p>\n<pre><code>cosign verify-attestation \\\n  --key k8s:\/\/tekton-chains\/signing-secrets \\\n  --type slsaprovenance \\\n  ghcr.io\/your-username\/tekton-lab:v1 | jq -r '.payload' | base64 -d | jq .<\/code><\/pre>\n<h3>Comprendre la Structure de la Provenance<\/h3>\n<p>L&rsquo;attestation de provenance suit le format in-toto Statement avec un pr\u00e9dicat SLSA Provenance. Voici une analyse des champs cl\u00e9s :<\/p>\n<pre><code>{\n  \"_type\": \"https:\/\/in-toto.io\/Statement\/v0.1\",\n  \"predicateType\": \"https:\/\/slsa.dev\/provenance\/v0.2\",\n  \"subject\": [\n    {\n      \"name\": \"ghcr.io\/your-username\/tekton-lab\",\n      \"digest\": {\n        \"sha256\": \"abc123def456...\"\n      }\n    }\n  ],\n  \"predicate\": {\n    \"builder\": {\n      \"id\": \"https:\/\/tekton.dev\/chains\/v2\"\n    },\n    \"buildType\": \"tekton.dev\/v1beta1\/TaskRun\",\n    \"invocation\": {\n      \"configSource\": {},\n      \"parameters\": {\n        \"repo-url\": \"https:\/\/github.com\/GoogleContainerTools\/kaniko.git\",\n        \"image\": \"ghcr.io\/your-username\/tekton-lab:v1\"\n      }\n    },\n    \"buildConfig\": {\n      \"steps\": [\n        {\n          \"entryPoint\": \"...\",\n          \"arguments\": null,\n          \"environment\": {\n            \"container\": \"clone\",\n            \"image\": \"alpine\/git:2.43.0@sha256:...\"\n          }\n        },\n        {\n          \"entryPoint\": \"...\",\n          \"environment\": {\n            \"container\": \"build-and-push\",\n            \"image\": \"gcr.io\/kaniko-project\/executor:latest@sha256:...\"\n          }\n        }\n      ]\n    },\n    \"materials\": [\n      {\n        \"uri\": \"oci:\/\/alpine\/git:2.43.0\",\n        \"digest\": { \"sha256\": \"...\" }\n      },\n      {\n        \"uri\": \"oci:\/\/gcr.io\/kaniko-project\/executor:latest\",\n        \"digest\": { \"sha256\": \"...\" }\n      }\n    ]\n  }\n}<\/code><\/pre>\n<p>Passons en revue chaque champ :<\/p>\n<ul>\n<li><strong>subject<\/strong> \u2014 L&rsquo;artefact qui a \u00e9t\u00e9 produit, identifi\u00e9 par son URL de registre et son condens\u00e9 SHA-256. C&rsquo;est ce dont la provenance <em>t\u00e9moigne<\/em>.<\/li>\n<li><strong>builder.id<\/strong> \u2014 Identifie le syst\u00e8me de build. Tekton Chains d\u00e9finit cette valeur \u00e0 <code>https:\/\/tekton.dev\/chains\/v2<\/code>.<\/li>\n<li><strong>buildConfig.steps<\/strong> \u2014 Enregistre chaque \u00e9tape qui a \u00e9t\u00e9 ex\u00e9cut\u00e9e dans le TaskRun, y compris les images de conteneurs exactes utilis\u00e9es (\u00e9pingl\u00e9es par condens\u00e9).<\/li>\n<li><strong>materials<\/strong> \u2014 Liste les artefacts d&rsquo;entr\u00e9e consomm\u00e9s pendant le build, tels que les images de base. Chaque mat\u00e9riau inclut un condens\u00e9 pour la reproductibilit\u00e9.<\/li>\n<li><strong>invocation.parameters<\/strong> \u2014 Capture les param\u00e8tres pass\u00e9s au TaskRun, montrant exactement quelles entr\u00e9es ont pilot\u00e9 le build.<\/li>\n<\/ul>\n<p>Ces donn\u00e9es de provenance satisfont les exigences du <strong>SLSA Level 2<\/strong> : le processus de build est d\u00e9fini dans un service de build (Tekton), et la provenance est g\u00e9n\u00e9r\u00e9e automatiquement par Tekton Chains (et non par le script de build lui-m\u00eame). La provenance est sign\u00e9e, fournissant une preuve de non-alt\u00e9ration.<\/p>\n<h2>Exercice 5 : Ajouter une Task d&rsquo;Analyse de Vuln\u00e9rabilit\u00e9s<\/h2>\n<p>Un pipeline s\u00e9curis\u00e9 ne devrait pas seulement signer les artefacts, mais aussi v\u00e9rifier qu&rsquo;ils sont exempts de vuln\u00e9rabilit\u00e9s connues avant le d\u00e9ploiement. Dans cet exercice, vous allez ajouter une \u00e9tape d&rsquo;analyse de vuln\u00e9rabilit\u00e9s Grype au pipeline.<\/p>\n<h3>Appliquer la Task d&rsquo;Analyse<\/h3>\n<p>Appliquez la Task d&rsquo;analyse de vuln\u00e9rabilit\u00e9s que vous avez cr\u00e9\u00e9e pr\u00e9c\u00e9demment :<\/p>\n<pre><code>kubectl apply -f vuln-scan-task.yaml<\/code><\/pre>\n<h3>Mettre \u00e0 Jour le Pipeline<\/h3>\n<p>Mettez \u00e0 jour <code>build-pipeline.yaml<\/code> pour inclure l&rsquo;analyse de vuln\u00e9rabilit\u00e9s apr\u00e8s l&rsquo;\u00e9tape de build :<\/p>\n<pre><code>apiVersion: tekton.dev\/v1\nkind: Pipeline\nmetadata:\n  name: secure-build\nspec:\n  params:\n    - name: repo-url\n      type: string\n    - name: image\n      type: string\n  workspaces:\n    - name: shared-workspace\n  tasks:\n    - name: build\n      taskRef:\n        name: git-clone-and-build\n      params:\n        - name: repo-url\n          value: $(params.repo-url)\n        - name: image\n          value: $(params.image)\n      workspaces:\n        - name: source\n          workspace: shared-workspace\n    - name: vulnerability-scan\n      runAfter:\n        - build\n      taskRef:\n        name: vulnerability-scan\n      params:\n        - name: image\n          value: $(params.image)<\/code><\/pre>\n<p>Appliquez le pipeline mis \u00e0 jour :<\/p>\n<pre><code>kubectl apply -f build-pipeline.yaml<\/code><\/pre>\n<h3>Tester avec une Image Vuln\u00e9rable<\/h3>\n<p>Pour d\u00e9montrer la d\u00e9tection de vuln\u00e9rabilit\u00e9s par l&rsquo;analyse, cr\u00e9ez un Dockerfile qui utilise une image de base connue comme vuln\u00e9rable et poussez un d\u00e9p\u00f4t ou modifiez les param\u00e8tres en cons\u00e9quence. Si l&rsquo;image contient des vuln\u00e9rabilit\u00e9s critiques, Grype fera \u00e9chouer l&rsquo;\u00e9tape :<\/p>\n<pre><code>tkn pipelinerun logs -f --last\n# [vulnerability-scan : scan] NAME             INSTALLED  FIXED-IN  TYPE  VULNERABILITY   SEVERITY\n# [vulnerability-scan : scan] libcrypto3       3.0.12     3.0.13    apk   CVE-2024-0727   Critical\n# [vulnerability-scan : scan] 1 critical vulnerability found\n# [vulnerability-scan : scan] ERROR: failed to pass severity threshold\n#\n# TaskRun failed: step \"scan\" exited with code 1<\/code><\/pre>\n<p>Le pipeline \u00e9choue correctement \u00e0 l&rsquo;\u00e9tape d&rsquo;analyse, emp\u00eachant une image vuln\u00e9rable d&rsquo;\u00eatre promue.<\/p>\n<h3>Tester avec une Image Corrig\u00e9e<\/h3>\n<p>Ex\u00e9cutez maintenant le pipeline avec un d\u00e9p\u00f4t contenant une image de base \u00e0 jour. Lorsqu&rsquo;aucune vuln\u00e9rabilit\u00e9 critique n&rsquo;est trouv\u00e9e, l&rsquo;analyse r\u00e9ussit :<\/p>\n<pre><code>tkn pipelinerun logs -f --last\n# [vulnerability-scan : scan] No critical vulnerabilities found\n# PipelineRun completed successfully<\/code><\/pre>\n<p>Le flux du pipeline est d\u00e9sormais : <strong>git-clone \u2192 build-push \u2192 vulnerability-scan<\/strong>. Seules les images qui passent l&rsquo;analyse de vuln\u00e9rabilit\u00e9s sont sign\u00e9es par Tekton Chains, car Chains ne traite que les TaskRuns <em>r\u00e9ussis<\/em>.<\/p>\n<h2>Exercice 6 : Signature sans Cl\u00e9 avec Fulcio (Avanc\u00e9)<\/h2>\n<p>La gestion de cl\u00e9s de signature \u00e0 longue dur\u00e9e de vie introduit de la complexit\u00e9 op\u00e9rationnelle et des risques de s\u00e9curit\u00e9. <strong>Fulcio<\/strong> de Sigstore fournit une signature sans cl\u00e9 en \u00e9mettant des certificats de courte dur\u00e9e li\u00e9s \u00e0 une identit\u00e9 OIDC. Dans cet exercice, vous allez configurer Tekton Chains pour utiliser la signature sans cl\u00e9.<\/p>\n<h3>Mettre \u00e0 Jour la Configuration de Chains<\/h3>\n<p>Modifiez la configuration de Chains pour activer la signature sans cl\u00e9 :<\/p>\n<pre><code>kubectl patch configmap chains-config -n tekton-chains -p='{\"data\":{\n  \"signers.x509.fulcio.enabled\": \"true\",\n  \"signers.x509.fulcio.address\": \"https:\/\/fulcio.sigstore.dev\",\n  \"transparency.enabled\": \"true\",\n  \"transparency.url\": \"https:\/\/rekor.sigstore.dev\"\n}}'<\/code><\/pre>\n<p>Vous devez \u00e9galement supprimer ou renommer le secret <code>signing-secrets<\/code> existant pour que Chains bascule en mode sans cl\u00e9 :<\/p>\n<pre><code>kubectl delete secret signing-secrets -n tekton-chains<\/code><\/pre>\n<p>Red\u00e9marrez le contr\u00f4leur Chains :<\/p>\n<pre><code>kubectl rollout restart deployment tekton-chains-controller -n tekton-chains<\/code><\/pre>\n<h3>Configurer OIDC pour Chains<\/h3>\n<p>Chains a besoin d&rsquo;un jeton OIDC pour s&rsquo;authentifier aupr\u00e8s de Fulcio. Sur un service Kubernetes g\u00e9r\u00e9 (GKE, EKS, AKS), vous pouvez utiliser l&rsquo;identit\u00e9 de charge de travail (workload identity). Pour un cluster kind local, vous pouvez configurer Spiffe\/SPIRE ou utiliser un fournisseur OIDC ambiant. La documentation de Tekton Chains fournit des instructions de configuration pour chaque environnement.<\/p>\n<p>Pour une configuration de production GKE, le compte de service est automatiquement f\u00e9d\u00e9r\u00e9 :<\/p>\n<pre><code># Exemple : liaison d'identit\u00e9 de charge de travail GKE\ngcloud iam service-accounts add-iam-policy-binding \\\n  tekton-chains-sa@your-project.iam.gserviceaccount.com \\\n  --role roles\/iam.workloadIdentityUser \\\n  --member \"serviceAccount:your-project.svc.id.goog[tekton-chains\/tekton-chains-controller]\"<\/code><\/pre>\n<h3>Ex\u00e9cuter le Pipeline avec la Signature sans Cl\u00e9<\/h3>\n<p>D\u00e9clenchez un nouveau PipelineRun :<\/p>\n<pre><code>kubectl create -f pipelinerun.yaml<\/code><\/pre>\n<p>Apr\u00e8s l&rsquo;ach\u00e8vement, v\u00e9rifiez avec la v\u00e9rification sans cl\u00e9 en sp\u00e9cifiant l&rsquo;identit\u00e9 attendue et l&rsquo;\u00e9metteur OIDC :<\/p>\n<pre><code>cosign verify \\\n  --certificate-identity \"https:\/\/kubernetes.io\/namespaces\/tekton-chains\/serviceaccounts\/tekton-chains-controller\" \\\n  --certificate-oidc-issuer \"https:\/\/your-oidc-issuer\" \\\n  ghcr.io\/your-username\/tekton-lab:v2<\/code><\/pre>\n<p>La v\u00e9rification repose d\u00e9sormais sur la cha\u00eene de certificats de Fulcio plut\u00f4t que sur une paire de cl\u00e9s statique. Cette approche \u00e9limine enti\u00e8rement la gestion des cl\u00e9s : chaque op\u00e9ration de signature obtient un certificat frais et de courte dur\u00e9e, et l&rsquo;\u00e9v\u00e9nement de signature est enregistr\u00e9 dans le journal de transparence Rekor pour l&rsquo;auditabilit\u00e9.<\/p>\n<h2>Exercice 7 : Appliquer les Images Sign\u00e9es au D\u00e9ploiement<\/h2>\n<p>Signer les images n&rsquo;est utile que si vous <em>appliquez<\/em> la v\u00e9rification des signatures au moment du d\u00e9ploiement. Dans cet exercice, vous allez d\u00e9ployer le policy-controller de Sigstore pour rejeter toute image de conteneur qui ne poss\u00e8de pas de signature Tekton Chains valide.<\/p>\n<h3>Installer le Policy Controller de Sigstore<\/h3>\n<pre><code>helm repo add sigstore https:\/\/sigstore.github.io\/helm-charts\nhelm repo update\n\nhelm install policy-controller sigstore\/policy-controller \\\n  --namespace cosign-system \\\n  --create-namespace \\\n  --set webhook.configMapName=policy-controller-config<\/code><\/pre>\n<p>Attendez que le policy controller soit pr\u00eat :<\/p>\n<pre><code>kubectl get pods -n cosign-system --watch<\/code><\/pre>\n<h3>Cr\u00e9er une Politique d&rsquo;Image<\/h3>\n<p>Cr\u00e9ez une <code>ClusterImagePolicy<\/code> qui exige que les images soient sign\u00e9es par votre cl\u00e9 Tekton Chains. Enregistrez ceci sous <code>image-policy.yaml<\/code> :<\/p>\n<pre><code>apiVersion: policy.sigstore.dev\/v1beta1\nkind: ClusterImagePolicy\nmetadata:\n  name: tekton-chains-signed\nspec:\n  images:\n    - glob: \"ghcr.io\/your-username\/**\"\n  authorities:\n    - key:\n        data: |\n          -----BEGIN PUBLIC KEY-----\n          YOUR_COSIGN_PUBLIC_KEY_HERE\n          -----END PUBLIC KEY-----\n      attestations:\n        - name: must-have-slsa-provenance\n          predicateType: \"https:\/\/slsa.dev\/provenance\/v0.2\"\n          policy:\n            type: cue\n            data: |\n              predicateType: \"https:\/\/slsa.dev\/provenance\/v0.2\"<\/code><\/pre>\n<p>Remplacez la cl\u00e9 publique par la cl\u00e9 publique Cosign que vous avez g\u00e9n\u00e9r\u00e9e pr\u00e9c\u00e9demment :<\/p>\n<pre><code># Extraire la cl\u00e9 publique\nkubectl get secret signing-secrets -n tekton-chains -o jsonpath='{.data.cosign\\.pub}' | base64 -d<\/code><\/pre>\n<p>Appliquez la politique :<\/p>\n<pre><code>kubectl apply -f image-policy.yaml<\/code><\/pre>\n<h3>Appliquer la Politique sur un Namespace<\/h3>\n<p>Labellisez un namespace pour activer l&rsquo;application de la politique :<\/p>\n<pre><code>kubectl create namespace secure-apps\nkubectl label namespace secure-apps policy.sigstore.dev\/include=true<\/code><\/pre>\n<h3>Test : D\u00e9ployer une Image Sign\u00e9e<\/h3>\n<p>D\u00e9ployez l&rsquo;image qui a \u00e9t\u00e9 sign\u00e9e par Tekton Chains :<\/p>\n<pre><code>kubectl run signed-app \\\n  --image=ghcr.io\/your-username\/tekton-lab:v1 \\\n  --namespace=secure-apps\n# pod\/signed-app created<\/code><\/pre>\n<p>Le d\u00e9ploiement r\u00e9ussit car l&rsquo;image poss\u00e8de une signature et une attestation de provenance valides.<\/p>\n<h3>Test : D\u00e9ployer une Image Non Sign\u00e9e<\/h3>\n<p>Essayez maintenant de d\u00e9ployer une image qui n&rsquo;a pas \u00e9t\u00e9 sign\u00e9e :<\/p>\n<pre><code>kubectl run unsigned-app \\\n  --image=ghcr.io\/your-username\/unsigned-image:latest \\\n  --namespace=secure-apps\n# Error from server (BadRequest): admission webhook \"policy.sigstore.dev\" denied the request:\n# validation failed: failed policy: tekton-chains-signed:\n# spec.containers[0].image ghcr.io\/your-username\/unsigned-image:latest\n# signature key validation failed for authority<\/code><\/pre>\n<p>Le webhook d&rsquo;admission rejette correctement l&rsquo;image non sign\u00e9e. Cela boucle la boucle : les images sont automatiquement sign\u00e9es pendant le build, et seules les images sign\u00e9es peuvent \u00eatre d\u00e9ploy\u00e9es.<\/p>\n<h2>Nettoyage<\/h2>\n<p>Lorsque vous avez termin\u00e9 le lab, nettoyez les ressources :<\/p>\n<pre><code># Supprimer Tekton Chains\nkubectl delete -f https:\/\/storage.googleapis.com\/tekton-releases\/chains\/latest\/release.yaml\n\n# Supprimer Tekton Pipelines\nkubectl delete -f https:\/\/storage.googleapis.com\/tekton-releases\/pipeline\/latest\/release.yaml\n\n# Supprimer le policy controller\nhelm uninstall policy-controller -n cosign-system\nkubectl delete namespace cosign-system\n\n# Supprimer le cluster kind\nkind delete cluster --name tekton-lab<\/code><\/pre>\n<h2>Points Cl\u00e9s \u00e0 Retenir<\/h2>\n<ul>\n<li><strong>Tekton Chains fournit une s\u00e9curit\u00e9 de la cha\u00eene d&rsquo;approvisionnement sans configuration.<\/strong> Une fois install\u00e9 et configur\u00e9, il signe automatiquement chaque r\u00e9sultat de TaskRun et g\u00e9n\u00e8re la provenance SLSA \u2014 sans aucune modification de pipeline requise.<\/li>\n<li><strong>La provenance SLSA relie les artefacts \u00e0 leur processus de build.<\/strong> L&rsquo;attestation in-toto enregistre exactement quelle source, quelles \u00e9tapes et quels outils ont produit un artefact, cr\u00e9ant une cha\u00eene de tra\u00e7abilit\u00e9 auditable.<\/li>\n<li><strong>La v\u00e9rification avec Cosign est simple.<\/strong> Une seule commande valide qu&rsquo;une image a \u00e9t\u00e9 sign\u00e9e par votre instance Tekton Chains et n&rsquo;a pas \u00e9t\u00e9 alt\u00e9r\u00e9e depuis.<\/li>\n<li><strong>La signature sans cl\u00e9 \u00e9limine la gestion des cl\u00e9s.<\/strong> En s&rsquo;int\u00e9grant avec Fulcio et Rekor, vous pouvez signer des artefacts avec des certificats de courte dur\u00e9e li\u00e9s \u00e0 l&rsquo;identit\u00e9 de la charge de travail, supprimant la charge de rotation et de s\u00e9curisation des cl\u00e9s \u00e0 longue dur\u00e9e de vie.<\/li>\n<li><strong>L&rsquo;analyse de vuln\u00e9rabilit\u00e9s comme porte de contr\u00f4le du pipeline emp\u00eache les d\u00e9ploiements non s\u00e9curis\u00e9s.<\/strong> L&rsquo;ajout de Grype ou d&rsquo;un scanner similaire comme \u00e9tape de pipeline garantit que seules les images exemptes de vuln\u00e9rabilit\u00e9s critiques passent \u00e0 la signature et au d\u00e9ploiement.<\/li>\n<li><strong>Le contr\u00f4le d&rsquo;admission applique la politique.<\/strong> L&rsquo;utilisation du policy-controller de Sigstore comme webhook d&rsquo;admission Kubernetes garantit que seules les images correctement sign\u00e9es et attest\u00e9es peuvent s&rsquo;ex\u00e9cuter dans votre cluster, bouclant la boucle de s\u00e9curit\u00e9 du build au d\u00e9ploiement.<\/li>\n<\/ul>\n<h2>Prochaines \u00c9tapes<\/h2>\n<p>Continuez \u00e0 renforcer vos connaissances en s\u00e9curit\u00e9 de la cha\u00eene d&rsquo;approvisionnement avec ces guides connexes :<\/p>\n<ul>\n<li><a href=\"https:\/\/secure-pipelines.com\/fr\/ci-cd-security\/artifact-provenance-attestations-slsa-in-toto-2\/\">Provenance des Artefacts et Attestations : De SLSA \u00e0 in-toto<\/a> \u2014 Plong\u00e9e approfondie dans le framework SLSA, les niveaux de provenance et la sp\u00e9cification d&rsquo;attestation in-toto.<\/li>\n<li><a href=\"https:\/\/secure-pipelines.com\/fr\/ci-cd-security\/signing-verifying-container-images-sigstore-cosign\/\">Signature et V\u00e9rification des Images de Conteneurs avec Sigstore et Cosign<\/a> \u2014 Guide complet sur Cosign, Fulcio et Rekor pour la signature et la v\u00e9rification des images de conteneurs.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Pr\u00e9sentation Tekton est un puissant framework open source natif de Kubernetes permettant de cr\u00e9er des syst\u00e8mes d&rsquo;int\u00e9gration continue et de livraison continue (CI\/CD). Il s&rsquo;ex\u00e9cute sous forme de Custom Resource Definitions (CRDs) sur n&rsquo;importe quel cluster Kubernetes, vous permettant de d\u00e9finir des pipelines sous forme de YAML d\u00e9claratif, portables d&rsquo;un environnement \u00e0 l&rsquo;autre. Tekton Chains &#8230; <a title=\"Lab : Impl\u00e9mentation d&rsquo;un Pipeline de Build S\u00e9curis\u00e9 avec Tekton et Tekton Chains\" class=\"read-more\" href=\"https:\/\/secure-pipelines.com\/fr\/ci-cd-security\/lab-secure-build-pipeline-tekton-tekton-chains\/\" aria-label=\"En savoir plus sur Lab : Impl\u00e9mentation d&rsquo;un Pipeline de Build S\u00e9curis\u00e9 avec Tekton et Tekton Chains\">Lire la suite<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[49,50],"tags":[],"post_folder":[],"class_list":["post-545","post","type-post","status-publish","format-standard","hentry","category-ci-cd-security","category-software-supply-chain"],"_links":{"self":[{"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/posts\/545","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/comments?post=545"}],"version-history":[{"count":2,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/posts\/545\/revisions"}],"predecessor-version":[{"id":585,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/posts\/545\/revisions\/585"}],"wp:attachment":[{"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/media?parent=545"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/categories?post=545"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/tags?post=545"},{"taxonomy":"post_folder","embeddable":true,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/post_folder?post=545"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}