Actualiser modules/users.nix

This commit is contained in:
2026-08-18 15:04:08 +02:00
parent 64a0983856
commit 96415babe7
+29 -562
View File
@@ -1,567 +1,34 @@
{ pkgs, ... }: { pkgs, ... }:
let
# ============================================================
# Assistant interactif de première connexion
#
# Étape 1 : changement du mot de passe local
# Étape 2 : changement du PIN YubiKey
# ============================================================
firstLoginSetup = pkgs.writeShellScript "first-login-setup" ''
set -u
state_dir="$HOME/.local/state/nixos-workstations"
password_marker="$state_dir/password-initialized"
yubikey_marker="$state_dir/yubikey-pin-initialized"
runtime_dir="''${XDG_RUNTIME_DIR:-/tmp}"
active_file="$runtime_dir/nixos-workstations-first-login.active"
# ----------------------------------------------------------
# Permet au superviseur de savoir que l'assistant tourne.
# ----------------------------------------------------------
printf '%s\n' "$$" > "$active_file"
cleanup() {
${pkgs.coreutils}/bin/rm -f "$active_file"
}
trap cleanup EXIT HUP INT TERM
# ----------------------------------------------------------
# Couleurs
# ----------------------------------------------------------
RESET="\033[0m"
BOLD="\033[1m"
BLUE="\033[38;5;39m"
CYAN="\033[38;5;45m"
GREEN="\033[38;5;82m"
YELLOW="\033[38;5;220m"
RED="\033[38;5;196m"
GREY="\033[38;5;245m"
WHITE="\033[38;5;255m"
separator() {
printf "''${BLUE}''${RESET}\n"
}
clear_screen() {
printf "\033[2J\033[H"
}
header() {
clear_screen
echo
separator
echo
printf " ''${BOLD}''${CYAN}🔐 CONFIGURATION DE VOTRE COMPTE''${RESET}\n"
echo
separator
echo
}
# ==========================================================
# ÉTAPE 1 : MOT DE PASSE LOCAL
# ==========================================================
if [ ! -e "$password_marker" ]; then
header
printf " ''${BOLD}''${CYAN}ÉTAPE 1 SUR 2''${RESET}\n"
echo
printf " ''${BOLD}''${WHITE}Personnalisation du mot de passe de secours''${RESET}\n"
echo
printf " Votre compte possède actuellement un mot de passe temporaire.\n"
printf " Vous devez maintenant le remplacer par votre mot de passe\n"
printf " personnel.\n"
echo
separator
echo
printf " ''${CYAN}''${RESET} Saisissez votre mot de passe temporaire actuel.\n"
echo
printf " ''${CYAN}''${RESET} Choisissez votre nouveau mot de passe personnel.\n"
echo
printf " ''${CYAN}''${RESET} Confirmez votre nouveau mot de passe.\n"
echo
separator
echo
printf " ''${GREY}Ce mot de passe reste local au poste.''${RESET}\n"
printf " ''${GREY}Il pourra être utilisé comme solution de secours si votre''${RESET}\n"
printf " ''${GREY}YubiKey est indisponible.''${RESET}\n"
echo
separator
echo
printf " ''${BOLD}''${YELLOW}Veuillez maintenant suivre les instructions ci-dessous.''${RESET}\n"
echo
# --------------------------------------------------------
# IMPORTANT NixOS
#
# On utilise volontairement le wrapper SUID NixOS.
#
# NE PAS remplacer par :
# ${pkgs.shadow}/bin/passwd
# --------------------------------------------------------
if /run/wrappers/bin/passwd; then
# Le marqueur est créé immédiatement après le succès
# confirmé par passwd.
${pkgs.coreutils}/bin/mkdir -p "$state_dir"
${pkgs.coreutils}/bin/touch "$password_marker"
echo
separator
echo
printf " ''${BOLD}''${GREEN} MOT DE PASSE MODIFIÉ AVEC SUCCÈS''${RESET}\n"
echo
printf " Votre nouveau mot de passe personnel est maintenant actif.\n"
echo
separator
echo
${pkgs.coreutils}/bin/sleep 3
else
echo
separator
echo
printf " ''${BOLD}''${RED} LE MOT DE PASSE N'A PAS ÉTÉ MODIFIÉ''${RESET}\n"
echo
printf " L'opération a été annulée ou a échoué.\n"
printf " Cette étape sera automatiquement reproposée.\n"
echo
separator
echo
${pkgs.coreutils}/bin/sleep 3
exit 1
fi
fi
# ==========================================================
# ÉTAPE 2 : PIN YUBIKEY
# ==========================================================
if [ ! -e "$yubikey_marker" ]; then
header
printf " ''${BOLD}''${CYAN}ÉTAPE 2 SUR 2''${RESET}\n"
echo
printf " ''${BOLD}''${WHITE}Personnalisation du PIN de votre YubiKey''${RESET}\n"
echo
printf " Votre YubiKey possède actuellement le PIN temporaire\n"
printf " fourni lors de la préparation du poste.\n"
echo
separator
echo
printf " ''${CYAN}''${RESET} Saisissez votre PIN temporaire actuel.\n"
echo
printf " ''${CYAN}''${RESET} Choisissez votre nouveau PIN personnel.\n"
echo
printf " ''${CYAN}''${RESET} Confirmez votre nouveau PIN.\n"
echo
separator
echo
printf " ''${GREY}Votre PIN est enregistré directement dans la YubiKey.''${RESET}\n"
printf " ''${GREY}Il n'est ni enregistré sur ce poste, ni dans Git.''${RESET}\n"
printf " ''${GREY}Le service informatique ne connaît pas votre nouveau PIN.''${RESET}\n"
echo
separator
echo
printf " ''${BOLD}''${YELLOW} ATTENTION AU PAVÉ NUMÉRIQUE''${RESET}\n"
echo
printf " Vérifiez que ''${BOLD}Verr Num''${RESET} est activé avant de saisir votre PIN.\n"
printf " En cas de doute, utilisez les chiffres situés au-dessus\n"
printf " des lettres du clavier.\n"
echo
separator
echo
printf " ''${BOLD}''${YELLOW}Veuillez maintenant suivre les instructions ci-dessous.''${RESET}\n"
echo
if ${pkgs.yubikey-manager}/bin/ykman fido access change-pin; then
# Le marqueur est créé immédiatement après que ykman
# confirme réellement le changement du PIN.
${pkgs.coreutils}/bin/mkdir -p "$state_dir"
${pkgs.coreutils}/bin/touch "$yubikey_marker"
echo
separator
echo
printf " ''${BOLD}''${GREEN} PIN YUBIKEY MODIFIÉ AVEC SUCCÈS''${RESET}\n"
echo
printf " Votre nouveau PIN personnel est maintenant actif.\n"
echo
separator
echo
${pkgs.coreutils}/bin/sleep 3
else
echo
separator
echo
printf " ''${BOLD}''${RED} LE PIN N'A PAS ÉTÉ MODIFIÉ''${RESET}\n"
echo
printf " L'opération a été annulée ou a échoué.\n"
echo
if [ -e "$password_marker" ]; then
printf " ''${GREEN} Votre nouveau mot de passe est déjà enregistré.''${RESET}\n"
printf " Il ne vous sera pas demandé de le modifier à nouveau.\n"
echo
fi
printf " Seule la configuration du PIN sera reproposée.\n"
echo
separator
echo
${pkgs.coreutils}/bin/sleep 3
exit 1
fi
fi
# ==========================================================
# CONFIGURATION TERMINÉE
# ==========================================================
header
printf " ''${BOLD}''${GREEN} VOTRE POSTE EST PRÊT''${RESET}\n"
echo
separator
echo
printf " La configuration initiale de votre compte est terminée.\n"
echo
printf " ''${GREEN}''${RESET} Mot de passe personnel configuré\n"
printf " ''${GREEN}''${RESET} PIN personnel YubiKey configuré\n"
echo
separator
echo
printf " ''${BOLD}Pour vos prochaines connexions :''${RESET}\n"
echo
printf " ''${BOLD}YubiKey + PIN personnel''${RESET}\n"
echo
printf " Votre mot de passe local reste disponible comme solution\n"
printf " de secours si votre YubiKey est indisponible.\n"
echo
separator
echo
printf " Fermeture automatique"
for i in 1 2 3 4 5; do
printf "."
${pkgs.coreutils}/bin/sleep 1
done
echo
exit 0
'';
# ============================================================
# Superviseur
#
# Son rôle :
# - lancer l'assistant ;
# - le relancer s'il est fermé avant la fin ;
# - NE JAMAIS tuer KDE ou la session.
# ============================================================
firstLoginSupervisor =
pkgs.writeShellScript "first-login-supervisor" ''
set -u
current_user="$(${pkgs.coreutils}/bin/id -un)"
# Pour le moment, uniquement Alice.
if [ "$current_user" != "alice" ]; then
exit 0
fi
state_dir="$HOME/.local/state/nixos-workstations"
password_marker="$state_dir/password-initialized"
yubikey_marker="$state_dir/yubikey-pin-initialized"
runtime_dir="''${XDG_RUNTIME_DIR:-/tmp}"
active_file="$runtime_dir/nixos-workstations-first-login.active"
supervisor_lock="$runtime_dir/nixos-workstations-first-login.lock"
KDIALOG="${pkgs.kdePackages.kdialog}/bin/kdialog"
KONSOLE="${pkgs.kdePackages.konsole}/bin/konsole"
# --------------------------------------------------------
# Empêche deux superviseurs de fonctionner simultanément.
# --------------------------------------------------------
exec 9>"$supervisor_lock"
if ! ${pkgs.util-linux}/bin/flock -n 9; then
exit 0
fi
# --------------------------------------------------------
# Tout est déjà configuré.
# --------------------------------------------------------
if [ -e "$password_marker" ] && [ -e "$yubikey_marker" ]; then
exit 0
fi
# Laisse Plasma finir son démarrage.
${pkgs.coreutils}/bin/sleep 4
# ========================================================
# Boucle de provisioning
# ========================================================
while \
[ ! -e "$password_marker" ] || \
[ ! -e "$yubikey_marker" ]
do
# ------------------------------------------------------
# Présentation KDE
# ------------------------------------------------------
"$KDIALOG" \
--title "Finalisation de votre poste" \
--warningcontinuecancel \
"Bienvenue Alice.
Votre poste est presque prêt.
Pour terminer sa configuration, vous devez personnaliser vos deux moyens d'authentification :
🔑 Votre mot de passe local de secours
🔐 Le PIN de votre YubiKey
Les nouveaux secrets que vous choisirez sont personnels.
Ils ne sont ni enregistrés dans Git, ni communiqués au service informatique.
Cette opération ne doit être effectuée qu'une seule fois."
dialog_result=$?
# ------------------------------------------------------
# Alice ferme la fenêtre d'accueil.
#
# On ne touche PAS à KDE.
# L'assistant sera simplement reproposé.
# ------------------------------------------------------
if [ "$dialog_result" -ne 0 ]; then
"$KDIALOG" \
--title "Configuration requise" \
--sorry \
"La configuration initiale de votre compte n'est pas terminée.
Cette étape est obligatoire.
L'assistant va être reproposé."
${pkgs.coreutils}/bin/sleep 1
continue
fi
# ------------------------------------------------------
# Supprime un éventuel fichier actif devenu obsolète.
# ------------------------------------------------------
if [ -s "$active_file" ]; then
assistant_pid="$(
${pkgs.coreutils}/bin/cat "$active_file" 2>/dev/null || true
)"
if [ -n "$assistant_pid" ]; then
if ! ${pkgs.coreutils}/bin/kill -0 "$assistant_pid" 2>/dev/null; then
${pkgs.coreutils}/bin/rm -f "$active_file"
fi
else
${pkgs.coreutils}/bin/rm -f "$active_file"
fi
fi
# ------------------------------------------------------
# Lance l'assistant.
# ------------------------------------------------------
"$KONSOLE" \
--separate \
--fullscreen \
--hide-menubar \
--hide-tabbar \
-e ${firstLoginSetup} \
>/dev/null 2>&1 &
# Laisse au script le temps d'écrire active_file.
${pkgs.coreutils}/bin/sleep 2
# ======================================================
# Attend la fin réelle de l'assistant
# ======================================================
while true; do
# Les deux opérations sont terminées.
if [ -e "$password_marker" ] && [ -e "$yubikey_marker" ]; then
break
fi
# Le script n'est plus déclaré actif.
if [ ! -s "$active_file" ]; then
break
fi
assistant_pid="$(
${pkgs.coreutils}/bin/cat "$active_file" 2>/dev/null || true
)"
if [ -z "$assistant_pid" ]; then
break
fi
# Le script a disparu.
if ! ${pkgs.coreutils}/bin/kill -0 "$assistant_pid" 2>/dev/null; then
${pkgs.coreutils}/bin/rm -f "$active_file"
break
fi
${pkgs.coreutils}/bin/sleep 1
done
# ======================================================
# Tout est terminé
# ======================================================
if [ -e "$password_marker" ] && [ -e "$yubikey_marker" ]; then
"$KDIALOG" \
--title "Poste configuré" \
--msgbox \
" Votre poste est prêt.
Votre mot de passe personnel et le PIN de votre YubiKey ont été configurés.
Pour vos prochaines connexions, utilisez :
YubiKey + votre PIN personnel
Votre mot de passe local reste disponible comme solution de secours."
exit 0
fi
# ======================================================
# Configuration partielle / fenêtre fermée / erreur
# ======================================================
"$KDIALOG" \
--title "Configuration incomplète" \
--sorry \
"La configuration initiale n'est pas entièrement terminée.
Les étapes déjà réalisées sont conservées.
L'assistant va reprendre uniquement les étapes restantes."
${pkgs.coreutils}/bin/sleep 1
done
exit 0
'';
in
{ {
# ============================================================ # Les mots de passe peuvent être modifiés localement.
# Lancement automatique lors de l'ouverture de session KDE # Un nixos-rebuild ne réécrase pas le mot de passe choisi par l'utilisateur.
# ============================================================ users.mutableUsers = true;
environment.etc."xdg/autostart/yubikey-first-login.desktop".text = '' # Compte d'administration local
[Desktop Entry] users.users.localadm = {
Type=Application isNormalUser = true;
Name=Finalisation du poste description = "Administrateur local";
Comment=Configuration initiale du compte utilisateur extraGroups = [
Exec=${firstLoginSupervisor} "networkmanager"
OnlyShowIn=KDE; "wheel"
NoDisplay=true ];
StartupNotify=false
''; packages = with pkgs; [
kdePackages.kate
];
};
# Utilisateur standard
users.users.alice = {
isNormalUser = true;
description = "Alice";
# Alice n'est pas administratrice.
extraGroups = [ ];
# Utilisé uniquement lors de la création initiale du compte.
# Demo pass : LaboTest@1980
initialHashedPassword = "$y$j9T$XiIgBUxXjqAYbQQs3eBtr.$dT01AYyRiBtjoaF1MIG83cx2h0bRxEILE6tpilE2V9D";
};
} }