Téléverser les fichiers vers "modules"

This commit is contained in:
2026-08-19 08:48:40 +02:00
parent 24f75b70b3
commit 20e38cfa33
3 changed files with 101 additions and 70 deletions
+4
View File
@@ -1,6 +1,10 @@
{ ... }: { ... }:
{ {
# Module NixOS officiel : installe YubiKey Manager et les règles udev
# nécessaires pour que ykman puisse accéder à la clé en session utilisateur.
programs.yubikey-manager.enable = true;
# Déploiement du mapping utilisateur <-> YubiKey # Déploiement du mapping utilisateur <-> YubiKey
environment.etc."u2f-mappings".source = ../u2f-mappings; environment.etc."u2f-mappings".source = ../u2f-mappings;
+2 -1
View File
@@ -34,6 +34,7 @@
# Avec users.mutableUsers = true, ce hash sert uniquement lors de la # Avec users.mutableUsers = true, ce hash sert uniquement lors de la
# création initiale du compte. Après changement via passwd, le nouveau # création initiale du compte. Après changement via passwd, le nouveau
# mot de passe local est conservé lors des activations suivantes. # mot de passe local est conservé lors des activations suivantes.
initialHashedPassword = "$y$j9T$mra1r8ta998VNiAAoS89a.$cqQKliEqw4k9WvnDeXA.5BqBGGEKVsr5zQ6fwXRid32"; initialHashedPassword =
"$6$VwAqDD0hXRojZr2T$5EVBlLOVnOvyJxde9uAGj.ehkiQaRis5SwTrSLuVAhiXXvG4DH9DNC.88pWfiL2O28wanR52.23INxuyEtNSQ/";
}; };
} }
+95 -69
View File
@@ -10,76 +10,99 @@ let
#!${pkgs.expect}/bin/expect -f #!${pkgs.expect}/bin/expect -f
# Les secrets arrivent uniquement par stdin depuis l'application. # Les secrets arrivent uniquement par stdin depuis l'application.
# Ils ne sont jamais passés dans argv et aucun transcript n'est affiché. # Ils ne sont jamais placés dans argv et le transcript enfant n'est pas affiché.
log_user 0 log_user 0
exp_internal 0 exp_internal 0
set timeout 30 set timeout 30
proc fail {token code} {
puts stderr $token
exit $code
}
if {[gets stdin current] < 0 || [gets stdin newpass] < 0 || [gets stdin confirm] < 0} { if {[gets stdin current] < 0 || [gets stdin newpass] < 0 || [gets stdin confirm] < 0} {
puts stderr "INPUT_ERROR" fail "INPUT_ERROR" 20
exit 20
} }
if {$newpass ne $confirm} { if {$newpass ne $confirm} {
puts stderr "CONFIRM_MISMATCH" fail "CONFIRM_MISMATCH" 21
exit 21
} }
spawn -noecho ${pkgs.coreutils}/bin/env LC_ALL=C LANG=C /run/wrappers/bin/passwd spawn -noecho ${pkgs.coreutils}/bin/env LC_ALL=C LANG=C /run/wrappers/bin/passwd
# Étape 1 : passwd doit demander le mot de passe actuel.
expect { expect {
-re {(?i)(current.*password|unix password|password.*current).*:} { -re {(?i)(current|old|unix).*password.*:} {
send -- "$current\r" send -- "$current\r"
} }
-re {(?i)new.*password.*:} {
fail "CURRENT_PROMPT_MISSING" 22
}
-re {(?i)(authentication failure|incorrect password|password unchanged)} {
fail "CURRENT_REJECTED" 23
}
eof { eof {
puts stderr "CURRENT_REJECTED" fail "CURRENT_REJECTED" 24
exit 22
} }
timeout { timeout {
puts stderr "TIMEOUT_CURRENT" fail "TIMEOUT_CURRENT" 124
exit 124
} }
} }
# Efface la copie du mot de passe actuel dès qu'elle n'est plus utile.
set current "" set current ""
# Étape 2 : le nouveau mot de passe n'est envoyé qu'après validation
# du mot de passe actuel par passwd/PAM.
expect { expect {
-re {(?i)new.*password.*:} { -re {(?i)new.*password.*:} {
send -- "$newpass\r" send -- "$newpass\r"
} }
# Certains passwd redemandent immédiatement le mot de passe courant
# après une erreur. On s'arrête sans envoyer une seconde tentative.
-re {(?i)(current|old|unix).*password.*:} {
fail "CURRENT_REJECTED" 25
}
-re {(?i)(authentication failure|incorrect password|password unchanged)} {
fail "CURRENT_REJECTED" 25
}
eof { eof {
puts stderr "CURRENT_REJECTED" fail "CURRENT_REJECTED" 26
exit 23
} }
timeout { timeout {
puts stderr "TIMEOUT_NEW" fail "TIMEOUT_NEW" 124
exit 124
} }
} }
# Étape 3 : confirmation. Un nouveau prompt "New password" à ce stade
# signifie que PAM/passwd a refusé la valeur proposée.
expect { expect {
-re {(?i)(retype|repeat|confirm).*password.*:} { -re {(?i)(retype|repeat|confirm).*password.*:} {
send -- "$confirm\r" send -- "$confirm\r"
} }
-re {(?i)new.*password.*:} { -re {(?i)new.*password.*:} {
puts stderr "NEW_REJECTED" fail "NEW_REJECTED" 27
exit 24
} }
eof { eof {
puts stderr "NEW_REJECTED" fail "NEW_REJECTED" 28
exit 25
} }
timeout { timeout {
puts stderr "TIMEOUT_CONFIRM" fail "TIMEOUT_CONFIRM" 124
exit 124
} }
} }
set newpass "" set newpass ""
set confirm "" set confirm ""
expect eof expect {
eof {}
-re {(?i)new.*password.*:} {
fail "NEW_REJECTED" 29
}
timeout {
fail "TIMEOUT_FINISH" 124
}
}
set waitResult [wait] set waitResult [wait]
set exitCode [lindex $waitResult 3] set exitCode [lindex $waitResult 3]
@@ -88,8 +111,7 @@ let
exit 0 exit 0
} }
puts stderr "PASSWD_FAILED" fail "PASSWD_FAILED" $exitCode
exit $exitCode
''; '';
}; };
@@ -99,64 +121,69 @@ let
text = '' text = ''
#!${pkgs.expect}/bin/expect -f #!${pkgs.expect}/bin/expect -f
# Même principe que pour passwd : aucune valeur secrète dans argv. # Une seule invocation de ykman par clic : aucune tentative automatique
# supplémentaire n'est faite en cas de mauvais PIN.
log_user 0 log_user 0
exp_internal 0 exp_internal 0
set timeout 30 set timeout 30
proc fail {token code} {
puts stderr $token
exit $code
}
if {[gets stdin current] < 0 || [gets stdin newpin] < 0 || [gets stdin confirm] < 0} { if {[gets stdin current] < 0 || [gets stdin newpin] < 0 || [gets stdin confirm] < 0} {
puts stderr "INPUT_ERROR" fail "INPUT_ERROR" 30
exit 30
} }
if {$newpin ne $confirm} { if {$newpin ne $confirm} {
puts stderr "CONFIRM_MISMATCH" fail "CONFIRM_MISMATCH" 31
exit 31
} }
spawn -noecho ${pkgs.coreutils}/bin/env LC_ALL=C LANG=C ${pkgs.yubikey-manager}/bin/ykman fido access change-pin spawn -noecho ${pkgs.coreutils}/bin/env LC_ALL=C LANG=C ${pkgs.yubikey-manager}/bin/ykman fido access change-pin
set transcript "" set transcript ""
# Une clé déjà provisionnée doit demander le PIN actuel. Si ykman passe
# directement au nouveau PIN, la clé n'a pas le pré-provisionnement attendu.
expect { expect {
-re {Enter your current PIN.*:} { -re {(?i)enter.*current.*pin.*:} {
append transcript $expect_out(buffer) append transcript $expect_out(buffer)
send -- "$current\r" send -- "$current\r"
} }
-re {No YubiKey|Failed to connect|No FIDO} { -re {(?i)enter.*new.*pin.*:} {
puts stderr "NO_YUBIKEY" append transcript $expect_out(buffer)
exit 32 fail "PIN_NOT_CONFIGURED" 32
}
-re {(?i)(no yubikey|multiple yubikey|failed to connect|no fido|device.*not found|permission denied|access denied)} {
append transcript $expect_out(buffer)
fail "NO_YUBIKEY" 33
} }
eof { eof {
append transcript $expect_out(buffer) append transcript $expect_out(buffer)
if {[regexp -nocase {No YubiKey|Failed to connect|No FIDO} $transcript]} { if {[regexp -nocase {no yubikey|multiple yubikey|failed to connect|no fido|device.*not found|permission denied|access denied} $transcript]} {
puts stderr "NO_YUBIKEY" fail "NO_YUBIKEY" 34
} else {
puts stderr "PIN_FAILED"
} }
exit 33 fail "PIN_FAILED" 35
} }
timeout { timeout {
puts stderr "TIMEOUT_CURRENT_PIN" fail "TIMEOUT_CURRENT_PIN" 124
exit 124
} }
} }
set current "" set current ""
expect { expect {
-re {Enter your new PIN.*:} { -re {(?i)enter.*new.*pin.*:} {
append transcript $expect_out(buffer) append transcript $expect_out(buffer)
send -- "$newpin\r" send -- "$newpin\r"
} }
eof { eof {
append transcript $expect_out(buffer) append transcript $expect_out(buffer)
puts stderr "PIN_FAILED" fail "PIN_FAILED" 36
exit 34
} }
timeout { timeout {
puts stderr "TIMEOUT_NEW_PIN" fail "TIMEOUT_NEW_PIN" 124
exit 124
} }
} }
@@ -167,12 +194,10 @@ let
} }
eof { eof {
append transcript $expect_out(buffer) append transcript $expect_out(buffer)
puts stderr "PIN_FAILED" fail "PIN_FAILED" 37
exit 35
} }
timeout { timeout {
puts stderr "TIMEOUT_CONFIRM_PIN" fail "TIMEOUT_CONFIRM_PIN" 124
exit 124
} }
} }
@@ -189,27 +214,25 @@ let
exit 0 exit 0
} }
if {[regexp -nocase {Wrong PIN|PIN_INVALID} $transcript]} { if {[regexp -nocase {pin[_ ]auth[_ ]blocked|ctaperr_pin_auth_blocked|temporarily blocked} $transcript]} {
puts stderr "WRONG_PIN" fail "PIN_AUTH_BLOCKED" $exitCode
} elseif {[regexp -nocase {authentication is currently blocked|PIN_AUTH_BLOCKED} $transcript]} { } elseif {[regexp -nocase {pin[_ ]blocked|ctaperr_pin_blocked|pin is blocked} $transcript]} {
puts stderr "PIN_AUTH_BLOCKED" fail "PIN_BLOCKED" $exitCode
} elseif {[regexp -nocase {PIN is blocked|PIN_BLOCKED} $transcript]} { } elseif {[regexp -nocase {wrong pin|pin_invalid|pin auth invalid|pin verification failed|ctaperr_pin_invalid} $transcript]} {
puts stderr "PIN_BLOCKED" fail "WRONG_PIN" $exitCode
} elseif {[regexp -nocase {No YubiKey|Failed to connect|No FIDO} $transcript]} { } elseif {[regexp -nocase {no yubikey|multiple yubikey|failed to connect|no fido|device.*not found|permission denied|access denied} $transcript]} {
puts stderr "NO_YUBIKEY" fail "NO_YUBIKEY" $exitCode
} elseif {[regexp -nocase {complexity|policy|at least|at most} $transcript]} { } elseif {[regexp -nocase {complexity|policy|minimum pin length|must be at least|too short} $transcript]} {
puts stderr "PIN_POLICY" fail "PIN_POLICY" $exitCode
} else {
puts stderr "PIN_FAILED"
} }
exit $exitCode fail "PIN_FAILED" $exitCode
''; '';
}; };
workstationSetup = pkgs.stdenv.mkDerivation { workstationSetup = pkgs.stdenv.mkDerivation {
pname = "nixos-workstations-setup"; pname = "nixos-workstations-setup";
version = "1.0.0"; version = "1.1.0";
src = ../workstation-setup; src = ../workstation-setup;
@@ -230,14 +253,17 @@ let
cmakeFlags = [ cmakeFlags = [
"-DPASSWORD_HELPER_PATH=${passwordHelper}" "-DPASSWORD_HELPER_PATH=${passwordHelper}"
"-DPIN_HELPER_PATH=${pinHelper}" "-DPIN_HELPER_PATH=${pinHelper}"
"-DTARGET_USER=${cfg.user}"
]; ];
}; };
launcher = pkgs.writeShellScript "nixos-workstations-setup-launcher" '' launcher = pkgs.writeShellScript "nixos-workstations-setup-launcher" ''
set -eu set -eu
if [ "$(${pkgs.coreutils}/bin/id -un)" != ${lib.escapeShellArg cfg.user} ]; then current_user="$(${pkgs.coreutils}/bin/id -un)"
target_user=${lib.escapeShellArg cfg.user}
# L'autostart ne doit concerner que l'utilisateur configuré.
if [ "$current_user" != "$target_user" ]; then
exit 0 exit 0
fi fi
@@ -245,6 +271,7 @@ let
password_marker="$state_dir/password-initialized" password_marker="$state_dir/password-initialized"
pin_marker="$state_dir/yubikey-pin-initialized" pin_marker="$state_dir/yubikey-pin-initialized"
# Une session déjà finalisée n'affiche plus l'assistant.
if [ -e "$password_marker" ] && [ -e "$pin_marker" ]; then if [ -e "$password_marker" ] && [ -e "$pin_marker" ]; then
exit 0 exit 0
fi fi
@@ -252,11 +279,11 @@ let
# Ne jamais générer de core dump contenant potentiellement un secret. # Ne jamais générer de core dump contenant potentiellement un secret.
ulimit -c 0 ulimit -c 0
# Laisse Plasma finir son démarrage sans créer de logique de supervision # Laisse Plasma terminer son démarrage.
# susceptible de tuer ou manipuler la session utilisateur.
${pkgs.coreutils}/bin/sleep 3 ${pkgs.coreutils}/bin/sleep 3
exec ${workstationSetup}/bin/nixos-workstations-setup exec ${workstationSetup}/bin/nixos-workstations-setup \
--target-user "$target_user"
''; '';
in in
@@ -274,7 +301,6 @@ in
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
environment.systemPackages = [ environment.systemPackages = [
workstationSetup workstationSetup
pkgs.yubikey-manager
]; ];
environment.etc."xdg/autostart/nixos-workstations-setup.desktop".text = '' environment.etc."xdg/autostart/nixos-workstations-setup.desktop".text = ''