Files
nixos-workstations/modules/yubikey-first-login.nix
T

406 lines
10 KiB
Nix

{ pkgs, ... }:
let
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"
printf '%s\n' "$$" > "$active_file"
cleanup() {
rm -f "$active_file"
}
trap cleanup EXIT HUP INT TERM
# ==========================================================
# Couleurs
# ==========================================================
RESET="\033[0m"
BOLD="\033[1m"
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"
line() {
printf "''${GREY}────────────────────────────────────────────────────────────''${RESET}\n"
}
clear
echo
echo
printf " ''${BOLD}''${CYAN}CONFIGURATION DE VOTRE COMPTE''${RESET}\n"
echo
line
echo
printf " Bienvenue ''${BOLD}Alice''${RESET}.\n"
echo
printf " Cette procédure termine la préparation de votre poste.\n"
printf " Elle ne sera effectuée qu'une seule fois.\n"
echo
line
echo
# ==========================================================
# ÉTAPE 1 : MOT DE PASSE LOCAL
# ==========================================================
if [ ! -e "$password_marker" ]; then
printf " ''${BOLD}''${CYAN}ÉTAPE 1 / 2''${RESET}\n"
echo
printf " ''${BOLD}Choisissez votre mot de passe de secours''${RESET}\n"
echo
printf " Ce mot de passe permet notamment d'accéder au poste\n"
printf " si votre YubiKey est indisponible.\n"
echo
printf " ''${YELLOW}Vous allez saisir :''${RESET}\n"
echo
printf " ① votre mot de passe temporaire actuel\n"
printf " ② votre nouveau mot de passe personnel\n"
printf " ③ une confirmation du nouveau mot de passe\n"
echo
line
echo
if ${pkgs.shadow}/bin/passwd; then
${pkgs.coreutils}/bin/mkdir -p "$state_dir"
${pkgs.coreutils}/bin/touch "$password_marker"
echo
printf " ''${GREEN}✓ Mot de passe modifié avec succès.''${RESET}\n"
echo
${pkgs.coreutils}/bin/sleep 2
else
echo
printf " ''${RED}✗ Le changement du mot de passe a échoué.''${RESET}\n"
echo
printf " La procédure sera automatiquement reproposée.\n"
${pkgs.coreutils}/bin/sleep 3
exit 1
fi
fi
# ==========================================================
# ÉTAPE 2 : PIN YUBIKEY
# ==========================================================
clear
echo
echo
printf " ''${BOLD}''${CYAN}CONFIGURATION DE VOTRE COMPTE''${RESET}\n"
echo
line
echo
printf " ''${BOLD}''${CYAN}ÉTAPE 2 / 2''${RESET}\n"
echo
printf " ''${BOLD}Personnalisez le PIN de votre YubiKey''${RESET}\n"
echo
printf " Votre clé utilise actuellement le PIN temporaire fourni\n"
printf " lors de la préparation du poste.\n"
echo
printf " ''${YELLOW}Vous allez saisir :''${RESET}\n"
echo
printf " ① votre PIN temporaire actuel\n"
printf " ② votre nouveau PIN personnel\n"
printf " ③ une confirmation du nouveau PIN\n"
echo
printf " ''${GREY}Le nouveau PIN reste enregistré uniquement dans la YubiKey.''${RESET}\n"
echo
printf " ''${YELLOW}⚠ Vérifiez Verr Num si vous utilisez le pavé numérique.''${RESET}\n"
printf " En cas de doute, utilisez les chiffres situés au-dessus du clavier.\n"
echo
line
echo
if [ ! -e "$yubikey_marker" ]; then
if ${pkgs.yubikey-manager}/bin/ykman fido access change-pin; then
${pkgs.coreutils}/bin/mkdir -p "$state_dir"
${pkgs.coreutils}/bin/touch "$yubikey_marker"
echo
printf " ''${GREEN}✓ PIN YubiKey modifié avec succès.''${RESET}\n"
${pkgs.coreutils}/bin/sleep 2
else
echo
printf " ''${RED}✗ Le changement du PIN n'a pas été terminé.''${RESET}\n"
echo
printf " Votre mot de passe déjà modifié sera conservé.\n"
printf " Seule cette étape sera reproposée.\n"
${pkgs.coreutils}/bin/sleep 3
exit 1
fi
fi
# ==========================================================
# TERMINÉ
# ==========================================================
clear
echo
echo
line
echo
printf " ''${BOLD}''${GREEN}✓ CONFIGURATION TERMINÉE''${RESET}\n"
echo
line
echo
printf " Votre compte est maintenant prêt.\n"
echo
printf " ''${GREEN}✓''${RESET} Mot de passe personnel configuré\n"
printf " ''${GREEN}✓''${RESET} PIN personnel YubiKey configuré\n"
echo
echo
printf " Pour vos prochaines connexions :\n"
echo
printf " ''${BOLD}YubiKey + votre PIN personnel''${RESET}\n"
echo
printf " Votre mot de passe local reste disponible comme solution\n"
printf " de secours.\n"
echo
line
echo
printf " Fermeture automatique"
for i in 1 2 3 4 5; do
printf "."
${pkgs.coreutils}/bin/sleep 1
done
echo
exit 0
'';
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"
# Une seule instance du superviseur.
exec 9>"$supervisor_lock"
if ! ${pkgs.util-linux}/bin/flock -n 9; then
exit 0
fi
# Les deux opérations sont déjà terminées.
if [ -e "$password_marker" ] && [ -e "$yubikey_marker" ]; then
exit 0
fi
# Laisse Plasma terminer son démarrage.
${pkgs.coreutils}/bin/sleep 3
# ========================================================
# Présentation
# ========================================================
while \
[ ! -e "$password_marker" ] || \
[ ! -e "$yubikey_marker" ]
do
"$KDIALOG" \
--title "Finalisation de votre poste" \
--warningcontinuecancel \
"Bienvenue Alice.
Votre poste est presque prêt.
Pour terminer sa configuration, vous devez personnaliser deux éléments de sécurité :
🔑 Votre mot de passe local de secours
🔐 Le PIN de votre YubiKey
Ces informations deviennent personnelles.
Elles ne sont pas enregistrées dans Git et ne sont pas transmises au service informatique.
La procédure prend seulement quelques instants."
result=$?
if [ "$result" -ne 0 ]; then
"$KDIALOG" \
--title "Configuration requise" \
--sorry \
"La configuration initiale de votre compte n'est pas terminée.
L'assistant va être reproposé."
${pkgs.coreutils}/bin/sleep 1
continue
fi
# ------------------------------------------------------
# Lance l'assistant interactif
# ------------------------------------------------------
"$KONSOLE" \
--separate \
--fullscreen \
--hide-menubar \
--hide-tabbar \
-e ${firstLoginSetup} \
>/dev/null 2>&1 &
${pkgs.coreutils}/bin/sleep 1
# ------------------------------------------------------
# Attend la fin réelle du script.
# ------------------------------------------------------
while true; do
if [ \
-e "$password_marker" \
] && [ \
-e "$yubikey_marker" \
]; then
break
fi
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
if ! ${pkgs.coreutils}/bin/kill -0 "$assistant_pid" 2>/dev/null; then
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 votre YubiKey et votre nouveau PIN.
Votre mot de passe local reste disponible comme solution de secours."
exit 0
fi
"$KDIALOG" \
--title "Configuration incomplète" \
--sorry \
"La configuration n'a pas été 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
{
environment.etc."xdg/autostart/yubikey-first-login.desktop".text = ''
[Desktop Entry]
Type=Application
Name=Finalisation du poste
Comment=Configuration initiale du compte utilisateur
Exec=${firstLoginSupervisor}
OnlyShowIn=KDE;
NoDisplay=true
StartupNotify=false
'';
}