ADR-101 — Gate mot de passe administrateur pour les mutations de la base comptes (mécanisme)
Statut : Accepté (2026-07-24, décision BDFL). RFC de mécanisme
(ADR-015) répondant à la dépendance
explicitement différée par ADR-073
§Décision règle 2 (« le mécanisme d’autorisation exact … fera l’objet d’un RFC
dédié »). Companion de ADR-100 (base comptes
binaire) : premier consommateur = le CLI air-account (A.5b).
Catégorie : Sécurité — mécanisme d’autorisation. N’altère aucune couche scellée
(logique couche 2, dans le CLI ; s’appuie sur air-crypto couche 1).
Contexte
[ADR-073] impose que toute mutation de configuration Air passe par un CLI dédié qui
exige la ressaisie du mot de passe administrateur, pour qu’un attaquant ayant
pris un shell (même avec sudo permissif) ne puisse pas trivialement réécrire
la configuration — il lui faut un secret qu’il n’a pas. [ADR-073] a renvoyé
le mécanisme exact à un RFC. [ADR-100] ayant livré la base credentials binaire
(/etc/air/shadow.aircfg, hachages Argon2id PHC) et son CLI d’administration,
ce mécanisme peut être spécifié.
Décision
1. L’« administrateur » = root (uid 0)
Le mot de passe administrateur est le credential de root dans
/etc/air/shadow.aircfg. Pas de secret séparé : root est l’administrateur de la
machine, et son hachage existe déjà dans la base. Vérification en temps constant
via [air_crypto::AirArgon2::verify_password].
2. Toutes les mutations sont gatées
air-account user add|mod|del, group add|mod|del, passwd <name> redemandent
le mot de passe administrateur (celui de root) avant toute écriture. Mismatch
⇒ refus, zéro mutation, code d’erreur. La vérification lit shadow.aircfg
(root-only) — cohérent avec le régime 0600.
passwd <name>demande deux secrets : le mot de passe admin (autorisation) puis le nouveau mot de passe de<name>(donnée). Les deux sont lus ligne par ligne sur stdin (jamaisargv, invisible àps) ; flags--admin-password/--passwordpour l’automatisation et les tests.
3. Gate actif ⇔ root a un hachage Argon2id
Le gate ne s’active que si l’entrée root de shadow.aircfg porte un hachage
Argon2id ($argon2id$…) — le seul format que verify_password sait vérifier.
Sinon (root absent, verrouillé !/*, ou hachage $6$/$5$ importé
d’un /etc/shadow glibc), c’est la fenêtre de bootstrap : le gate est sauté,
seul l’accès root au FS protège encore.
Conséquence — flux de déploiement ([ADR-100] import) : import (base texte
/etc → binaire ; root $6$) puis air-account passwd root (pose un
$argon2id$ admin) active le gate. Avant cette pose, les mutations restent
possibles pour l’opérateur root (bootstrap). import lui-même n’est jamais gaté
(il exige déjà l’accès root et précède l’existence d’un credential admin).
4. Objectif assumé — retarder, pas rendre impossible ([ADR-073])
Le gate est une défense en profondeur. root peut toujours éditer le binaire
shadow.aircfg directement, ou remplacer air-account : le gate élève le coût
et supprime la mutation triviale par simple air-account … sans le secret. La
contrainte dure (sandbox/Landlock, bit immuable) viendra avec air-launchd
(hors périmètre, cf. ADR-041 §6).
Conséquences
- Positif : muter la base exige désormais le mot de passe de root en plus de
l’accès FS ; un shell compromis (même
sudo) ne suffit plus ; point unique outillable (audit possible). - Ergonomie : chaque mutation devient une action authentifiée explicite — choix assumé (rigueur > commodité, [ADR-073]).
- Bootstrap : documenté et sûr (fenêtre root-FS jusqu’à la pose du 1ᵉʳ mot de passe admin Argon2id).
- Limites v1 (hors périmètre) : pas de verrouillage/anti-bruteforce (le gate n’est pas une frontière dure) ; l’admin ≠ root (multi-admins) et le portage du gate à d’autres composants à conf ([ADR-073]) sont différés.
Alternatives rejetées
- Credential admin dédié (
/etc/air/admin.aircfgséparé de root) — plus d’isolation (compromettre root ≠ muter la conf) mais plus de machinerie + bootstrap dédié ; différé : root-comme-admin suffit à l’objectif ADR-073 en v1. - Gate seulement sur les opérations « sensibles » (passwd/suppressions) — laisse les ajouts/modifs libres ; incohérent avec « toute mutation » d’[ADR-073]. Rejeté.
- Mot de passe admin en
argv(--admin-passwordpar défaut) — visible dansps; réservé à l’automatisation, stdin est le défaut. - Vérifier un
$6$importé —verify_passwordest Argon2id-only (charte moderne) ; plutôt que d’embarquercrypt(3)legacy, on exige la pose d’un mot de passe admin Argon2id (fenêtre de bootstrap explicite).