Aller au contenu

Votre première promotion

Étape 2 sur 2 — vous avez l’instance de l’étape 1. Cette page la met à sa vraie place : entre les registres où le contenu vit déjà et la zone qui le consomme. Vous allez épingler une image publique dans une recipe, signer la recipe, la publier dans un cookbook, déclarer l’état désiré de la zone, laisser votre instance promouvoir — et finir par un docker pull depuis le registre de zone. Tout ce qui suit n’utilise que de l’outillage utilisateur ordinaire — rien qui vienne de l’arborescence des sources.

Où vit le contenu Votre zone docker.io l'image, déjà publiée registre cookbook votre recipe signée Tobby store + registre de zone clients de la zone docker pull image, par digest recipe + signature Vérifié à la frontière — jamais réécrit, jamais re-signé

Il vous faut : le binaire tobby et le tobby.yaml de l’étape 1, plus docker, cosign et curl. L’image vient de Docker Hub ; la seule chose que vous montez vous-même est un registre cookbook jetable en boucle locale.

Élément Rôle
docker.io Le registre amont. L’image y vit déjà ; rien n’y est poussé.
Un registre cookbook (:5001) Un registre OCI ordinaire qui héberge votre recipe signée. N’importe quel registre où vous pouvez pousser convient — ici, un registre local jetable.
Votre instance (:8080) Celle de l’étape 1 : sécurisée, avec sa clé de confiance et son Retriever. C’est elle qui promeut.
Une paire de clés cosign Signe la recipe. La clé publique devient la racine de confiance de votre instance.

Les recipes se publient dans un cookbook : un dépôt OCI ordinaire, sur n’importe quel registre où vous pouvez pousser. Si vous en avez déjà un (ghcr.io, Harbor, …), utilisez-le et adaptez les adresses qui suivent. Pour le parcours, un registre jetable en boucle locale suffit :

Fenêtre de terminal
docker run -d --rm --name cookbook -p 5001:5000 registry:2

Le port hôte est 5001 et non 5000 : sur macOS, le récepteur AirPlay occupe le port 5000 et répond 403 à sa place — un grand classique des tutoriels de registry locale.

Une recipe désigne le contenu par digest, jamais par simple tag. Lisez le digest que alpine:3.22.1 résout aujourd’hui :

Fenêtre de terminal
docker buildx imagetools inspect docker.io/library/alpine:3.22.1

Les premières lignes affichent Digest: sha256:… — gardez ce digest, la recipe l’épingle.

Une recipe décrit une livraison cohérente. Une recipe « cuite » — la seule qu’un cookbook publie — épingle chaque ingrédient par digest : une seule signature atteste les octets exacts de toute la livraison. Écrivez alpine.yaml, avec le digest de l’étape précédente :

apiVersion: recipe.tobby.dev/v1alpha1
kind: Recipe
metadata:
name: alpine
version: 3.22.1
description: Première promotion — une image épinglée
spec:
ingredients:
- name: alpine
kind: ContainerImage
ref: docker.io/library/alpine # référence nominale, sans tag
version: 3.22.1
digest: sha256:<le digest affiché par imagetools>

Les concepts — recipes, cookbooks, retrievers — sont couverts dans Comprendre les recipes.

tobby recipe push publie la recipe comme artefact OCI après l’avoir contrôlée : un document qui n’est pas une recipe valide, pas entièrement épinglé, ou déjà publié avec un contenu différent est refusé. Le registre jetable parle HTTP simple, ce qui exige un accord explicite par hôte :

Fenêtre de terminal
export TOBBY_REGISTRIES_INSECURE=127.0.0.1:5001
tobby recipe push alpine.yaml 127.0.0.1:5001/cookbook/alpine:3.22.1

Le digest publié sort sur stdout, prêt pour la signature. Signer reste hors de Tobby — il ne détient jamais de clé privée :

Fenêtre de terminal
cosign generate-key-pair
cosign sign --key cosign.key --yes --allow-insecure-registry \
--use-signing-config=false --tlog-upload=false \
"127.0.0.1:5001/cookbook/alpine@<le digest affiché par recipe push>"

Les deux drapeaux --use-signing-config=false --tlog-upload=false gardent la signature vérifiable hors-ligne : sans eux, cosign 3.x publie dans le journal de transparence public — un appel réseau qu’un signataire de zone restreinte ne devrait pas faire, et une consultation que la destination ne pourrait de toute façon pas effectuer.

Un Retriever nomme ce que la zone doit contenir. Écrivez retriever.yaml :

apiVersion: recipe.tobby.dev/v1alpha1
kind: Retriever
metadata:
name: zone-demo
spec:
cookbook: 127.0.0.1:5001/cookbook
recipes:
- name: alpine
version: "3.22.1"

Une version exacte est prise au mot ; une contrainte (6.x, ~0.16.1) se résout contre le cookbook à chaque synchronisation — une version corrective arrive en la publiant, sans fichier à modifier.

Arrêtez l’instance de l’étape 1 avec Ctrl-C — l’arrêt est gracieux — et ajoutez trois choses à son tobby.yaml : le Retriever, la racine de confiance, et l’accord HTTP simple pour le registre jetable :

retriever:
source: ./retriever.yaml # un fichier, une URL https://, ou une référence OCI
trust:
roots:
- name: cle-signature-demo
keyFile: ./cosign.pub
registries:
insecure: ["127.0.0.1:5001"]

Puis redémarrez :

Fenêtre de terminal
tobby serve --config ./tobby.yaml

En mode passthrough l’instance réconcilie sur son propre rythme (toutes les 15 minutes par défaut). Déclenchez un cycle tout de suite : l’écran Recipes propose une action de synchronisation, ou en ligne de commande :

Fenêtre de terminal
curl -u admin -X POST http://localhost:8080/api/v1/sync

Observez l’écran Tâches : la synchronisation résout le Retriever, récupère la recipe depuis le cookbook, vérifie sa signature cosign contre votre racine de confiance, puis tire l’image directement depuis docker.io et la contrôle contre le digest épinglé — en ne transférant que ce qui manque à la zone. L’écran Recipes montre alors la recipe, sa version résolue et son verdict de vérification.

Le détail de tâche : les items de la synchronisation avec leur statut et le journal JSON brut, identifiant de run inclus L’écran Recipes montrant la recipe promue, signature vérifiée

Relancez la synchronisation : elle se termine sans rien transférer — la zone correspond déjà à son état désiré.

Le registre embarqué de votre instance sert désormais le contenu promu. Docker s’authentifie avec le même compte que l’interface :

Fenêtre de terminal
docker login 127.0.0.1:8080 # le compte créé par le quickstart
docker pull 127.0.0.1:8080/docker.io/library/alpine:3.22.1

Si votre daemon Docker tourne dans une VM (Rancher Desktop, certains montages Colima), son 127.0.0.1 est la VM, pas votre machine — utilisez l’adresse LAN de votre hôte dans les deux commandes.

Le pull réussit, digest intact : l’image a été transportée, vérifiée et servie — jamais réécrite, jamais re-signée. Le chemin dit d’où vient le contenu ; pourquoi c’est important, et comment brancher de vrais clients (mirrors containerd, GitOps), c’est dans Brancher vos clients.

La scène était petite, mais rien n’était simulé : une recipe signée dans un cookbook, une zone qui déclare son état désiré, une promotion qui vérifie tout avant de servir. La production ne change que les adresses — le cookbook part sur un registre alimenté par votre processus de qualification, le Retriever se publie comme artefact OCI, les clés viennent de ce même processus.