Authentification forte (YubiKey)
Chaque membre du réseau peut associer à son compte une clé YubiKey principale et une clé de secours, en plus de son mot de passe (qui reste obligatoire et sert de repli automatique).
Le principe clé : un seul enrôlement par clé, sur le poste
d’administration. Tout le reste se propage déclarativement avec just apply —
la clé n’est jamais branchée sur les hôtes du parc, seulement au moment de s’en
servir.
Ce que couvre une clé
Section intitulée « Ce que couvre une clé »| Usage | Mécanisme | Effet |
|---|---|---|
| Session, sudo, écran de connexion | pam_u2f (sufficient) | Toucher la clé remplace le mot de passe |
| Disques chiffrés (LUKS) | FIDO2 hmac-secret | Déverrouillage au boot en touchant la clé |
| SSO (Kanidm) | Passkey WebAuthn | Connexion sans mot de passe aux services |
| Vaultwarden | WebAuthn (2FA) | Second facteur du coffre-fort |
Les quatre moyens de connexion Kanidm
Section intitulée « Les quatre moyens de connexion Kanidm »Un compte Kanidm expose plusieurs moyens d’authentification, indépendants les uns des autres. L’objectif est qu’aucune perte de clé ne verrouille un compte.
| Moyen | Nature Kanidm | Support |
|---|---|---|
| YubiKey principale | Passkey WebAuthn | Clé physique (PIN + toucher) |
| YubiKey de secours | Passkey WebAuthn | Clé physique rangée à part |
| Clé logicielle | Passkey WebAuthn | Coffre-fort (Bitwarden, KeePassXC) |
| Mot de passe + TOTP | Credential primaire | Filet de sécurité, jamais supprimé |
Les trois premiers sont des passkeys : Kanidm les stocke côte à côte et les propose ensemble au navigateur. Le quatrième vit ailleurs (le credential primaire) et ne peut pas être écrasé par une cérémonie WebAuthn.
Enrôler une clé
Section intitulée « Enrôler une clé »-
Brancher la YubiKey de l’utilisateur sur le poste admin, puis :
Fenêtre de terminal just yubikey <login> # clé principale (PIN FIDO2 + ~3 touches)just yubikey <login> backup # clé de secours (optionnel)Si la clé n’a pas encore de PIN FIDO2, la recette le crée d’abord (indispensable pour Kanidm, voir plus bas).
-
Committer et déployer :
Fenêtre de terminal git add usr/secrets/yubikeys.jsonjust commit "user(yubikey): <login>"just apply -
C’est tout : session et sudo répondent à la clé sur tous les postes de l’utilisateur, et les hôtes chiffrés inscrivent la clé dans leurs en-têtes LUKS eux-mêmes, au déploiement.
Ordre d’enrôlement des passkeys
Section intitulée « Ordre d’enrôlement des passkeys »Le principe : isoler chaque cérémonie de tout ce qui pourrait l’intercepter. Une passkey physique s’enrôle dans un navigateur sans extension de coffre-fort, une passkey logicielle s’enrôle dans le navigateur habituel. L’ordre garantit qu’un filet de sécurité existe avant chaque étape risquée.
-
Mot de passe et TOTP d’abord. Ils vivent hors des passkeys et ne peuvent pas être écrasés. Tant qu’ils existent, aucune erreur des étapes suivantes n’enferme l’utilisateur dehors.
-
Clé logicielle ensuite, dans le navigateur habituel, extension du coffre-fort déverrouillée. Au moment où le coffre propose d’enregistrer, choisir créer un nouvel élément, jamais « enregistrer dans un élément existant ».
-
YubiKey principale, dans un navigateur jetable et vierge : sans extension, l’interception est impossible.
Fenêtre de terminal firefox --new-instance --profile "$(mktemp -d)" https://idm.domain.tldPuis coller le lien de réinitialisation Kanidm imprimé par
just yubikey. -
YubiKey de secours, dans le même navigateur jetable, autre clé branchée.
-
Vérifier le résultat avant de fermer : le compte doit présenter trois passkeys. Voir Diagnostic des passkeys.
Diagnostic des passkeys
Section intitulée « Diagnostic des passkeys »Pour lister réellement les passkeys d’un compte, ouvrir une session interactive de mise à jour des credentials :
kanidm person credential update <login> --name idm_adminPour voir ce que le serveur envoie réellement au navigateur, ouvrir la console
(F12) sur la page de connexion, coller ce code, puis cliquer sur
Passkey :
const _get = navigator.credentials.get.bind(navigator.credentials);navigator.credentials.get = (o) => { const b64 = (v) => btoa(String.fromCharCode(...new Uint8Array(v))); const p = o.publicKey; console.log("rpId:", p.rpId, "| uv:", p.userVerification); console.log("allowCredentials:", (p.allowCredentials || []).map((c) => b64(c.id))); return _get(o);};Le nombre d’entrées de allowCredentials est la vérité : c’est la liste
exacte des passkeys que Kanidm connaît pour ce compte.
| Symptôme | Cause probable |
|---|---|
| Le navigateur réclame le PIN d’une YubiKey, aucune fenêtre de coffre-fort | Passkey logicielle orpheline, absente du coffre |
allowCredentials compte moins d’entrées que prévu | Une cérémonie a écrasé une passkey |
| Le PIN est réclamé alors que la clé physique n’est pas visée | Kanidm n’émet pas de transports, voir ci-dessous |
Une clé pour plusieurs comptes
Section intitulée « Une clé pour plusieurs comptes »Une même clé physique peut servir à plusieurs utilisateurs : répéter simplement l’enrôlement pour chaque login, clé branchée.
just yubikey <login1>just yubikey <login2> # même clé physique, autre compteChaque enrôlement crée des credentials propres au compte (PAM, LUKS, et un
lien de réinitialisation Kanidm par utilisateur pour refaire la cérémonie web
avec la même clé). Les passkeys Kanidm sont non résidentes : elles
n’occupent aucun emplacement sur la clé, le nombre de comptes est illimité.
Une révocation (just yubikey <login> main revoke) ne touche que le login
visé.
Sous le capot
Section intitulée « Sous le capot »| Fichier | Contenu | Statut |
|---|---|---|
usr/secrets/yubikeys.json | Credentials publics (PAM, id FIDO2, sel) | Public, versionné |
secrets.yaml → yubikey/<login>/<clé>/luks-secret | Secret LUKS dérivé de la clé | Chiffré sops |
secrets.yaml → luks-passphrase | Passphrase saisie à l’installation disko | Chiffré sops (demandée au 1ᵉʳ enrôlement) |
- PAM : l’origine est fixe (
pam://<domaine>), donc un credential vaut sur tout le parc. Le moduledarkone.system.yubikey(activé automatiquement dès que le registre existe) distribue/etc/u2f_mappingssur chaque hôte. - LUKS : le secret dérivé (
HMAC(clé, sel)) n’est calculable qu’avec la clé physique. Chaque hôte chiffré l’inscrit dans son en-tête LUKS (keyslot + tokensystemd-fido2, le format exact desystemd-cryptenroll) via un service idempotent, et retire ceux qui ne sont plus déclarés.
Révoquer une clé perdue
Section intitulée « Révoquer une clé perdue »just yubikey <login> main revoke # ou backupjust commit "user(yubikey): revoke <login>" && just applyAu déploiement, le credential PAM disparaît des hôtes et les keyslots LUKS correspondants sont supprimés. Penser aussi à retirer la passkey côté Kanidm (interface web ou jeton de réinitialisation) et Vaultwarden.
Limites et suite
Section intitulée « Limites et suite »- Le TOTP reste disponible côté web (Kanidm, Vaultwarden), pas au login local.
- Déverrouillage LUKS sans code PIN (touche seule) dans cette version.
- À venir : clés SSH FIDO2 (
ed25519-sk) et signature git, mode « second facteur obligatoire » par hôte, déchiffrement sops admin conditionné à la clé (age-plugin-fido2-hmac).