The NixOS security.pam module provides config options for Linux PAM (Pluggable Authentication Modules). PAM is how the authentication stack is configured for login and also programs like sudo, passwd, su, etc. With PAM, you can configure 2FA, LDAP/AD, encrypted home directories, automatic keychain unlock, and more.
The PAM infrastructure in NixOS needs some love. I have done some refactoring and I’m thinking about spinning up an RFC for a bigger design evolution. First, I want to hear from you:
What do YOU want the NixOS PAM module to do for you?
Below is my first stab, broken out by user category. Please comment with any corrections or additions!
NixOS Users
Defaults are secure. “I don’t have to think about PAM.”
Enabling a feature (e.g. U2F, LDAP) is as easy as configuring a NixOS service.
Different PAM features “just work” together by default.
NixOS/PAM Power Users
PAM stack can be fine-tuned through NixOS config. (Reorder rules, change arguments, etc.)
Never need to manually write PAM config files.
New PAMs can be added through NixOS config.
Customizing parts of the PAM stack doesn’t require maintaining the whole stack yourself.
NixOS Maintainers
PAM options are defined entirely in their own files (NixOS modules).
Clear guidance exists for how new PAMs should fit into the stack of PAM rules.
Desktop environments and other software don’t need to duplicate the PAM stack.
Insecure or unsuitable defaults are fixed without breaking existing users.
Following a PR that probably looks like what you attempted (sorry I didn’t look at your PR in details): (I realise now that you refer to it in your PR)
Now that I have, I can see that we are thinking similarly about many things! A lot of the changes you made are on my todo list if not already implemented.
So far, I’ve focused on lifting PAM rules into the module system, offering a low-level abstraction for defining rules first. My thinking is that if a user has to use the text escape hatch, then they have to throw away all the benefits of the module system. (Imagine a user using five different security.pam settings happily, only to have to write all their PAM rules manually because one need isn’t met by the modules as defined.) Hence the desire to “never need to manually write PAM config files.”
We also want (and to some extent already have) higher-level abstractions for enabling “features” or “modules” that create many rules. These options can be more opinionated and offer useful defaults, like 2FA modules coming after password login. My hope is that I can defer these higher-level design changes until after reworking the rule generation internals.
It looks like your PR addressed both these needs, and our PRs have fairly minor differences in interface design. One area I’ve neglected that I discovered in testing yesterday is defaults, since it isn’t (AFAIK) possible for a user to extend every value in a config attrset.
Unfortunately their wasn’t much traction to make this happen when I worked on it, but hopefully you’ll have more luck!
My burning question for you is: Where did your PR get stuck? How can I make sure I don’t get similarly stuck? It looks like you did great work and documented it well.
Where did your PR get stuck? How can I make sure I don’t get similarly stuck? It looks like you did great work and documented it well.
I think it’s simply due to its size, and perhaps the lack of “advertising” around it. I think if you manage to make as many small, non-breaking changes as possible (at least to the exposed modules under security.pam like security.pam.yubico.enable) before changing that, you’ll be able to rework the backend and have a proper foundation for moving forward. And with that, try to get as many eyes as you can on the PRs to get traction from core maintainers to make this happen.
I’d also be careful of the timing, no one wants to merge potentially breaking changes before a stable release.
I don’t know if going through the RFC process would be appropriate for those changes, but if you decide to, I’d love to co-author it.
Thanks for your thoughts! I made some changes to #255547 to hopefully make things smoother:
Cleaned up some inconsistencies in how rules are defined up front. That made the rest of the commits more automated and consistent.
Set the new options visible = false and marked them experimental. The idea is to retain the flexibility to rework these options and minimize the impact of getting the design wrong the first time around.
I don’t know yet if an RFC makes sense, but I’d be happy to work with you on one if so. I’ll definitely want to bounce some ideas off you when I get to the user-facing option design regardless.
As for getting more eyes on this work, I’ll start now: this refactor PR is ready for review! If you believe these PAM changes are important, please take a look through the commits and leave a review. The changes are easy on the eyes, I promise.
i feel like more wiki documentation would be nice - right now there is some about u2f/otp on the Yubikey page, while i’m not finding instructions for fido2 (in my case thru a device from Nitrokey).
i don’t super mind whether docs go to the wiki or the official manual, but either way some more clarity on how to use this would be nice.
tests are cool too but i’m not sure they’d be as accessible for newer users as a substitute for documentation.
I was trying to figure out a way to get the nextcloud client to work with autologin on SDDM and an empty kwallet password and couldn’t make it work. I found some instructions on how to edit pam.d files to facilitate this but couldn’t try them out because I don’t know how to change pam.d files in NixOS. So that would be my use case.
Something I’ve been doing lately is trying to make kwallet5 unlock automatically with the encryption password. I succeeded, but as far as I can tell, for stuff like autologin where the actual authentication piece is different, but you want to reuse the “stuff that uses PAM_AUTH_TOK” portion of the main config, that’s seems to not be currently possible without, possibly, setting security.pam.rules.sddm-autologin.enableKwallet and similar at every usage site?
I was at NixCon 2024 and saw many people using YubiKeys, which sparked my interest. I do have one myself, but I have never used it beyond setting 2FA on some websites.
It was cool to see that one can use it to execute the sudo command without a password or even log into a gnome-session.
But setting things up is kind of a PITA… To have a normal functioning fingerprint scanner on my framework, I had to be lucky to stumble upon this comment on a GitHub issue, which is just stupid in a way. I tried replicating it using pure Nix, but I was not quite sure what I was doing since I have basically no knowledge about pam.
Now I wanted to setup the yubikey pam modules too, and there were some conflicts I had to resolve and it seems to work… somehow
But I still face the issue, when the yubikey is plugged in while gdm is starting, I can only use my fingerprint or yubikey, but not my password. Sure enough, why would I bother to type in my password, I can just use two other, more convenient, methods. But with those two, the gnome keyring does not start, and at some point I need to insert my password.
Long story short: for an ordinary user, it is annoying to configure certain things, and it would be cool to have some nice defaults that work together, or examples on how to make them work together nicely.