Aller au contenu
English
Compte : non connecté, synchronisation possible Mon apprentissage
Selectionner le thème
English

Cosign : signer et vérifier vos images conteneurs

Par mis à jour le

Améliorer cette page

Cosign est l'outil en ligne de commande du projet Sigstore qui signe une image conteneur et vérifie cette signature avant de la déployer. Il répond à une question précise : l'image @sha256:… que le cluster s'apprête à lancer sort-elle bien de votre pipeline, sans modification ? Cette leçon s'adresse à un DevOps qui veut signer en CI et faire refuser par Kubernetes ce qui n'est pas signé.

Tout est mesuré le 1er octobre 2026 avec Cosign v3.1.3 : signature par clé sur un registre local, vérification keyless de deux images publiques, et une politique Kyverno 1.19.1 rejouée sur un cluster kind. Trois résultats structurent la leçon : cosign verify sort en code 10 quand aucune signature n'existe, en code 1 quand la signature vient d'une autre identité, et Kyverno refuse un pod dont la signature ne correspond pas.

  • Expliquer ce qu'une signature prouve, et le rôle de Fulcio et Rekor.
  • Installer Cosign en version épinglée, binaire vérifié par empreinte.
  • Signer une image par digest, avec une clé puis en keyless depuis GitHub Actions.
  • Vérifier une signature en contraignant l'identité du signataire, et lire ses codes de sortie.
  • Bloquer à l'admission Kubernetes les images non signées par la bonne CI.
  • Produire la preuve de SOCLE-REL-GEN-1, la signature des artefacts publiés, et de SOCLE-REL-VER-1, leur vérification avant usage.

Un registre n'authentifie personne : il stocke ce qu'on lui pousse et sert ce qu'on lui demande. Tant qu'aucune signature n'accompagne l'image, le cluster ne distingue pas l'artefact produit par votre pipeline d'un artefact substitué en chemin. Les deux sous-parties posent d'abord le risque, puis ce que la signature cryptographique apporte en retour.

Le problème : registres compromis et images altérées

Section intitulée « Le problème : registres compromis et images altérées »

Sans signature, rien ne prouve qu'une image order-service:2.1.0 a été construite par votre CI, qu'elle n'a pas été modifiée après le build, ni qu'elle correspond au code versionné. Le scénario redouté est simple : un attaquant obtient le droit de pousser dans le registre, remplace l'image sous le même tag, et les clusters la déploient en toute confiance. Signer par digest et vérifier avant le déploiement ferme cette porte.

Une signature Cosign établit trois propriétés, que la vérification contrôle toutes les trois. Aucune ne dit que l'image est sans vulnérabilité : une image signée peut contenir une faille, la signature prouve seulement d'où elle vient.

  1. Authenticité : l'image provient de l'identité déclarée, une clé ou un workflow de CI.
  2. Intégrité : l'image n'a pas changé depuis la signature, puisque la signature porte sur son digest.
  3. Traçabilité : en mode keyless, la signature est inscrite dans le journal public Rekor, consultable par tous.

Cosign fait partie de Sigstore, un projet de l'OpenSSF qui fournit une infrastructure publique de signature. Trois services travaillent avec lui, et le schéma montre leurs rôles : Cosign est le client, Fulcio délivre un certificat lié à une identité OIDC, Rekor enregistre chaque signature, et le registre garde la signature à côté de l'image.

Architecture Sigstore : un fournisseur OIDC (GitHub, GitLab, Google) fournit l'identité à Cosign, qui obtient un certificat éphémère de Fulcio, inscrit la signature dans le journal public Rekor et pousse la signature dans le registre OCI à côté de l'image.Fournisseur OIDCGitHub, GitLab, GoogleCosignsigne et vérifieFulciocertificat éphémèreRekorjournal publicRegistre OCIimage et signature
Source · SVG
Échap pour fermer, + et − pour zoomer, défilement pour se déplacer. 100 %
ComposantRôleGuide
CosignClient qui signe et vérifie images, fichiers et attestationsCette leçon
FulcioAutorité de certification qui émet un certificat de courte durée pour une identité OIDCFulcio
RekorJournal de transparence, en ajout seul, de toutes les signaturesRekor
Policy ControllerContrôleur d'admission Kubernetes du projet SigstoreSection Kubernetes ci-dessous

Cosign v3 privilégie le mode keyless : pas de clé privée à garder, mais une identité vérifiable. Le mode par clé reste utile hors ligne ou quand la politique de l'entreprise impose ses propres clés. Les deux modes produisent la même chose dans le registre, une signature liée au digest.

En mode keyless, Cosign génère une paire de clés éphémère, présente le jeton OIDC du job à Fulcio, qui renvoie un certificat valable dix minutes portant l'identité du workflow. La signature est inscrite dans Rekor, puis la clé privée est jetée. Le schéma suit l'échange dans l'ordre :

Séquence keyless : le job GitHub Actions remet son jeton OIDC à Cosign, qui l'envoie à Fulcio avec une clé publique éphémère ; Fulcio renvoie un certificat valable 10 minutes ; Cosign inscrit signature et certificat dans Rekor, reçoit une preuve d'inclusion, pousse le bundle lié au digest dans le registre OCI, puis jette la clé privée éphémère.Registre OCIRekorFulcioCosignJob GitHubActionsLa clé privéeéphémère estjetéeJeton OIDC du jobJeton et clé publiqueéphémèreCertificat valable 10minutesSignature et certificatPreuve d'inclusionBundle lié au digest de l'image
Source · SVG
Échap pour fermer, + et − pour zoomer, défilement pour se déplacer. 100 %

Ce que l'on vérifie ensuite n'est plus une clé mais une identité : le chemin du workflow (https://github.com/<org>/<dépôt>/.github/workflows/release.yml@refs/tags/v1.0.0) et l'émetteur du jeton (https://token.actions.githubusercontent.com). Aucun secret n'est à stocker, et une signature volée ne sert à rien hors de cette identité.

Les clés restent le bon choix pour un environnement isolé sans accès à l'instance publique de Sigstore, pour une politique qui impose des clés gérées par l'organisation, ou pour s'appuyer sur un KMS existant (AWS KMS, GCP KMS, Azure Key Vault, HashiCorp Vault). La clé privée devient alors un secret critique : sa fuite permet de signer n'importe quelle image.

Cosign est un binaire Go unique. Comme tout outil qui entre dans la chaîne de livraison, il s'installe en version fixée, et le binaire téléchargé se contrôle contre l'empreinte publiée avec la release. Mesuré pour la v3.1.3 : sha256sum --check répond cosign-linux-amd64: OK.

Fenêtre de terminal
VERSION=v3.1.3
curl -sSfLO "https://github.com/sigstore/cosign/releases/download/${VERSION}/cosign-linux-amd64"
curl -sSfLO "https://github.com/sigstore/cosign/releases/download/${VERSION}/cosign_checksums.txt"
sha256sum --check --ignore-missing cosign_checksums.txt
# cosign-linux-amd64: OK
sudo install -m 0755 cosign-linux-amd64 /usr/local/bin/cosign
cosign version | grep GitVersion
# GitVersion: v3.1.3

L'image officielle se fige par digest (ghcr.io/sigstore/cosign/cosign:v3.1.3@sha256:9e5c2f2edc34351160407ca3416c61855bdf9403c3c5936e0f0be7fc261611b8), et en CI l'action sigstore/cosign-installer accepte l'entrée cosign-release pour fixer la version installée :

- uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
with:
cosign-release: v3.1.3

Le mode par clé se rejoue entièrement en local, sans compte ni réseau public, ce qui en fait le meilleur terrain pour comprendre la vérification. Toutes les commandes suivantes ont tourné contre un registre local registry:3 servi en HTTP, d'où l'option --allow-insecure-registry, et avec une configuration de signature vide pour ne rien publier sur l'instance publique de Sigstore.

cosign generate-key-pair écrit cosign.key, chiffrée par une phrase de passe, et cosign.pub. En CI, la phrase de passe se fournit par la variable COSIGN_PASSWORD. La clé privée reste un secret à ranger dans un gestionnaire dédié, jamais dans le dépôt.

Fenêtre de terminal
cosign generate-key-pair
# Private key written to cosign.key
# Public key written to cosign.pub

Une signature porte sur un digest, jamais sur un tag. Cosign v3.1.3 accepte encore un tag, mais affiche un avertissement explicite et annonce la fin de cette possibilité :

Fenêtre de terminal
cosign signing-config create --out signing-config.json # aucun service public
cosign sign --key cosign.key --signing-config signing-config.json \
--allow-insecure-registry -y \
localhost:5000/python:3.13-slim@sha256:afe189875f1d2f9b45e287834fb9f2c273a5d59d354ae4050ab9affbf0a6ba06
# Signing artifact...
# Pushing signature to: localhost:5000/python
cosign sign --key cosign.key --signing-config signing-config.json \
--allow-insecure-registry -y localhost:5000/python:3.13-slim
# WARNING: Image reference localhost:5000/python:3.13-slim uses a tag, not a digest,
# to identify the image to sign. [...] The ability to refer to images by tag
# will be removed in a future release.

Sans --signing-config, Cosign v3 utilise la configuration publique de Sigstore et chercherait à inscrire la signature dans Rekor. L'ancienne option --tlog-upload=false est dépréciée : mesuré, Cosign v3.1.3 la refuse avec la configuration par défaut et demande une configuration de signature sans journal.

cosign verify --key cosign.pub contrôle la signature contre la clé publique. Trois cas mesurés résument ce qu'il faut savoir pour l'intégrer à un script : le code de sortie distingue l'absence de signature d'une signature qui ne correspond pas.

Situation mesuréeCodeMessage
Image signée, bonne clé0The signatures were verified against the specified public key
Image jamais signée10Error: no signatures found
Image signée avec une autre clé1accepted signatures do not match threshold, Found: 0, Expected 1
Fenêtre de terminal
cosign verify --key cosign.pub --insecure-ignore-tlog=true --allow-insecure-registry \
localhost:5000/python:3.13-slim@sha256:afe189875f1d2f9b45e287834fb9f2c273a5d59d354ae4050ab9affbf0a6ba06

La sortie standard est un JSON dont le champ type vaut https://sigstore.dev/cosign/sign/v1 en v3, et dont docker-manifest-digest reprend le digest vérifié. L'option --insecure-ignore-tlog=true n'a de sens ici que parce qu'aucun journal n'a été utilisé à la signature.

Cosign v3 ne pousse plus une image .sig : il écrit un bundle Sigstore (signature, certificat, preuve Rekor) dans un manifeste OCI dont le champ subject pointe vers l'image. cosign tree le montre :

Fenêtre de terminal
cosign tree --allow-insecure-registry \
localhost:5000/python:3.13-slim@sha256:afe189875f1d2f9b45e287834fb9f2c273a5d59d354ae4050ab9affbf0a6ba06
# └── https://sigstore.dev/cosign/sign/v1 artifacts via OCI referrer: localhost:5000/python@sha256:acf10e37...

Un registre qui ne sert pas l'API referrers reste compatible. Mesuré sur GHCR : GET /v2/openvex/vexctl/referrers/<digest> répond 404, mais l'image ghcr.io/openvex/vexctl:v0.4.4 porte un tag sha256-<digest> qui indexe le bundle, et cosign verify la vérifie sans difficulté. L'idée, répandue, que les signatures sur GHCR n'existeraient « que dans Rekor » est fausse. La commande cosign triangulate, qui servait à trouver ce tag, est dépréciée au profit de cosign tree et oras discover.

En CI, la signature keyless ne demande que la permission id-token: write sur le job, pour obtenir le jeton OIDC. Le workflow ci-dessous construit, pousse, puis signe par digest la sortie de docker/build-push-action, et vérifie immédiatement la signature contre l'identité exacte du workflow, construite à partir de github.workflow_ref.

.github/workflows/release.yml
name: release
on:
push:
tags: ["v*"]
permissions: {}
jobs:
build-sign:
runs-on: ubuntu-24.04
permissions:
contents: read
packages: write # pousser l'image et sa signature dans GHCR
id-token: write # obtenir le jeton OIDC pour Fulcio
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
- uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Construire et pousser
id: build
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
with:
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.ref_name }}
- uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
with:
cosign-release: v3.1.3
- name: Signer puis vérifier par digest
env:
IMAGE: ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }}
IDENTITE: ${{ github.server_url }}/${{ github.workflow_ref }}
run: |
cosign sign --yes "${IMAGE}"
cosign verify "${IMAGE}" \
--certificate-identity "${IDENTITE}" \
--certificate-oidc-issuer https://token.actions.githubusercontent.com

Ce workflow passe actionlint 1.7.12, zizmor 1.30.0 et poutine 1.1.6 sans aucun constat. Les valeurs issues du contexte passent par env:, jamais directement dans le script, ce qui écarte l'injection de modèle que zizmor signale. Une signature keyless réelle exige une identité OIDC : ce workflow n'a pas été exécuté pour la leçon, la vérification keyless a été mesurée sur des images publiques, ci-dessous.

Une vérification keyless exige deux contraintes : l'identité du signataire (--certificate-identity ou sa variante -regexp) et l'émetteur OIDC (--certificate-oidc-issuer). Sans elles, Cosign refuse de vérifier, mesuré dans la leçon sur le SBOM. Deux images publiques, signées par leur propre CI, servent de démonstration, en lecture seule.

L'image de vexctl est signée par le workflow de release du projet. La vérification contre l'organisation openvex réussit, et une identité fausse échoue en code 1 en affichant l'identité réellement trouvée :

Fenêtre de terminal
cosign verify ghcr.io/openvex/vexctl:v0.4.4@sha256:ce15c9c85ffc66cb630c0ce9c50a85e9241be77ca4e6e841ab14a0bf2a96bf7e \
--certificate-identity-regexp '^https://github.com/openvex/vexctl/' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
# Verification for ghcr.io/openvex/vexctl@sha256:ce15c9c8... --
# - The cosign claims were validated
# - Existence of the claims in the transparency log was verified offline
# - The code-signing certificate was verified using trusted certificate authority certificates
cosign verify ghcr.io/openvex/vexctl:v0.4.4@sha256:ce15c9c85ffc66cb630c0ce9c50a85e9241be77ca4e6e841ab14a0bf2a96bf7e \
--certificate-identity-regexp '^https://github.com/attaquant/' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
# Error: no matching attestations: failed to verify certificate identity: [...]
# got "https://github.com/openvex/vexctl/.github/workflows/release.yaml@refs/tags/v0.4.4"

L'image de Cosign elle-même n'est pas signée par GitHub Actions mais par un compte de service Google. La vérifier avec un motif GitHub échoue ; la bonne identité et le bon émetteur réussissent. C'est la raison pour laquelle il faut relever l'identité réelle d'un éditeur avant d'écrire sa politique, plutôt que la supposer.

Fenêtre de terminal
cosign verify ghcr.io/sigstore/cosign/cosign:v3.1.3@sha256:9e5c2f2edc34351160407ca3416c61855bdf9403c3c5936e0f0be7fc261611b8 \
--certificate-identity keyless@projectsigstore.iam.gserviceaccount.com \
--certificate-oidc-issuer https://accounts.google.com
# code de sortie 0, "type": "https://sigstore.dev/cosign/sign/v1"

Préférez --certificate-identity, qui attend une valeur exacte, dès que l'identité est connue. Un motif -regexp trop large, comme .* ou une organisation entière, accepte la signature de n'importe quel workflow qui correspond, y compris celui d'un dépôt de test.

Au-delà de l'image, Cosign signe des attestations : un document (SBOM, VEX, provenance) enveloppé dans une déclaration in-toto dont le sujet est le digest. La commande est cosign attest --type <type>, et cosign verify-attestation --type <type> exige le même type. Les types reconnus par Cosign v3.1.3 sont slsaprovenance, slsaprovenance02, slsaprovenance1, link, spdx, spdxjson, cyclonedx, vuln, openvex, custom, ou une URI. Les mesures complètes sont dans les leçons sur le SBOM et le VEX.

La commande cosign attach sbom, encore citée dans de nombreux exemples, est dépréciée, comme toute la famille cosign attach, dont Cosign v3.1.3 annonce le retrait en v4.0.0.

Avec un KMS (Key Management Service), la clé privée ne quitte jamais le coffre : Cosign lui délègue l'opération de signature, et la même URI --key sert à signer et à vérifier. Cette section n'a pas été rejouée, faute de compte cloud dédié ; la syntaxe est celle de la documentation de Cosign.

Fenêtre de terminal
cosign generate-key-pair --kms awskms:///alias/cosign-release
cosign sign --key awskms:///alias/cosign-release \
ghcr.io/openvex/vexctl:v0.4.4@sha256:ce15c9c85ffc66cb630c0ce9c50a85e9241be77ca4e6e841ab14a0bf2a96bf7e
cosign verify --key awskms:///alias/cosign-release \
ghcr.io/openvex/vexctl:v0.4.4@sha256:ce15c9c85ffc66cb630c0ce9c50a85e9241be77ca4e6e841ab14a0bf2a96bf7e

Les préfixes reconnus sont awskms://, gcpkms://, azurekms://, hashivault:// et k8s:// pour un secret Kubernetes. Le contrôle d'accès du KMS devient alors la vraie frontière : qui peut appeler l'opération de signature peut signer.

Signer ne protège rien tant que le cluster accepte les images non signées. Le contrôle se place à l'admission, l'étape où l'API Kubernetes accepte ou refuse un pod avant sa création. Deux implémentations dominent : Kyverno et le Policy Controller de Sigstore.

Kyverno 1.19 vérifie les signatures avec une ressource ImageValidatingPolicy. La politique suivante a été rejouée sur un cluster kind jetable : l'image vexctl signée par sa CI est admise, la même image est refusée dès que l'identité attendue ne correspond plus.

verify-image-signatures.yaml
apiVersion: policies.kyverno.io/v1
kind: ImageValidatingPolicy
metadata:
name: verify-image-signatures
spec:
validationActions: [Deny]
webhookConfiguration:
timeoutSeconds: 15
matchConstraints:
resourceRules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["pods"]
matchImageReferences:
- glob: "ghcr.io/openvex/*"
attestors:
- name: cosign
cosign:
keyless:
identities:
- issuer: "https://token.actions.githubusercontent.com"
subjectRegExp: "^https://github.com/openvex/"
ctlog:
url: "https://rekor.sigstore.dev"
validations:
- expression: >-
images.containers.map(image, verifyImageSignatures(image, [attestors.cosign])).all(e, e > 0)
message: "Image non signée par la CI de l'organisation openvex."
Fenêtre de terminal
kubectl run vexctl-signe --restart=Never \
--image ghcr.io/openvex/vexctl:v0.4.4@sha256:ce15c9c85ffc66cb630c0ce9c50a85e9241be77ca4e6e841ab14a0bf2a96bf7e
# pod/vexctl-signe created
# Même image, politique attendant l'identité ^https://github.com/attaquant/
# Error from server: admission webhook "ivpol.validate.kyverno.svc-fail-finegrained-verify-image-signatures"
# denied the request: Policy verify-image-signatures failed: Image non signée par la CI de l'organisation openvex.

Un détail décide de tout : la validation doit appeler verifyImageSignatures(), la fonction qui déclenche la vérification. Mesuré, une politique dont la validation se réduit à expression: "true" ne vérifie rien et bloque tout : Kyverno refuse le pod avec « no policy performed a signature or attestation check on it », y compris pour une image correctement signée.

Le Policy Controller est maintenu par le projet Sigstore. Une fois installé, il ne bloque encore rien : il faut étiqueter les namespaces à protéger (policy.sigstore.dev/include=true) et déclarer une ressource ClusterImagePolicy qui dit quelles images vérifier et sous quelle identité. Il n'a pas été rejoué pour cette leçon ; la version 0.10.8 est la dernière publiée du chart au 1er octobre 2026.

Fenêtre de terminal
helm repo add sigstore https://sigstore.github.io/helm-charts
helm install policy-controller sigstore/policy-controller \
-n cosign-system --create-namespace --version 0.10.8

Une signature ne vaut que ce que vaut le pipeline qui la produit : un workflow compromis émet des signatures parfaitement valides sur des images malveillantes. Les points suivants portent donc sur la chaîne autour de Cosign.

  • id-token: write au niveau du job, jamais du workflow entier : un job de tests, plus exposé, n'a pas à pouvoir signer.
  • Actions épinglées par SHA de commit, avec la version en commentaire : uses: actions/checkout@v4 (# ❌ à éviter) laisse l'éditeur de l'action changer le code exécuté.
  • Vérification immédiate après la signature, dans le même job, contre l'identité exacte : une signature non vérifiée ne prouve rien.
  • Identité exacte à l'admission : une politique qui accepte toute une organisation accepte aussi ses dépôts de test.
  • Provenance en plus de la signature : la signature dit qui a signé, la provenance SLSA dit comment l'artefact a été construit. Signer une image ne suffit pas à atteindre un niveau SLSA Build.

Les échecs de Cosign se ramènent presque toujours à trois causes : une identité qui ne correspond pas, une permission OIDC absente du job, ou une signature cherchée au mauvais endroit. Le code de sortie aide à trancher : 10 signifie qu'aucune signature n'a été trouvée, 1 qu'une signature existe mais ne correspond pas.

SymptômeCauseSolution
no signatures found, code 10Image non signée, ou digest différent de celui signéVérifier le digest avec cosign tree
expected SAN value to match regex ..., got "...", code 1Identité attendue différente de l'identité réelleLire la valeur après got et corriger la politique
accepted signatures do not match threshold, code 1Signature faite avec une autre cléVérifier avec la bonne cosign.pub
--certificate-identity or --certificate-identity-regexp is requiredVérification keyless sans contrainte d'identitéAjouter identité et émetteur
--tlog-upload=false is not supportedOption dépréciée en v3Utiliser --signing-config sans journal
Échec d'obtention du jeton OIDC en CIPermission id-token: write absente du jobAjouter la permission au job qui signe
Kyverno refuse tout avec no policy performed a signature or attestation checkValidation sans verifyImageSignatures()Appeler la fonction dans validations
  1. Cosign signe une image par son digest et vérifie ensuite qui l'a signée ; il ne dit rien de ses vulnérabilités.
  2. Le mode keyless remplace la clé par une identité OIDC : Fulcio certifie, Rekor enregistre, la clé éphémère est jetée.
  3. Une vérification keyless exige l'identité et l'émetteur ; préférez --certificate-identity exacte à un motif trop large.
  4. cosign verify sort en 10 sans signature et en 1 quand la signature ne correspond pas : un script peut distinguer les deux.
  5. Cosign v3 range un bundle lié au digest, via l'API referrers ou un tag sha256-<digest> sur les registres comme GHCR.
  6. Installez une version ≥ 3.0.4 (avis GHSA-whqx-f9j3-ch6m), épinglée et contrôlée par empreinte.
  7. À l'admission, Kyverno doit appeler verifyImageSignatures() : sans cet appel, la politique bloque tout.
  8. La preuve attendue par SOCLE-REL-GEN-1 est la signature des artefacts publiés ; SOCLE-REL-VER-1 attend leur vérification par les consommateurs avant usage, ici à l'admission Kubernetes.

Vérifiez que l'essentiel de cette leçon 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

6 questions
6 min.
70% requis

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

Les questions ci-dessous reprennent les doutes les plus courants sur Cosign : mode keyless, vérification d'identité, GHCR et Kubernetes, avec la même version épinglée que la leçon.

Ce projet vous est utile ?

Les guides, formations, quiz et labs restent gratuits. Si vous les utilisez régulièrement, vous pouvez contribuer à leur maintenance et à leur développement.

Devenir membre de soutien (nouvel onglet) Soutenir une fois (nouvel onglet) En savoir plus

Suivez aussi le projet sur LinkedIn