Étude — Surface d’administration et placement de la configuration
Statut : note de travail, conversation en cours. Ne fait autorité sur rien. Aucune décision n’est prise ici — elle est versée pour être reprise et poursuivie.
Pourquoi. L’étude « Le chemin » a établi qu’il manquait des Managers pour orchestrer un démarrage. En tirant sur ce fil sont apparues deux questions qu’elle ne traitait pas : quels outils d’administration Air doit fournir, et où vit la configuration dans un système à racine immuable. La seconde a fait apparaître un trou réel dans la conception du modèle A/B.
1. Les Managers : ce qui existe, ce qui manque
État relevé dans l’arbre le 2026-08-02, corrigé et précisé le 2026-08-03 après un audit méthodique — la première rédaction était juste sur le compte, trop grossière sur la nature de l’écart. L’état faisant autorité vit désormais dans l’amendement d’ADR-077 (« Managers de domaine en couche 1 ») ; ce qui suit en est le résumé.
Huit Managers existent — AirTaskManager (processus et threads), AirFileManager,
AirMemoryManager, AirSignalManager, AirNetworkManager (sockets, pas
configuration), AirEnvironmentManager, AirSystemManager, AirLogManager — mais exister
n’est pas jouer le rôle. Le renommage AirProcessManager → AirTaskManager (ADR-088) est
allé au bout dans le code ; il reste des mentions périmées dans les ADR et les manifestes.
Trois domaines mûrs n’ont pas de Manager — mais aucun n’est pour autant un tas de fonctions libres, et les trois cas ne sont pas de même gravité :
| Domaine | Ce qu’il expose réellement | Nature de l’écart |
|---|---|---|
air-device | AirDevice, AirDeviceEnumerator, AirDeviceMonitor, AirBlockDevice — surface objet, aucune fonction libre | Faible : il manque le point d’entrée médiateur unique, pas les objets |
air-sandbox | AirSandbox (poseur de profil, apply()), AirSandboxProfile, AirLandlockPolicy + deux fonctions de compilation | Moyen — et ADR-112 nomme AirSandboxManager dans son propre titre alors que le code livre AirSandbox |
air-terminal | AirTerminal, PtyPair, AnsiCodec mais l’essentiel en fonctions libres (openpty, pty_*, tcgetpgrp…) | Fort : ADR-077 exige nommément un AirTerminalManager |
ADR-077 pose que les toits consomment une surface médiatrice. Le lanceur sera un toit, et ces trois domaines sont exactement ceux dont il aura besoin.
1.1 Managers manquants pour orchestrer un démarrage
| Manager | Ce qu’il porte | Jalon |
|---|---|---|
AirMountManager | mount/umount, pivot_root | 1 — sans lui PID 1 ne monte ni /proc, ni /sys, ni /dev |
AirPowerManager | reboot(2) : redémarrer, éteindre, arrêter | 1 |
AirDeviceManager | peupler /dev, suivre le branchement à chaud | 1–2 |
AirClockManager | régler l’horloge système au démarrage | 2 |
AirSandboxManager | poser une cage avant exec — ce que le lanceur consulte | 2–3 |
AirCgroupManager | créer un cgroup, y placer un processus, cgroup.kill, cgroup.events | 3 |
AirLinkManager | netlink : lien haut/bas, adresse, route | 3 |
AirServiceManager | superviser N services : dépendances, ordre, redémarrage | 3 |
AirVolumeManager | device-mapper, dm-verity | 4 |
AirSessionManager | les fonctions dissoutes de logind | après 3 |
L’AirCgroupManager mérite qu’on s’y arrête : c’est ce qui rend l’arrêt d’un service
fiable et l’attribution des journaux infalsifiable. Sans lui, air-launchd supervise
comme les scripts SysV — en traquant des PID et en les perdant.
1.2 Deux pièges
Le nom AirNetworkManager est déjà pris, et il désigne les sockets. Le manager de
configuration réseau ne peut pas s’appeler ainsi — collision que
ADR-029 est censé prévenir. AirLinkManager
est un candidat, le nom reste à arbitrer.
ADR-077 est appliqué inégalement, et l’audit du 2026-08-03 a montré que l’écart est plus
large que « trois domaines sans Manager ». Il porte dans les deux sens : trois domaines
mûrs n’ont pas de Manager, et à l’inverse quatre Managers existent sans que la doctrine les
nomme (AirEnvironmentManager, AirSignalManager, AirMemoryManager, AirSystemManager).
Plus grave, exister ne suffit pas à jouer le rôle : AirNetworkManager porte quatre
méthodes — le codec sockaddr et deux options de socket — pendant que les toits consomment
AirSocket directement pour tout le reste. La médiation n’est pas violée (aucun toit ne touche
la couche 0), mais elle ne passe pas par le Manager.
Il faudra soit compléter, soit acter que certains domaines s’en passent — mais pas laisser la doctrine dire une chose et le code une autre. L’état complet, domaine par domaine, est consigné dans l’amendement d’ADR-077.
2. Les outils d’administration
2.1 Le patron existe déjà
air-account et air-keystore sont livrés comme binaires autonomes ; air-sshd et
air-ssh ont leur sous-commande config. La doctrine fixe la forme : artefact binaire
(ADR-073), CLI get/set, export/import JSON
pour les agents et le versionnement, porte admin sur les mutations
(ADR-101), validation à l’écriture —
pas au démarrage. Une configuration invalide doit être refusée par la CLI, au bureau, pas
découverte à trois heures du matin quand la machine ne remonte pas.
2.2 « Un Manager = une commande » ne tient pas
Trois cas le cassent :
- des Managers n’ont rien à configurer —
AirMemoryManager,AirSignalManager,AirTaskManagersont des APIs, pas des sous-systèmes paramétrables ; - une configuration traverse plusieurs Managers — un « profil réseau », c’est le lien, l’adressage, la résolution, demain le filtrage ;
- certaines configurations n’appartiennent pas au poste — les profils de confinement d’une application sont déclarés dans son manifeste.
Le bon découpage n’est pas la liste des Managers, c’est la liste des domaines de configuration : un corps d’état persistant qu’un administrateur doit pouvoir écrire, inspecter, valider et exporter.
2.3 Clarification : les Managers ne lisent pas de configuration
Qui monte les systèmes de fichiers au démarrage ? Pas AirMountManager — c’est une API,
elle ne décide rien, elle exécute une opération typée. C’est air-launchd qui lit « quoi
monter, où, dans quel ordre » et appelle le Manager.
La configuration appartient donc aux orchestrateurs, pas aux Managers. Si les Managers lisaient de la configuration, la politique redescendrait en couche 1 — exactement ce qu’ADR-077 refuse. La couche 1 exécute, elle ne décide pas.
2.4 Les outils, par domaine de configuration
Déjà là : air-account, air-keystore, air-sshd config, air-ssh config.
| Outil | Domaine | Jalon |
|---|---|---|
air-mount | Quoi monter, où, dans quel ordre, options, politique d’échec | 1 |
air-system | Nom d’hôte, fuseau, locale, source de temps | 2 |
air-service | Services, ordre, dépendances, profil de confinement, redémarrage | 3 |
air-net | Profils réseau : sélection d’interfaces, adressage, routes, DNS | 3 |
air-log | Destination, niveau, rotation, quotas | 3 |
air-sandbox | Profils de confinement nommés, plafond du poste | 3 |
air-pkg / air-sysupdate | Applications, mise à jour système | 4+ |
Deux points de conception :
air-mount — l’ordre est un graphe, pas une liste. On ne monte pas /var/log avant
/var. Une liste ordonnée à la main casse dès qu’on insère une entrée : il faut exprimer
des dépendances, laisser l’outil calculer l’ordre, et refuser les cycles à l’écriture.
Il faut aussi une politique d’échec par entrée (bloquante ou non), sans quoi un disque
absent empêche la machine de démarrer.
air-net — les noms d’interface ne sont pas stables. « Toutes les cartes ou seulement
quelques-unes » appelle un sélecteur (par nom, adresse MAC, type, motif), pas une liste
de noms — sinon la configuration d’une machine ne vaut que pour elle, et une image générique
ne peut rien contenir d’utile.
2.5 Trois choix transverses
N binaires plutôt qu’un air à sous-commandes. Pas par goût : chaque outil devient
confinable séparément, avec son profil et son octroi. air-net n’a aucune raison de
pouvoir écrire la base de comptes. La granularité de l’outil épouse celle du privilège —
c’est déjà le choix fait pour air-account et air-keystore.
Chaque outil doit savoir travailler hors ligne, pour produire un artefact au moment de la construction de l’image, pas seulement sur une machine vivante. Cela impose dès la conception un mode « produire vers tel arbre » en plus du mode « modifier ce système » — facile à prévoir, très pénible à rétrofitter.
Validation à l’écriture, jamais au démarrage (cf. §2.1).
3. Le placement de la configuration
C’est la partie qui a fait apparaître un trou.
3.1 Le mécanisme envisagé, et pourquoi il ne tient pas
Piste explorée : /etc sur la partition racine en lecture seule ; une partition inscriptible
montée à la demande (par exemple sur /air) contenant les vrais fichiers modifiables
sous /air/etc ; une commande d’administration monte /air, modifie, génère une version
signée, remonte /etc en écriture, y copie l’artefact, remonte /etc en lecture
seule, démonte /air.
Obstacle dur : on ne remonte pas une racine dm-verity en écriture. Ce n’est pas une
politique de montage, c’est la nature de la cible : le périphérique bloc est vérifié page par
page contre un arbre de Merkle dont la racine est signée et passée au démarrage. L’écriture
invaliderait l’arbre, et la cible ne la prend pas en charge. L’étape « remonter /etc en
écriture » est donc impossible si la racine est protégée. Et si elle ne l’est pas, tout
l’édifice d’intégrité tombe.
Deux conséquences en cascade.
Le modèle A/B. La racine est ce qu’on bascule atomiquement. Si la configuration vit dedans et mute, la racine n’est plus immuable, son empreinte verity change à chaque modification, et il faut re-signer la racine sur la machine — exactement la clé qu’on ne veut pas y mettre.
La signature locale ne vaut pas ce qu’elle semble valoir. Signée par quelle clé ? Si la machine détient une clé dont le système accepte les signatures, une machine compromise signe ce qu’elle veut. Sans coffre matériel — l’OTP du Pi n’en est pas un, et il n’y a pas de TPM — une clé locale est un fichier. Elle protège contre l’altération hors ligne ; pas contre un système compromis en marche, qui est la menace qui nous intéresse.
3.2 Le critère de découpage
Cette configuration décide-t-elle quel code s’exécute ?
- Oui → table de montage (on pourrait monter un autre
/usr), liste des services, profils de confinement. Ces configurations sont du code du point de vue de la sécurité. - Non → nom d’hôte, adresse réseau, fuseau,
known_hostsde l’utilisateur. Leur compromission est ennuyeuse ; elle n’ouvre pas la porte à l’exécution de code arbitraire.
| Où | Protection | Modifier | |
|---|---|---|---|
| Critique | dans l’image, couverte par verity | intégrité complète, signée hors machine | = nouvelle image, donc chemin A/B |
| Exploitation | partition inscriptible montée sur /etc/air | Landlock + porte admin | immédiat, par la CLI |
La seconde ligne n’est pas signée, et ce n’est pas un renoncement : ce qui la protège est que seuls les outils d’administration peuvent écrire ce chemin. La propriété fondatrice — un attaquant corrompt des applications, jamais le système — est préservée, une application n’étant ni root ni autorisée par Landlock. Et si l’attaquant est root, une signature locale ne l’aurait pas arrêté non plus.
3.3 Réduire le problème avant de le résoudre
Beaucoup de ce qui ressemble à de la configuration n’en est pas. Le disque externe est le cas
d’école : il ne demande aucune configuration, mais une politique (dans l’image) plus
un événement — air-device voit apparaître un bloc amovible, la politique dit « les
amovibles se montent sous /media/<uuid>, toujours en nosuid,nodev,noexec, propriété de
l’utilisateur de la session », c’est monté. Rien n’a été modifié, rien signé, aucun
redémarrage.
Première étape : reclasser. Une bonne moitié de ce qu’on croit devoir rendre mutable est une politique fixe plus des événements d’exécution.
3.4 Pour le reste : la délégation bornée
L’image ne fixe pas les valeurs, elle fixe l’enveloppe ; la partie mutable remplit à l’intérieur ; le lanceur refuse tout ce qui dépasse.
L’idée-clé : rendre la configuration mutable incapable d’exprimer un énoncé dangereux, plutôt que de la protéger cryptographiquement — protection qui ne tient pas sans coffre matériel.
- Montages : l’image déclare la table système et une politique de délégation — « sous
/media/**et/mnt/**, des montages sont permis, obligatoirement ennosuid,nodev,noexec, jamais par-dessus un chemin système ». Un attaquant qui réécrit la partie mutable monte un disque inutile ; il ne monte rien par-dessus/usret ne rend rien exécutable. Ça règle aussi le disque interne permanent, sans image nouvelle. - Services : l’image déclare les services système et le plafond de privilège de
chaque emplacement délégable. Une application enregistre un service d’arrière-plan dans
les limites de son octroi ; elle ne s’accorde pas
CAP_NET_ADMINen écrivant un fichier. - Réseau : catégorie inoffensive — une adresse IP n’exécute pas de code.
Ce qui reste vraiment structurel — modifier le privilège d’un service système, changer la table de montage système — est rare, et le redémarrage y est souhaitable : c’est le moment où la nouvelle configuration est vérifiée avant d’être active. Tous les systèmes comparables font ainsi ; ChromeOS et Android l’interdisent purement, Silverblue et MicroOS l’autorisent au prix d’un redémarrage. On ne peut pas à la fois vérifier au démarrage et modifier à chaud.
Le coût, sans le cacher : la difficulté se déplace vers le choix des enveloppes. Trop étroites, l’utilisateur se heurte à des murs ; trop larges, elles ne protègent plus rien. Et les élargir exige une nouvelle image. C’est un vrai travail de conception, mais fini et anticipable, là où la signature locale était une impasse.
Pourquoi c’est le bon mécanisme : c’est déjà le nôtre. L’enveloppe déclarée par l’image que la partie mutable ne peut dépasser, c’est exactement la « policy du poste » qui plafonne ce qu’un manifeste d’application peut demander. Même structure : une déclaration immuable qui borne, une déclaration mutable qui demande, un arbitre qui calcule l’intersection. Un seul concept à comprendre, implémenter et auditer.
3.5 Un avantage propre à Air
Sur un Linux classique, /etc est un zoo de fichiers texte écrits par des dizaines de
paquets, dont beaucoup exigent l’écriture à l’exécution — d’où les surcouches et les tmpfs
peuplés au démarrage des systèmes à racine immuable. Air n’a pas ce problème : la
configuration est binaire et le projet contrôle qui écrit quoi. /etc peut être quasi vide
dans l’image, et /etc/air un simple point de montage. C’est un bénéfice direct de la
doctrine de configuration binaire, qui n’avait pas été anticipé pour cela.
4. Le cas de la base de comptes
Elle met le critère du §3.2 à l’épreuve : elle est critique, et pourtant elle ne peut pas être dans l’image.
4.1 Elle décide bel et bien quel code s’exécute
Qui écrit la base de comptes peut créer un compte d’UID 0, s’ajouter à un groupe privilégié, poser un mot de passe qu’il connaît, changer le shell d’un compte, ou pointer le répertoire personnel d’un utilisateur privilégié vers un répertoire qu’il contrôle — dont les fichiers d’initialisation s’exécuteront sous cette identité.
C’est donc, avec les profils de confinement, l’état mutable le plus critique de la machine. Et elle doit rester modifiable : on ne reconstruit pas une image pour changer un mot de passe.
Il existe donc une catégorie non nommée au §3.2 : critique et nécessairement mutable. Elle est peu peuplée — la base de comptes en est le cas principal.
4.2 Ce qui la protège
Quatre mesures, dont trois existent déjà :
- Monopole d’écriture — seul
air-accountécrit ces artefacts (Landlock), etair-accountest lui-même un binaire signé de l’image. Aucun éditeur, aucun shell, même sous root. - Porte admin sur toute mutation (ADR-101).
- L’enveloppe, et c’est l’ajout qui compte : l’image déclare les UID et GID système
réservés.
air-accountne peut alors créer ni un second UID 0, ni ajouter quelqu’un à un groupe privilégié réservé. La délégation bornée appliquée aux comptes — elle retire le pire scénario, l’escalade par création de compte. - Journalisation de chaque mutation via
air-log. On n’empêche pas root ; on le rend bruyant.
4.3 Le point rassurant, spécifique à Air
Sur un Linux classique, compromettre la base de comptes équivaut à tout perdre : on devient root, et root exécute ce qu’il veut.
Dans Air, non. Si le lanceur refuse d’exécuter un binaire non signé, compromettre la base de comptes donne une identité, pas du code arbitraire : l’attaquant devient root et ne peut lancer que ce que le système accepte déjà. C’est une position sensiblement plus faible, et cela justifie a posteriori d’avoir mis l’arbitre de lancement au cœur du modèle.
4.4 Où exactement
Sur la partition inscriptible montée sur /etc/air, avec des permissions différenciées —
ce que la structure actuelle permet, les schémas étant trois artefacts distincts
(Passwd, Group, Shadow).
À conserver impérativement au passage en binaire : passwd et group doivent rester
lisibles (la résolution de noms en a besoin), shadow ne l’être que par air-account.
Fondre les trois obligerait à tout mettre en 0600 et casserait la résolution.
4.5 Là où l’absence de chiffrement mord
shadow est un actif de confidentialité, pas seulement d’intégrité. Sur une machine sans
chiffrement de disque — décision actée pour le Raspberry Pi, ADR-014 amendé — les empreintes
sont lisibles par quiconque a un accès physique. Argon2id rend l’attaque coûteuse, il ne
l’empêche pas.
C’est le premier endroit concret où cette décision a un coût identifiable. Elle n’est pas remise en cause — l’accès physique est hors du modèle de menace du Pi — mais c’est l’argument le plus solide pour chiffrer au moins cette partition le jour où un ancrage matériel existera.
5. Questions ouvertes
- Comment naît le premier compte ? À l’installation la base est vide : l’installeur crée le premier administrateur, donc il détient l’espace d’un instant le pouvoir d’écrire la base sans porte admin, puisqu’aucun administrateur n’existe pour l’ouvrir. Qui a ce droit, quand la fenêtre se referme, et comment on prouve qu’elle s’est refermée.
- Quelles enveloppes exactement, pour les montages et pour les services ? C’est le travail de conception que le §3.4 déplace, et il n’est pas fait.
AirLinkManager: le nom.AirNetworkManagerest pris par les sockets.- Complète-t-on ADR-077 pour les trois domaines sans Manager, ou acte-t-on l’exception ?
- Chiffrement de la partition de configuration : différé, ou instruit dès qu’un ancrage matériel existe ?
Licence du document : MPL 2.0 Statut : note de travail, conversation en cours.