Tous les articles [ Écosystème ] N° 08 / 16 S6 8 min de lecture //
Un module en une heure : chronomètre en main
Tutoriel du parcours outillé OC2-Edge : huit étapes de oc2 new à l'installation sur nœud émulé, le contrat de module déclaratif fondé sur gRPC et le choix du niveau d'isolation entre natif, microVM et WASI.
Le titre annonce une heure. Précision d’emblée : une heure est l’objectif de conception du parcours outillé, du gabarit initial au module installé sur un nœud émulé. Ce n’est pas une mesure. Nous ne publions pas de chronométrage tant qu’un protocole de mesure n’est pas défini et rejoué ; c’est un point ouvert. L’objectif reste vérifiable par chacun : le parcours ci-dessous s’exécute sans matériel dédié, chronomètre en main.
Ce tutoriel déroule les huit étapes du parcours, puis explicite les deux choix qui structurent un module : son contrat et son niveau d’isolation.
Prérequis
Trois éléments suffisent :
- le dépôt public OC2-Edge cloné et vérifié (la procédure est décrite dans le guide d’instance) ;
- l’outil
oc2en ligne de commande, construit depuis le dépôt ; - un nœud émulé : le socle s’émule en x86-64 et en ARM64, aucun calculateur cible n’est requis.
Les sorties présentées sont génériques et illustrent la forme attendue ; la documentation du dépôt fait référence. L’exemple construit un module minimal, hello-track, qui publie une piste de démonstration sur la COP (image tactique) du nœud. Le langage de l’exemple est Rust ; le parcours est identique pour les autres langages supportés par le gabarit.
Les huit étapes
1. oc2 new : le gabarit
oc2 new hello-track --lang rust --isolation wasi
La commande produit une arborescence complète : un manifeste module.yaml pré-rempli, un squelette de service gRPC, un test d’exemple, une configuration de build pour la cible choisie. Le gabarit compile et passe ses tests avant toute modification : le point de départ est un module valide, pas une page blanche.
2. oc2 lint : la validation du manifeste
oc2 lint
La commande valide le manifeste contre le schéma du contrat de module : identité complète, capacités déclarées connues, interfaces référencées existantes. Sortie attendue : la liste des contrôles passés, zéro avertissement. Un manifeste non conforme bloque ici, avant toute compilation.
3. oc2 build : l’artefact
oc2 build --target wasm32-wasi
La commande compile le module vers la cible d’isolation choisie. Sortie attendue : un artefact unique (hello-track.wasm dans cet exemple) et son empreinte. Pour un module WASI, le même artefact sert les nœuds x86-64 et ARM64.
4. oc2 test : la preuve locale
oc2 test
La commande exécute les tests du module dans la même sandbox que celle du nœud : le module testé est le module qui tournera, avec les mêmes restrictions de capacités. Sortie attendue : le verdict par test et un verdict global vert.
5. oc2 keygen : la clé d’éditeur
oc2 keygen --algo ml-dsa-65 --out ./keys/editeur
La commande génère une paire de clés ML-DSA-65 (FIPS 204). La clé privée reste locale ; elle n’est transmise ni au dépôt ni à Cercle Digital. Pour une publication vers une flotte réelle, cette clé s’inscrit dans la PKI de l’instance ; pour ce tutoriel, une clé locale suffit.
6. oc2 sign : la signature
oc2 sign --key ./keys/editeur --artifact out/hello-track.wasm
La commande produit une signature détachée couvrant l’artefact et le manifeste. C’est l’étape qui donne son sens au reste : un nœud OC2-Edge refuse tout module dont la signature ne remonte pas à une clé approuvée par le magasin de modules de son instance.
7. oc2 pack : l’archive
oc2 pack --out hello-track-0.1.0.ocm
La commande assemble artefact, manifeste et signature en une archive de module. L’archive est l’unité de distribution : c’est elle qui entre dans le magasin de modules et transite par le dépôt TUF de l’instance.
8. oc2 install : le nœud émulé
oc2 emu up --profile node-x86_64
oc2 install hello-track-0.1.0.ocm --target emu
Le nœud émulé vérifie la signature, contrôle les capacités demandées contre sa politique, charge le module dans sa sandbox et l’inscrit au catalogue local. Sortie attendue : le module à l’état actif, ses interfaces visibles depuis la COP (image tactique) du nœud, en mode MAQUETTE.
Le parcours est terminé. Chaque étape a produit un objet vérifiable : arborescence, verdict de lint, artefact, verdict de test, clé, signature, archive, module actif.
Quand une étape échoue
Le parcours est conçu pour échouer tôt et proprement. Trois échecs types illustrent le comportement attendu.
Un manifeste non conforme échoue à l’étape 2 : oc2 lint désigne le champ fautif et la règle violée, avant toute compilation. Une capacité demandée mais inconnue du socle est signalée ici, pas à l’installation.
Un test rouge échoue à l’étape 4 : la sandbox de test étant celle du nœud, un module qui tente un accès non déclaré (fichier, socket, horloge) échoue en test local exactement comme il échouerait sur le nœud. C’est voulu : l’écart entre l’environnement de développement et l’environnement d’exécution est la source classique des surprises de déploiement, et la sandbox unique le supprime.
Une signature invalide échoue à l’étape 8 : le nœud refuse l’archive et journalise le motif (clé inconnue de sa politique, artefact modifié après signature, manifeste divergent). Aucune option ne permet de forcer l’installation d’un module non vérifié, y compris sur nœud émulé ; le chemin de confiance du tutoriel est le même que celui d’une flotte réelle.
Le contrat de module : rien d’implicite
Un module OC2-Edge est défini par son manifeste déclaratif. Le manifeste porte trois blocs :
identity:
name: hello-track
version: 0.1.0
publisher: exemple-sas
capabilities:
network: [mesh.tracks.publish]
storage: [state.local]
interfaces:
- grpc: oc2.tracks.v1.TrackSource
L’identité nomme le module, sa version et son éditeur. Les capacités énumèrent ce que le module demande : accès réseau, stockage, matériel. Les interfaces déclarent ce que le module expose et consomme.
L’interface d’exécution est gRPC : contrats typés, versionnés, générés depuis une définition unique [1]. Les interfaces du socle sont versionnées explicitement (oc2.tracks.v1 dans l’exemple) : un module compilé contre une version d’interface continue de fonctionner tant que cette version est servie, et le manifeste rend la dépendance visible. L’évolution d’une interface passe par une nouvelle version, jamais par une modification silencieuse de l’ancienne.
Le choix découle d’une règle : rien d’implicite. Ce qui n’est pas déclaré dans le manifeste est refusé à l’exécution ; ce qui n’est pas dans le contrat gRPC n’existe pas entre modules. Un relecteur détermine les privilèges d’un module en lisant son manifeste, sans lire son code, et l’opérateur d’instance fonde sa décision d’approbation sur ce même document. La même approche déclarative structure les spécifications de conteneurs, où la configuration d’exécution est un document normé et vérifiable [6].
Choisir son isolation
Le gabarit demande un niveau d’isolation à la création. Trois niveaux existent ; le choix engage le module.
Le niveau natif exécute le module comme processus confiné : namespaces, cgroups, seccomp. C’est le niveau le plus performant et le moins isolant ; il requiert la confiance maximale et reste réservé aux modules du socle ou aux modules audités par l’opérateur d’instance. Pour le module, cela signifie : accès système direct, mais revue de sécurité obligatoire avant entrée au magasin.
Le niveau microVM exécute le module dans une machine virtuelle minimale, sur le modèle de Firecracker [3] : frontière d’isolation matérielle virtuelle, surface d’attaque réduite au strict nécessaire. Le coût est un surcroît de mémoire par module par rapport aux deux autres niveaux. Pour le module, cela signifie : un vrai noyau invité, donc la possibilité d’embarquer des dépendances système, au prix d’une empreinte plus lourde.
Le niveau WebAssembly/WASI compile le module en WebAssembly et l’exécute dans un runtime conforme WASI [2][4]. La sandbox fonctionne par capacités : le module ne voit aucun descripteur, aucun fichier, aucune socket qui ne lui ait été explicitement accordé, ce qui s’aligne exactement sur le manifeste déclaratif. La portabilité est l’autre gain : un artefact unique pour toutes les architectures de nœud. Le modèle de composants WebAssembly type les interfaces au niveau du langage [5]. Pour le module, cela signifie : langages restreints à ceux qui compilent bien vers WASI, pas d’accès système hors capacités, portabilité maximale.
Le gabarit du tutoriel choisit WASI : c’est le niveau par défaut recommandé pour un module tiers, parce que sa sandbox rend vérifiable ce que le manifeste déclare.
En pratique, la règle de choix tient en trois cas. Un module de traitement de données (connecteur, fusion, calcul) prend WASI par défaut. Un module qui embarque une pile logicielle existante avec ses dépendances système prend microVM. Un module qui touche au matériel ou au temps réel du socle prend le niveau natif et accepte en contrepartie la revue de sécurité complète de l’opérateur d’instance. Le niveau d’isolation figure dans le manifeste et dans le magasin de modules : changer de niveau est une nouvelle version, approuvée comme telle.
Publier son premier module
Le parcours ci-dessus s’arrête au nœud émulé. L’étape suivante est la publication : proposer le module au magasin d’une instance, ou le verser au catalogue communautaire du projet pour qu’il serve d’exemple à d’autres éditeurs. Le canal communautaire du dépôt public accueille les manifestes, les questions de contrat et les retours sur le parcours outillé ; les demandes d’accompagnement passent par le contact du site. Un module utile, signé et bien isolé est la contribution la plus directe à l’écosystème.
Sources
- gRPC Authors, « Introduction to gRPC », 2024, https://grpc.io/docs/what-is-grpc/introduction/
- WASI Subgroup (W3C WebAssembly Community Group), « WASI : The WebAssembly System Interface », 2024, https://wasi.dev/
- Amazon Web Services, « Firecracker : Secure and fast microVMs for serverless computing », 2024, https://firecracker-microvm.github.io/
- Bytecode Alliance, « Wasmtime Documentation », 2024, https://docs.wasmtime.dev/
- Bytecode Alliance, « The WebAssembly Component Model », 2024, https://component-model.bytecodealliance.org/
- Open Container Initiative, « OCI Runtime Specification », 2024, https://github.com/opencontainers/runtime-spec