Loading nixos/modules/security/pam.nix +30 −0 Original line number Diff line number Diff line Loading @@ -544,6 +544,7 @@ let # We use try_first_pass the second time to avoid prompting password twice (optionalString (cfg.unixAuth && (config.security.pam.enableEcryptfs || config.security.pam.enableFscrypt || cfg.pamMount || cfg.enableKwallet || cfg.enableGnomeKeyring Loading @@ -558,6 +559,9 @@ let optionalString config.security.pam.enableEcryptfs '' auth optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap '' + optionalString config.security.pam.enableFscrypt '' auth optional ${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so '' + optionalString cfg.pamMount '' auth optional ${pkgs.pam_mount}/lib/security/pam_mount.so disable_interactive '' + Loading Loading @@ -606,6 +610,9 @@ let optionalString config.security.pam.enableEcryptfs '' password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so '' + optionalString config.security.pam.enableFscrypt '' password optional ${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so '' + optionalString cfg.pamMount '' password optional ${pkgs.pam_mount}/lib/security/pam_mount.so '' + Loading Loading @@ -652,6 +659,14 @@ let optionalString config.security.pam.enableEcryptfs '' session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so '' + optionalString config.security.pam.enableFscrypt '' # Work around https://github.com/systemd/systemd/issues/8598 # Skips the pam_fscrypt module for systemd-user sessions which do not have a password # anyways. # See also https://github.com/google/fscrypt/issues/95 session [success=1 default=ignore] pam_succeed_if.so service = systemd-user session optional ${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so '' + optionalString cfg.pamMount '' session optional ${pkgs.pam_mount}/lib/security/pam_mount.so disable_interactive '' + Loading Loading @@ -1168,6 +1183,14 @@ in }; security.pam.enableEcryptfs = mkEnableOption (lib.mdDoc "eCryptfs PAM module (mounting ecryptfs home directory on login)"); security.pam.enableFscrypt = mkEnableOption (lib.mdDoc '' Enables fscrypt to automatically unlock directories with the user's login password. This also enables a service at security.pam.services.fscrypt which is used by fscrypt to verify the user's password when setting up a new protector. If you use something other than pam_unix to verify user passwords, please remember to adjust this PAM service. ''); users.motd = mkOption { default = null; Loading @@ -1192,6 +1215,7 @@ in ++ optionals config.security.pam.enableOTPW [ pkgs.otpw ] ++ optionals config.security.pam.oath.enable [ pkgs.oath-toolkit ] ++ optionals config.security.pam.p11.enable [ pkgs.pam_p11 ] ++ optionals config.security.pam.enableFscrypt [ pkgs.fscrypt-experimental ] ++ optionals config.security.pam.u2f.enable [ pkgs.pam_u2f ]; boot.supportedFilesystems = optionals config.security.pam.enableEcryptfs [ "ecryptfs" ]; Loading Loading @@ -1233,6 +1257,9 @@ in it complains "Cannot create session: Already running in a session". */ runuser-l = { rootOK = true; unixAuth = false; }; } // optionalAttrs (config.security.pam.enableFscrypt) { # Allow fscrypt to verify login passphrase fscrypt = {}; }; security.apparmor.includes."abstractions/pam" = let Loading Loading @@ -1297,6 +1324,9 @@ in optionalString config.security.pam.enableEcryptfs '' mr ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so, '' + optionalString config.security.pam.enableFscrypt '' mr ${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so, '' + optionalString (isEnabled (cfg: cfg.pamMount)) '' mr ${pkgs.pam_mount}/lib/security/pam_mount.so, '' + Loading nixos/tests/all-tests.nix +1 −0 Original line number Diff line number Diff line Loading @@ -179,6 +179,7 @@ in { ec2-config = (handleTestOn ["x86_64-linux"] ./ec2.nix {}).boot-ec2-config or {}; ec2-nixops = (handleTestOn ["x86_64-linux"] ./ec2.nix {}).boot-ec2-nixops or {}; ecryptfs = handleTest ./ecryptfs.nix {}; fscrypt = handleTest ./fscrypt.nix {}; ejabberd = handleTest ./xmpp/ejabberd.nix {}; elk = handleTestOn ["x86_64-linux"] ./elk.nix {}; emacs-daemon = handleTest ./emacs-daemon.nix {}; Loading nixos/tests/fscrypt.nix 0 → 100644 +50 −0 Original line number Diff line number Diff line import ./make-test-python.nix ({ ... }: { name = "fscrypt"; nodes.machine = { pkgs, ... }: { imports = [ ./common/user-account.nix ]; security.pam.enableFscrypt = true; }; testScript = '' def login_as_alice(): machine.wait_until_tty_matches("1", "login: ") machine.send_chars("alice\n") machine.wait_until_tty_matches("1", "Password: ") machine.send_chars("foobar\n") machine.wait_until_tty_matches("1", "alice\@machine") def logout(): machine.send_chars("logout\n") machine.wait_until_tty_matches("1", "login: ") machine.wait_for_unit("default.target") with subtest("Enable fscrypt on filesystem"): machine.succeed("tune2fs -O encrypt /dev/vda") machine.succeed("fscrypt setup --quiet --force --time=1ms") with subtest("Set up alice with an fscrypt-enabled home directory"): machine.succeed("(echo foobar; echo foobar) | passwd alice") machine.succeed("chown -R alice.users ~alice") machine.succeed("echo foobar | fscrypt encrypt --skip-unlock --source=pam_passphrase --user=alice /home/alice") with subtest("Create file as alice"): login_as_alice() machine.succeed("echo hello > /home/alice/world") logout() # Wait for logout to be processed machine.sleep(1) with subtest("File should not be readable without being logged in as alice"): machine.fail("cat /home/alice/world") with subtest("File should be readable again as alice"): login_as_alice() machine.succeed("cat /home/alice/world") logout() ''; }) Loading
nixos/modules/security/pam.nix +30 −0 Original line number Diff line number Diff line Loading @@ -544,6 +544,7 @@ let # We use try_first_pass the second time to avoid prompting password twice (optionalString (cfg.unixAuth && (config.security.pam.enableEcryptfs || config.security.pam.enableFscrypt || cfg.pamMount || cfg.enableKwallet || cfg.enableGnomeKeyring Loading @@ -558,6 +559,9 @@ let optionalString config.security.pam.enableEcryptfs '' auth optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap '' + optionalString config.security.pam.enableFscrypt '' auth optional ${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so '' + optionalString cfg.pamMount '' auth optional ${pkgs.pam_mount}/lib/security/pam_mount.so disable_interactive '' + Loading Loading @@ -606,6 +610,9 @@ let optionalString config.security.pam.enableEcryptfs '' password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so '' + optionalString config.security.pam.enableFscrypt '' password optional ${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so '' + optionalString cfg.pamMount '' password optional ${pkgs.pam_mount}/lib/security/pam_mount.so '' + Loading Loading @@ -652,6 +659,14 @@ let optionalString config.security.pam.enableEcryptfs '' session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so '' + optionalString config.security.pam.enableFscrypt '' # Work around https://github.com/systemd/systemd/issues/8598 # Skips the pam_fscrypt module for systemd-user sessions which do not have a password # anyways. # See also https://github.com/google/fscrypt/issues/95 session [success=1 default=ignore] pam_succeed_if.so service = systemd-user session optional ${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so '' + optionalString cfg.pamMount '' session optional ${pkgs.pam_mount}/lib/security/pam_mount.so disable_interactive '' + Loading Loading @@ -1168,6 +1183,14 @@ in }; security.pam.enableEcryptfs = mkEnableOption (lib.mdDoc "eCryptfs PAM module (mounting ecryptfs home directory on login)"); security.pam.enableFscrypt = mkEnableOption (lib.mdDoc '' Enables fscrypt to automatically unlock directories with the user's login password. This also enables a service at security.pam.services.fscrypt which is used by fscrypt to verify the user's password when setting up a new protector. If you use something other than pam_unix to verify user passwords, please remember to adjust this PAM service. ''); users.motd = mkOption { default = null; Loading @@ -1192,6 +1215,7 @@ in ++ optionals config.security.pam.enableOTPW [ pkgs.otpw ] ++ optionals config.security.pam.oath.enable [ pkgs.oath-toolkit ] ++ optionals config.security.pam.p11.enable [ pkgs.pam_p11 ] ++ optionals config.security.pam.enableFscrypt [ pkgs.fscrypt-experimental ] ++ optionals config.security.pam.u2f.enable [ pkgs.pam_u2f ]; boot.supportedFilesystems = optionals config.security.pam.enableEcryptfs [ "ecryptfs" ]; Loading Loading @@ -1233,6 +1257,9 @@ in it complains "Cannot create session: Already running in a session". */ runuser-l = { rootOK = true; unixAuth = false; }; } // optionalAttrs (config.security.pam.enableFscrypt) { # Allow fscrypt to verify login passphrase fscrypt = {}; }; security.apparmor.includes."abstractions/pam" = let Loading Loading @@ -1297,6 +1324,9 @@ in optionalString config.security.pam.enableEcryptfs '' mr ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so, '' + optionalString config.security.pam.enableFscrypt '' mr ${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so, '' + optionalString (isEnabled (cfg: cfg.pamMount)) '' mr ${pkgs.pam_mount}/lib/security/pam_mount.so, '' + Loading
nixos/tests/all-tests.nix +1 −0 Original line number Diff line number Diff line Loading @@ -179,6 +179,7 @@ in { ec2-config = (handleTestOn ["x86_64-linux"] ./ec2.nix {}).boot-ec2-config or {}; ec2-nixops = (handleTestOn ["x86_64-linux"] ./ec2.nix {}).boot-ec2-nixops or {}; ecryptfs = handleTest ./ecryptfs.nix {}; fscrypt = handleTest ./fscrypt.nix {}; ejabberd = handleTest ./xmpp/ejabberd.nix {}; elk = handleTestOn ["x86_64-linux"] ./elk.nix {}; emacs-daemon = handleTest ./emacs-daemon.nix {}; Loading
nixos/tests/fscrypt.nix 0 → 100644 +50 −0 Original line number Diff line number Diff line import ./make-test-python.nix ({ ... }: { name = "fscrypt"; nodes.machine = { pkgs, ... }: { imports = [ ./common/user-account.nix ]; security.pam.enableFscrypt = true; }; testScript = '' def login_as_alice(): machine.wait_until_tty_matches("1", "login: ") machine.send_chars("alice\n") machine.wait_until_tty_matches("1", "Password: ") machine.send_chars("foobar\n") machine.wait_until_tty_matches("1", "alice\@machine") def logout(): machine.send_chars("logout\n") machine.wait_until_tty_matches("1", "login: ") machine.wait_for_unit("default.target") with subtest("Enable fscrypt on filesystem"): machine.succeed("tune2fs -O encrypt /dev/vda") machine.succeed("fscrypt setup --quiet --force --time=1ms") with subtest("Set up alice with an fscrypt-enabled home directory"): machine.succeed("(echo foobar; echo foobar) | passwd alice") machine.succeed("chown -R alice.users ~alice") machine.succeed("echo foobar | fscrypt encrypt --skip-unlock --source=pam_passphrase --user=alice /home/alice") with subtest("Create file as alice"): login_as_alice() machine.succeed("echo hello > /home/alice/world") logout() # Wait for logout to be processed machine.sleep(1) with subtest("File should not be readable without being logged in as alice"): machine.fail("cat /home/alice/world") with subtest("File should be readable again as alice"): login_as_alice() machine.succeed("cat /home/alice/world") logout() ''; })