Aller au contenu

Déployer : Kubernetes et VM

Tobby se livre sous trois formes, toutes issues de la même chaîne de release reproductible : un chart Helm (avec son jumeau en manifestes bruts), des paquets Linux (.deb, .rpm, .apk) et une image de conteneur. Quelle que soit la forme, une règle domine la mise en place.

Tobby écrit dans deux répertoires :

  • Le store (storage.root) contient les artefacts, les recipes et les journaux d’opération. Volumineux, autonome, re-téléchargeable.
  • L’état (state.root) contient l’identité de l’instance : comptes, jetons, certificats servis, spools de téléchargements reprenables. Petit, et rien ne le recrée.

Le répertoire d’état est la cible de sauvegarde ; le store ne coûte que de la bande passante à reconstruire. Les deux ne doivent jamais être imbriqués l’un dans l’autre — les secrets ne voyagent pas sur un média transportable — et Tobby refuse de démarrer quand ils le sont. Le chart Helm refuse en plus de se rendre quand les deux chemins de montage sont identiques. Voir Exploiter dans la durée.

Le déploiement de référence existe sous deux formes : un chart Helm, publié à chaque release comme artefact OCI sous oci://ghcr.io/tobby-fetch/charts/tobby, et le même pod écrit en YAML brut numéroté dans deploy/manifests/, pour les clusters qui ne font pas tourner Helm. Les deux produisent un conteneur non-root sur un système de fichiers racine en lecture seule, toutes capacités abandonnées, probes câblées, et des PersistentVolumeClaims distincts pour le store (100Gi par défaut) et l’état (20Gi par défaut — l’état accueille aussi les spools de téléchargements reprenables, voir Exploiter).

Fenêtre de terminal
helm install tobby oci://ghcr.io/tobby-fetch/charts/tobby --version 0.6.0 \
--namespace tobby --create-namespace \
--set config.mode=passthrough

La version du chart est la version de Tobby : le chart 0.6.0 déploie l’image v0.6.0, et rien d’autre. Épinglez --version — sans elle, Helm prend le chart le plus récent, c’est-à-dire une mise à jour que vous n’avez pas choisie. Chaque chart publié est signé sans clé par le workflow de release, comme l’image :

Fenêtre de terminal
cosign verify ghcr.io/tobby-fetch/charts/tobby:0.6.0 \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp '^https://github.com/tobby-fetch/tobby-fetch/'

Un cluster sans route vers ghcr.io reçoit le chart comme tout le reste : le chart et l’image qu’il désigne sont deux ingrédients d’une recette, transportés par Tobby et tirés depuis le registre de la zone (oci://registry.zone.example/…). Depuis un clone du dépôt, ./deploy/charts/tobby est le même chart, pour le développement.

config.mode est la seule valeur sans défaut utilisable : une instance doit dire ce qu’elle est (FR-001). La valeur config du chart devient /etc/tobby/config.yaml et reprend exactement les clés de configuration de Tobby — la sortie de tobby config dump se colle telle quelle. env positionne les variables TOBBY_* et extraArgs ajoute des drapeaux ; la précédence est drapeaux > environnement > fichier (FR-003). Quatre clés (storage.root, state.root, server.addr, registries.credentialsFile) appartiennent au chart et sont rejetées si elles sont posées directement, parce que la spec du pod en dépend.

Les credentials de registre sont un Secret kubernetes.io/dockerconfigjson distinct (FR-004), monté en lecture seule — jamais dans le fichier de configuration, jamais dans le store :

Fenêtre de terminal
kubectl -n tobby create secret docker-registry tobby-registry-credentials \
--docker-server=registry.example.com \
--docker-username=tobby \
--docker-password="$(cat ./token)"
helm upgrade tobby oci://ghcr.io/tobby-fetch/charts/tobby --version 0.6.0 \
--namespace tobby --reuse-values \
--set registryCredentials.enabled=true \
--set registryCredentials.existingSecret=tobby-registry-credentials

Les entrées sont cherchées par l’hôte réellement contacté — avec une substitution de source en jeu, le registre de substitution, pas le registre nominal.

Les fichiers de deploy/manifests/ sont numérotés dans l’ordre d’application et créent leur propre namespace tobby, qui impose le Pod Security Standard restricted — une modification ultérieure affaiblissant le contexte de sécurité du pod est rejetée par l’API server, pas silencieusement acceptée.

Fenêtre de terminal
kubectl apply -f ./deploy/manifests/

Modifiez 20-secret-config.yaml (posez mode, et retriever.source si vous en avez un) et 21-secret-registry-credentials.yaml (la charge livrée est un {"auths":{}} vide et valide) avant d’appliquer.

L’image publiée porte une provenance SLSA Build L3 et une signature cosign, toutes deux faites contre le digest. Épinglez le digest en production (image.digest dans le chart) et vérifiez d’abord :

Fenêtre de terminal
cosign verify ghcr.io/tobby-fetch/tobby-fetch@sha256:... \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp '^https://github.com/tobby-fetch/tobby-fetch/'

Le tag glissant latest est signé avec la même identité mais ne porte aucune provenance SLSA — seuls les digests immuables vX.Y.Z en ont. Le guide de vérification complet, provenance comprise, est Vérifier une release.

Chaque release publie des paquets .deb, .rpm et .apk qui enveloppent exactement le binaire de release tobby-linux-<arch> — installé dans /usr/bin/tobby, sans script d’installation, entièrement autonome (CGO désactivé). Ils sont conçus pour une installation hors-ligne, sans dépôt : vérifiez (SHA256SUMS ou provenance SLSA), copiez le fichier, installez sans réseau :

Fenêtre de terminal
dpkg -i tobby_0.6.0_linux_amd64.deb # Debian/Ubuntu
rpm -i tobby_0.6.0_linux_amd64.rpm # RHEL/SUSE/Fedora
apk add --allow-untrusted tobby_0.6.0_linux_amd64.apk # Alpine

Les paquets ne portent délibérément aucune signature de gestionnaire de paquets : la confiance vient de la vérification de provenance ou de checksum faite avant l’installation — --allow-untrusted sur apk le dit exactement. Le raisonnement est détaillé dans Vérifier une release.

Les paquets n’installent que le binaire ; la définition du service est à vous. Cette unit de référence reprend la posture du déploiement en conteneur :

/etc/systemd/system/tobby.service
[Unit]
Description=Tobby instance
After=network-online.target
Wants=network-online.target
[Service]
User=tobby
Group=tobby
ExecStart=/usr/bin/tobby serve --config /etc/tobby/config.yaml
Restart=on-failure
# SIGTERM lance l'arrêt en douceur ; laissez-lui plus que
# shutdown.gracePeriod (30s par défaut) avant le SIGKILL.
TimeoutStopSec=60
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
ReadWritePaths=/var/lib/tobby/store /var/lib/tobby/state
[Install]
WantedBy=multi-user.target

Créez les deux répertoires appartenant à l’utilisateur du service, posez storage.root et state.root dans /etc/tobby/config.yaml, et gardez les secrets hors du fichier d’unit — le mot de passe du proxy, par exemple, appartient au fichier de configuration ou à un fichier d’environnement lisible du seul utilisateur du service (voir Réseau d’entreprise).

ghcr.io/tobby-fetch/tobby-fetch est une image minimale, sans shell, tournant sous l’UID 65532. Montez les deux volumes et la configuration :

Fenêtre de terminal
docker run -d --name tobby --read-only \
-p 8080:8080 \
-v /srv/tobby/store:/var/lib/tobby/store \
-v /srv/tobby/state:/var/lib/tobby/state \
-v /srv/tobby/config.yaml:/etc/tobby/config.yaml:ro \
ghcr.io/tobby-fetch/tobby-fetch:v0.6.0 \
serve --config /etc/tobby/config.yaml
Plateforme Palier
Linux amd64 / arm64 Périmètre de production validé : service passthrough, paquets, image de conteneur.
Windows amd64 / arm64 Binaire statique unique publié, et le parcours du poste miroir y est validé (NFR-018). Le mode passthrough sous Windows est hors du périmètre validé. Voir plateformes supportées.
macOS amd64 / arm64 Palier de confort (NFR-001) : même chaîne reproductible, distribution via brew install tobby-fetch/tap/tobby, suite de tests complète en CI — mais aucun support de production impliqué.

Le store refuse les systèmes de fichiers qui ne peuvent pas contenir sa disposition — FAT32 en fait partie ; voir limites.

L’authentification est active par défaut, et Tobby refuse de servir tant que le répertoire d’état ne contient pas au moins un compte (TBY-AUTH-001) — une installation Kubernetes neuve reste en CrashLoopBackOff jusqu’à ce que l’administrateur existe, ce qui est voulu : aucune surface n’est jamais exposée ouverte. Sur un terminal, tobby quickstart vous accompagne. Pour l’automatisation, chaque question a un drapeau, et le mot de passe arrive sur l’entrée standard — jamais sur la ligne de commande :

Fenêtre de terminal
printf '%s\n' "$ADMIN_PASSWORD" | tobby quickstart \
--mode passthrough \
--config /etc/tobby/config.yaml \
--storage-root /var/lib/tobby/store \
--state-root /var/lib/tobby/state \
--password-stdin

Les commandes primitives équivalentes sont tobby user add admin --state-root /var/lib/tobby/state --password-stdin suivie de tobby serve --config /etc/tobby/config.yaml. Le premier compte d’une instance est toujours admin, et l’outil calcule lui-même le hash du mot de passe. Sur Kubernetes, où l’image n’a pas de shell, exécutez l’étape user add dans un pod éphémère montant le claim d’état — la recette exacte est dans deploy/README.md.

S’il vous faut absolument tourner ouvert, auth.disabled: true est un opt-in explicite qui pose un bandeau d’avertissement permanent dans l’interface (FR-075). Ne le laissez jamais actif.

OIDC et SAML sont désactivés par défaut, et le compte local admin reste — c’est le compte de secours quand l’annuaire est en panne. Pour activer l’un ou l’autre, trois points à soigner dès l’installation (détails dans Identité d’entreprise) :

  • Les URL de retour vivent sous /auth/. Déclarez exactement https://<hôte>/auth/oidc/callback (OIDC) ou le service consommateur d’assertions https://<hôte>/auth/saml/acs (SAML ; le descripteur du SP est https://<hôte>/auth/saml/metadata). Une configuration qui nomme un autre chemin est refusée au démarrage. Un reverse proxy placé devant doit laisser passer /auth/.
  • Épinglez le fournisseur SAML. Préférez auth.saml.idpMetadataFile ; auth.saml.idpMetadataURL exige le certificat de signature épinglé dans auth.saml.idpCertificateFile.
  • Montez les secrets hors du store : auth.oidc.clientSecretFile et auth.saml.keyFile, comme tout chemin secret.

displayName libelle le bouton de connexion ; auth.oidc.nameClaim et auth.saml.nameAttribute choisissent le nom affiché pour une personne. Tous trois ne servent qu’à l’affichage. Une mise à jour depuis v0.5.x n’exige rien de tout cela pour continuer à fonctionner : chaque nouvelle clé de fédération est désactivée ou a une valeur par défaut.

Un défaut change en revanche quand on met à jour depuis v0.5.x : l’analyse de vulnérabilités s’exécute désormais, en mode consultatif. Chaque image de conteneur récupérée est analysée, quel que soit le type sous lequel elle est déclarée, — il n’existe pas d’interrupteur « activé » — et, avec scan.mode laissé à warn, les résultats sont rapportés (rapport de tâche, API, interface, métriques, avec l’âge de la base) alors que rien n’est retenu. Une instance sans scanner ou sans base affiche à la place la bannière du mode dégradé. Pour refuser ce qui dépasse un seuil, posez scan.mode: block (ou TOBBY_SCAN_MODE=block ; le seuil est scan.threshold, 7.0 par défaut), ou posez un seuil pour un périmètre précis : le spec.scanPolicy.threshold d’un Retriever ou l’annotation recipe.tobby.dev/scan-threshold d’une recipe, chacun bloquant pour ce qu’il couvre. Un refus retient la recipe entière. Voir l’analyse de vulnérabilités.

Suite : pointez l’instance vers le monde extérieur à travers le réseau d’entreprise.