Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

ADR-137 — Identité machine stable comme principal de certificat : empreinte de la host key, CA-attestée, découplée du hostname/IP

Statut : Accepté (2026-07-29, décision BDFL). RFC de direction (ADR-015). S’appuie sur ADR-109 (certificats SSH + CA), ADR-108 (air-keystore, host key), ADR-121 (provisioning first-boot), ADR-134 (migration host key → keystore), ADR-029 (nommage).

Catégorie : raffinement de sémantique d’ADR-109 (couche 2 + packaging). Compagnon de la séquence d’incréments ADR-109.

Contexte

Un certificat d’hôte SSH standard lie une clé à des principals = noms d’hôte. Or un nom d’hôte (ou une IP, ou un nom de domaine) change dans la vie d’une machine. Une authentification par certificat adossée au hostname casse dès qu’on renomme ou ré-adresse la machine, alors que la machine — physiquement, logiquement — est la même.

Directive BDFL (2026-07-29). « Ancrer l’identité d’une machine sur une clé unique et stable, pas sur un hostname/IP mutable. À l’installation du keystore, initialiser réellement le keystore et générer la clé qui identifie le host. Le certificat porte cette clé dans le champ principal ; la machine peut changer de nom, le certificat reste valable. »

L’insight : dissocier l’adresse par laquelle on joint une machine (mutable, sans importance cryptographique) de son identité (stable). SSH prouve déjà, au KEX, la possession de la host key ; il suffit d’ériger l’empreinte de cette host key en identité de principal.

Décision

1. Identité machine fpr(K_pub) = empreinte SHA256 de la host key

fpr(K_pub) est l’empreinte SHA256 (représentation canonique SHA256:<base64 sans padding>, forme OpenSSH) de la host key Ed25519 de la machine (celle de hostkeys.aircfg, [ADR-134]). Aucune clé nouvelle : la host key est l’ancre d’identité, son empreinte est fpr(K_pub). fpr(K_pub) est stable pour la vie de la machine (indépendant du hostname/IP/domaine).

2. Émission : valid_principals = [fpr(K_pub)]

Un certificat d’hôte émis pour une machine porte, en valid_principals, l’empreinte de la clé qu’il certifie (fpr(K_pub)), au lieu d’un hostname. (Chemin d’émission : incrément « émission » d’ADR-109 + CLI air-keysign.)

3. Vérification client : invariant de cohérence de soi + confiance CA

Le client (Air) vérifie un certificat d’hôte ainsi (fail-closed) :

  1. Signé par une CA d’hôtes de confiance (magasin trusted_ca.aircfg, périmètre Host) — c’est la CA qui autorise : une machine CA-signée est un membre légitime de la flotte.
  2. validité temporelle, non révoqué, options critiques connues (déjà [ADR-109] Inc.1).
  3. Cohérence de soi — fpr(K_pub)valid_principalsK_pub = la clé certifiée : le client recalcule l’empreinte de la clé d’hôte que le serveur a prouvé posséder au KEX, et exige qu’elle figure dans les principals. Le certificat doit donc attester sa propre clé — il ne peut pas prétendre une identité qui n’est pas celle de la clé certifiée.

Le check hostname d’[ADR-109] Inc.1 (#522) est remplacé par cet invariant (3). La CA autorise ; l’identité est vérifiée, pas seulement étiquetée.

Pourquoi (3) plutôt qu’un principal purement étiquette (non vérifié) ? Coût nul (une empreinte à recalculer) contre un gain réel : l’identité machine devient une propriété vérifiée et honnête (robuste à une émission boguée/malveillante qui logerait un mauvais principal), et le journal « connecté à la machine fpr(K_pub) » est fiable. Doctrine Air : vérifie, ne fais pas confiance — la confiance CA sert à l’autorisation, pas à l’intégrité de l’identité.

Le KEX prouvant déjà la possession de la host key, le triplet **{CA vouche} + {KEX prouve la clé}

  • {principal == empreinte de cette clé}** identifie quelle machine (par fpr(K_pub), stable) a répondu, sans épingler N machines : on épingle une CA.

4. Initialisation à l’installation (postinst)

Le postinst du paquet (keystore / air-sshd) initialise le keystore et génère la host key si absente (Ed25519, hostkeys.aircfg en 0600) — donc fpr(K_pub) existe dès l’installation, sans intervention. Comble le trou de provisioning ([ADR-121], postinst binaires-seuls). Idempotent : une host key présente n’est pas régénérée (l’identité ne doit jamais changer sous les pieds).

5. Interop OpenSSH : via HostkeyAlias (pas Hostname)

Un client OpenSSH standard peut interopérer, en découplant l’adresse de l’identité avec HostkeyAlias :

Host ma-machine
    Hostname     203.0.113.10                                   # l'ADRESSE (mutable)
    HostkeyAlias SHA256:dadSVa461jwd+hn0ed1Gdck5rIGRetfmDZNysbonqGc   # l'IDENTITÉ = fpr(K_pub) (stable)

Le cert Air portant fpr(K_pub), OpenSSH se connecte par IP et matche le principal contre le HostkeyAlias. Renommage/re-IP ⇒ on change Hostname, on garde HostkeyAlias ⇒ l’auth tient. Hostname ne convient pas (OpenSSH y résout l’adresse). Le client Air n’a besoin d’aucun alias : il recalcule fpr(K_pub) depuis la clé (invariant 3).

(Réserve : le matching exact de principal contre HostkeyAlias peut varier selon la version d’OpenSSH — à valider sur une install réelle, cf. incrément interop d’ADR-109.)

Réserve CONFIRMÉE et tranchée (BDFL, 2026-07-30) — interop cert d’hôte par HostkeyAlias INOPÉRANTE, documentée comme limite. L’incrément interop d’ADR-109 (Inc.5) l’a prouvé sur OpenSSH 10.2p1 : le client abaisse la casse du HostkeyAlias avant de le comparer aux valid_principals du certificat. Or M = SHA256:<base64> est sensible à la casse (§3 : abaisser la casse ferait collisionner des identités) ⇒ le principal ne matche jamais (Certificate invalid: name is not a listed principal). Prouvé par contrôle (même montage, principal en minuscules signé par une CA ssh-keygen pure ⇒ réussit). Décision BDFL : documenter la limite, ne PAS émettre de second principal en minuscules — Air n’affaiblit pas son modèle d’identité (résistance aux collisions de M) pour contourner une perte d’information d’un client tiers. Ce qui fonctionne : l’émission d’Air (ssh-keygen -L lit le cert, principal = M), la vérification Air-native (le client Air recalcule l’empreinte byte-à-byte, sans alias — invariant 3), et l’interop cert utilisateur OpenSSH (TrustedUserCAKeys, prouvée). Seul le pont @cert-authority + HostkeyAlias pour un client OpenSSH vérifiant un cert d’hôte Air est hors de portée — limite d’OpenSSH, pas d’Air.

Chemin opt-in (à la demande de l’opérateur, [ADR-115] §6). La CLI air-keystore offre, explicitement et jamais par défaut, cert issue-host --openssh-hostkey-alias-compat qui ajoute lowercase(M) comme second principal (le cert garde M exact pour Air). Un client OpenSSH configuré @cert-authority + HostkeyAlias matche alors la forme abaissée. Coût assumé et documenté : lowercase(M) a une résistance aux collisions réduite (repli de casse base64) ; Air ne l’utilise jamais pour sa propre vérification (invariant 3, M exact). L’opérateur qui a besoin de l’interop l’active en connaissance de cause ; le défaut reste M exact seul.

Conséquences

Positives. Identité stable (renommage/re-IP sans casse) ; flotte simple (épingler une CA, pas N machines) ; identité vérifiée (invariant 3), pas décorative ; provisioning à l’install ; interop OpenSSH possible (HostkeyAlias).

Coûts / risques. Divergence de sémantique vs le host-cert « principal=hostname » d’OpenSSH (atténuée par HostkeyAlias). L’fpr(K_pub) reste lié à la host key : une rotation de host key change fpr(K_pub) (comme une réinstallation change l’identité — comportement voulu ; rotation = re-publication). La confiance repose sur la CA : sa compromission autoriserait toute machine (inhérent au modèle CA, hors périmètre).

Emplacements d’implémentation

MorceauIncrément
Helper fpr(K_pub) (forme SHA256:…)air-sshd::host_identity (ou air-keystore)identité machine
Client : check hostname → fpr(K_pub), valid_principalsair-sshd/src/host_trust.rs (modifie #522)identité machine
postinst : keystore init + host-key-gen idempotentpackaging (maintainer scripts)identité machine
Émission : valid_principals = [fpr(K_pub)]orchestration d’émissionADR-109 Inc.4 + CLI
Interop OpenSSH réel (HostkeyAlias)testADR-109 Inc.5

Alternatives rejetées

  • Clé « machine-id » dédiée (distincte de la host key) : deux clés à gérer pour une seule identité ; la host key est déjà l’ancre. Refusé (BDFL).
  • Principal purement étiquette (non vérifié) : décoratif, non robuste à une émission menteuse. Refusé au profit de l’invariant (3).
  • Pinning par-machine (le client épingle fpr(K_pub) de chaque serveur) : ne passe pas à l’échelle d’une flotte ; la confiance CA suffit. Refusé (BDFL).
  • Principal = hostname (OpenSSH classique) : casse au renommage — le problème même que résout cet ADR.