NixOS / nixpkgs

Nix Packages collection & NixOS
MIT License
18.07k stars 14.06k forks source link

User management: passwordFile does not work as advertised on current stable NixOS #148044

Open kciredor opened 2 years ago

kciredor commented 2 years ago

Describe the bug

Using users.users..passwordFile = "path/to/textfile/containing/hashed/password"; does not work as advertised, I'm unable to login.

Using a workaround with hashedPassword sourced from the same file does work and results in a system I can login to.

Steps To Reproduce

Bootstrapping a new system with NixOS and having a configuration.nix containing:

users = {
  mutableUsers = false;

  users.kciredor = {
    isNormalUser = true;
    passwordFile = "/path/to/password.txt";
  };
};

Followed by running nixos-install, results in a system I cannot log in to.

Working around the issue by replacing passwordFile with hashedPassword like this does work:

users = {
  mutableUsers = false;

  users.kciredor = {
    isNormalUser = true;
    hashedPassword = lib.strings.fileContents path/to/password.txt;
  };
};

Please note that both approaches use the exact same password input file.

Looking into https://github.com/NixOS/nixpkgs/blob/nixos-21.05/nixos/modules/config/users-groups.nix#L247 I'm confident that passwordFile should contain a hash and not a plaintext password.

I've created the hashed password using mkpasswd -m sha-512 | tr -d '\n' > password.txt (which also strips the trailing linebreak unfortunately produced by mkpasswd, as can be verified by a hex dump).

Notify maintainers

Could not find any maintainers listed so I'm tagging the most recent committers to users-groups.nix: @alyssais @symphorien, @dnr, @ncfavier, @infinisil

Metadata

$ nix-shell -p nix-info --run "nix-info -m"
these paths will be fetched (0.05 MiB download, 0.28 MiB unpacked):
  /nix/store/1bpw671p7r93sp3sbdxq9ly6h4npx5ff-bash-interactive-4.4-p23-dev
copying path '/nix/store/1bpw671p7r93sp3sbdxq9ly6h4npx5ff-bash-interactive-4.4-p23-dev' from 'https://cache.nixos.org'...
 - system: `"x86_64-linux"`
 - host os: `Linux 5.10.81, NixOS, 21.05.4394.2553aee74fe (Okapi)`
 - multi-user?: `yes`
 - sandbox: `yes`
 - version: `nix-env (Nix) 2.3.16`
 - channels(root): `"home-manager-21.05, nixos-21.05.4394.2553aee74fe, nixos-unstable-22.05pre334685.8a308775674"`
 - nixpkgs: `/nix/var/nix/profiles/per-user/root/channels/nixos`
ncfavier commented 2 years ago

Have you tried without | tr -d '\n'? That shouldn't be needed.

Can you compare the contents of /etc/passwd and /etc/shadow in both cases?

kciredor commented 2 years ago

Yes @ncfavier my first attempts were without the removal of newline. But because it was not working, and a hint on IRC, I took a better look at the produced hash via a hex dump, and I figured: "ah that must be it, there's a newline character added to the hash". But that was not the problem, I left it there though because for the workaround with hashedPassword it still makes sense.

To be honest /etc/shadow has a hash of '!' for my user after nixos-install. The docs state that it will be updated on system activation, which in my mind is after a boot into the new system.

So currently I'm thinking: what if nixos-install is not the same thing as nixos-rebuild? Could it be nixos-install which does not play nicely with passwordFile?

kciredor commented 2 years ago

As soon as I run nixos-switch rebuild from a running system, replacing hashedPassword with passwordFile, my /etc/shadow file user hash is removed and replaced by '!' again. So nixos-install and nixos-rebuild act the same way: '!' instead of the hash.

kciredor commented 2 years ago

Think I've got it now. As the documentation states, passwordFile must contain the full path to the file containing the password hash.

When bootstrapping a new system, everything is mounted into /mnt so I have to deal with the /mnt prefix. Using full path it means something like /mnt/path/to/password.txt.

When rebuilding a running system there is no /mnt prefix so the path would suddenly have to become /path/to/password.txt.

For that reason I've been using a relative path in configuration.nix which works fine with other stuff like importing files, lib.strings.fileContents and so on. But not with passwordFile.

I'll stick with my workaround for this reason, sourcing the hashedPassword with lib.strings.fileContents allows a relative path input and works with bootstrapping a new system and rebuilding a running system.

Would be a nice improvement if passwordFile could both accept a full path and relative path I think!

OPNA2608 commented 2 years ago

When bootstrapping a new system, everything is mounted into /mnt so I have to deal with the /mnt prefix. Using full path it means something like /mnt/path/to/password.txt.

Have you tried it without the /mnt prefix? I also use passwordFile and bootstrapping new systems works fine for me without that.

kciredor commented 2 years ago

Yes thanks @OPNA2608, passwordFile = "/etc/nixos/secrets/password-user.txt" does not work during install for me. It results in the '!' "hash" in /etc/shadow.

I have symlinked /mnt/etc/nixos to /mnt/home/user/something/nixos during install (after install I update the target of the symlink omitting /mnt prefix). Using the actual target file to ensure symlinks are not to blame does not work either: "/mnt/home/user/something/nixos/password-user.txt".

But omitting /mnt again using the target file resulting in "/home/user/something/nixos/password-user.txt" works during nixos-install! So... symlinks are interfering during install?

Perhaps passwordFile does not follow symlinks during nixos-install, and does follow them during nixos-rebuild? Or it's trying to remove the /mnt prefix of the symlink target?

I'm likely not the only one who symlinks /etc/nixos to a user directory containing a git repo, combined with using passwordFile.

infinisil commented 2 years ago

Quoting the description of the passwordFile option:

The password file is read on each system activation.

And system activation happens when you nixos-install, nixos-rebuild and when you boot the machine.

PgBiel commented 6 months ago

For future readers, I was facing this problem while configuring an impermanence setup (with https://github.com/nix-community/impermanence), as I was trying to persist the hashed password file but failing, even though the file was being bind mounted (and/or symlinked). Thanks to the information in this thread, I figured out that I had to add fileSystems."/path/to/password/file".neededForBoot = true; so that the bind mount occurred at the right time, such that the password file was properly picked up during boot, and I could then log in.