1 # This module provides configuration for the PAM (Pluggable
2 # Authentication Modules) system.
4 { config, lib, pkgs, ... }:
11 pamOpts = { config, name, ... }: let cfg = config; in let config = parentConfig; in {
18 description = lib.mdDoc "Name of the PAM service.";
24 description = lib.mdDoc ''
25 Whether users can log in with passwords defined in
33 description = lib.mdDoc ''
34 If set, root doesn't need to authenticate (e.g. for the
35 {command}`useradd` service).
40 default = config.security.pam.p11.enable;
41 defaultText = literalExpression "config.security.pam.p11.enable";
43 description = lib.mdDoc ''
44 If set, keys listed in
45 {file}`~/.ssh/authorized_keys` and
46 {file}`~/.eid/authorized_certificates`
47 can be used to log in with the associated PKCS#11 tokens.
52 default = config.security.pam.u2f.enable;
53 defaultText = literalExpression "config.security.pam.u2f.enable";
55 description = lib.mdDoc ''
56 If set, users listed in
57 {file}`$XDG_CONFIG_HOME/Yubico/u2f_keys` (or
58 {file}`$HOME/.config/Yubico/u2f_keys` if XDG variable is
59 not set) are able to log in with the associated U2F key. Path can be
60 changed using {option}`security.pam.u2f.authFile` option.
67 description = lib.mdDoc ''
68 If set, users with an SSH certificate containing an authorized principal
69 in their SSH agent are able to log in. Specific options are controlled
70 using the {option}`security.pam.ussh` options.
72 Note that the {option}`security.pam.ussh.enable` must also be
73 set for this option to take effect.
77 yubicoAuth = mkOption {
78 default = config.security.pam.yubico.enable;
79 defaultText = literalExpression "config.security.pam.yubico.enable";
81 description = lib.mdDoc ''
82 If set, users listed in
83 {file}`~/.yubico/authorized_yubikeys`
84 are able to log in with the associated Yubikey tokens.
88 googleAuthenticator = {
92 description = lib.mdDoc ''
93 If set, users with enabled Google Authenticator (created
94 {file}`~/.google_authenticator`) will be required
95 to provide Google Authenticator token to log in.
101 default = config.security.pam.usb.enable;
102 defaultText = literalExpression "config.security.pam.usb.enable";
104 description = lib.mdDoc ''
105 If set, users listed in
106 {file}`/etc/pamusb.conf` are able to log in
107 with the associated USB key.
111 otpwAuth = mkOption {
112 default = config.security.pam.enableOTPW;
113 defaultText = literalExpression "config.security.pam.enableOTPW";
115 description = lib.mdDoc ''
116 If set, the OTPW system will be used (if
117 {file}`~/.otpw` exists).
121 googleOsLoginAccountVerification = mkOption {
124 description = lib.mdDoc ''
125 If set, will use the Google OS Login PAM modules
126 (`pam_oslogin_login`,
127 `pam_oslogin_admin`) to verify possible OS Login
128 users and set sudoers configuration accordingly.
129 This only makes sense to enable for the `sshd` PAM
134 googleOsLoginAuthentication = mkOption {
137 description = lib.mdDoc ''
138 If set, will use the `pam_oslogin_login`'s user
139 authentication methods to authenticate users using 2FA.
140 This only makes sense to enable for the `sshd` PAM
145 mysqlAuth = mkOption {
146 default = config.users.mysql.enable;
147 defaultText = literalExpression "config.users.mysql.enable";
149 description = lib.mdDoc ''
150 If set, the `pam_mysql` module will be used to
151 authenticate users against a MySQL/MariaDB database.
155 fprintAuth = mkOption {
156 default = config.services.fprintd.enable;
157 defaultText = literalExpression "config.services.fprintd.enable";
159 description = lib.mdDoc ''
160 If set, fingerprint reader will be used (if exists and
161 your fingerprints are enrolled).
165 oathAuth = mkOption {
166 default = config.security.pam.oath.enable;
167 defaultText = literalExpression "config.security.pam.oath.enable";
169 description = lib.mdDoc ''
170 If set, the OATH Toolkit will be used.
174 sshAgentAuth = mkOption {
177 description = lib.mdDoc ''
178 If set, the calling user's SSH agent is used to authenticate
179 against the keys in the calling user's
180 {file}`~/.ssh/authorized_keys`. This is useful
181 for {command}`sudo` on password-less remote systems.
189 description = lib.mdDoc ''
190 If set, use the Duo Security pam module
191 `pam_duo` for authentication. Requires
192 configuration of {option}`security.duosec` options.
197 startSession = mkOption {
200 description = lib.mdDoc ''
201 If set, the service will register a new session with
202 systemd's login manager. For local sessions, this will give
203 the user access to audio devices, CD-ROM drives. In the
204 default PolicyKit configuration, it also allows the user to
209 setEnvironment = mkOption {
212 description = lib.mdDoc ''
213 Whether the service should set the environment variables
214 listed in {option}`environment.sessionVariables`
219 setLoginUid = mkOption {
221 description = lib.mdDoc ''
222 Set the login uid of the process
223 ({file}`/proc/self/loginuid`) for auditing
224 purposes. The login uid is only set by ‘entry points’ like
225 {command}`login` and {command}`sshd`, not by
226 commands like {command}`sudo`.
234 description = lib.mdDoc ''
235 Enable or disable TTY auditing for specified users
239 enablePattern = mkOption {
240 type = types.nullOr types.str;
242 description = lib.mdDoc ''
243 For each user matching one of comma-separated
244 glob patterns, enable TTY auditing
248 disablePattern = mkOption {
249 type = types.nullOr types.str;
251 description = lib.mdDoc ''
252 For each user matching one of comma-separated
253 glob patterns, disable TTY auditing
257 openOnly = mkOption {
260 description = lib.mdDoc ''
261 Set the TTY audit flag when opening the session,
262 but do not restore it when closing the session.
263 Using this option is necessary for some services
264 that don't fork() to run the authenticated session,
270 forwardXAuth = mkOption {
273 description = lib.mdDoc ''
274 Whether X authentication keys should be passed from the
275 calling user to the target user (e.g. for
280 pamMount = mkOption {
281 default = config.security.pam.mount.enable;
282 defaultText = literalExpression "config.security.pam.mount.enable";
284 description = lib.mdDoc ''
285 Enable PAM mount (pam_mount) system to mount fileystems on user login.
289 allowNullPassword = mkOption {
292 description = lib.mdDoc ''
293 Whether to allow logging into accounts that have no password
294 set (i.e., have an empty password field in
295 {file}`/etc/passwd` or
296 {file}`/etc/group`). This does not enable
297 logging into disabled accounts (i.e., that have the password
298 field set to `!`). Note that regardless of
299 what the pam_unix documentation says, accounts with hashed
300 empty passwords are always allowed to log in.
307 description = lib.mdDoc ''
308 Wheather the delay after typing a wrong password should be disabled.
312 requireWheel = mkOption {
315 description = lib.mdDoc ''
316 Whether to permit root access only to members of group wheel.
323 description = lib.mdDoc ''
324 Attribute set describing resource limits. Defaults to the
325 value of {option}`security.pam.loginLimits`.
326 The meaning of the values is explained in {manpage}`limits.conf(5)`.
330 showMotd = mkOption {
333 description = lib.mdDoc "Whether to show the message of the day.";
336 makeHomeDir = mkOption {
339 description = lib.mdDoc ''
340 Whether to try to create home directories for users
341 with `$HOME`s pointing to nonexistent
342 locations on session login.
346 updateWtmp = mkOption {
349 description = lib.mdDoc "Whether to update {file}`/var/log/wtmp`.";
352 logFailures = mkOption {
355 description = lib.mdDoc "Whether to log authentication failures in {file}`/var/log/faillog`.";
358 enableAppArmor = mkOption {
361 description = lib.mdDoc ''
362 Enable support for attaching AppArmor profiles at the
363 user/group level, e.g., as part of a role based access
368 enableKwallet = mkOption {
371 description = lib.mdDoc ''
372 If enabled, pam_wallet will attempt to automatically unlock the
373 user's default KDE wallet upon login. If the user has no wallet named
374 "kdewallet", or the login password does not match their wallet
375 password, KDE will prompt separately after login.
378 sssdStrictAccess = mkOption {
381 description = lib.mdDoc "enforce sssd access control";
384 enableGnomeKeyring = mkOption {
387 description = lib.mdDoc ''
388 If enabled, pam_gnome_keyring will attempt to automatically unlock the
389 user's default Gnome keyring upon login. If the user login password does
390 not match their keyring password, Gnome Keyring will prompt separately
399 description = lib.mdDoc ''
400 If enabled, this will replace the `FAIL_DELAY` setting from `login.defs`.
401 Change the delay on failure per-application.
409 description = lib.mdDoc "The delay time (in microseconds) on failure.";
417 description = lib.mdDoc ''
418 If enabled, pam_gnupg will attempt to automatically unlock the
419 user's GPG keys with the login password via
420 {command}`gpg-agent`. The keygrips of all keys to be
421 unlocked should be written to {file}`~/.pam-gnupg`,
422 and can be queried with {command}`gpg -K --with-keygrip`.
423 Presetting passphrases must be enabled by adding
424 `allow-preset-passphrase` in
425 {file}`~/.gnupg/gpg-agent.conf`.
429 noAutostart = mkOption {
432 description = lib.mdDoc ''
433 Don't start {command}`gpg-agent` if it is not running.
434 Useful in conjunction with starting {command}`gpg-agent` as
435 a systemd user service.
439 storeOnly = mkOption {
442 description = lib.mdDoc ''
443 Don't send the password immediately after login, but store for PAM
450 type = types.nullOr types.lines;
451 description = lib.mdDoc "Contents of the PAM service file.";
456 # The resulting /etc/pam.d/* file contents are verified in
457 # nixos/tests/pam/pam-file-contents.nix. Please update tests there when
458 # changing the derivation.
460 name = mkDefault name;
461 setLoginUid = mkDefault cfg.startSession;
462 limits = mkDefault config.security.pam.loginLimits;
464 # !!! TODO: move the LDAP stuff to the LDAP module, and the
465 # Samba stuff to the Samba module. This requires that the PAM
466 # module provides the right hooks.
470 # Account management.
472 optionalString use_ldap ''
473 account sufficient ${pam_ldap}/lib/security/pam_ldap.so
475 optionalString cfg.mysqlAuth ''
476 account sufficient ${pkgs.pam_mysql}/lib/security/pam_mysql.so config_file=/etc/security/pam_mysql.conf
478 optionalString (config.services.sssd.enable && cfg.sssdStrictAccess==false) ''
479 account sufficient ${pkgs.sssd}/lib/security/pam_sss.so
481 optionalString (config.services.sssd.enable && cfg.sssdStrictAccess) ''
482 account [default=bad success=ok user_unknown=ignore] ${pkgs.sssd}/lib/security/pam_sss.so
484 optionalString config.security.pam.krb5.enable ''
485 account sufficient ${pam_krb5}/lib/security/pam_krb5.so
487 optionalString cfg.googleOsLoginAccountVerification ''
488 account [success=ok ignore=ignore default=die] ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so
489 account [success=ok default=ignore] ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_admin.so
491 # The required pam_unix.so module has to come after all the sufficient modules
492 # because otherwise, the account lookup will fail if the user does not exist
493 # locally, for example with MySQL- or LDAP-auth.
495 account required pam_unix.so
497 # Authentication management.
499 optionalString cfg.googleOsLoginAuthentication ''
500 auth [success=done perm_denied=die default=ignore] ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so
502 optionalString cfg.rootOK ''
503 auth sufficient pam_rootok.so
505 optionalString cfg.requireWheel ''
506 auth required pam_wheel.so use_uid
508 optionalString cfg.logFailures ''
509 auth required pam_faillock.so
511 optionalString cfg.mysqlAuth ''
512 auth sufficient ${pkgs.pam_mysql}/lib/security/pam_mysql.so config_file=/etc/security/pam_mysql.conf
514 optionalString (config.security.pam.enableSSHAgentAuth && cfg.sshAgentAuth) ''
515 auth sufficient ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so file=${lib.concatStringsSep ":" config.services.openssh.authorizedKeysFiles}
517 (let p11 = config.security.pam.p11; in optionalString cfg.p11Auth ''
518 auth ${p11.control} ${pkgs.pam_p11}/lib/security/pam_p11.so ${pkgs.opensc}/lib/opensc-pkcs11.so
520 (let u2f = config.security.pam.u2f; in optionalString cfg.u2fAuth (''
521 auth ${u2f.control} ${pkgs.pam_u2f}/lib/security/pam_u2f.so ${optionalString u2f.debug "debug"} ${optionalString (u2f.authFile != null) "authfile=${u2f.authFile}"} ''
522 + ''${optionalString u2f.interactive "interactive"} ${optionalString u2f.cue "cue"} ${optionalString (u2f.appId != null) "appid=${u2f.appId}"} ${optionalString (u2f.origin != null) "origin=${u2f.origin}"}
524 optionalString cfg.usbAuth ''
525 auth sufficient ${pkgs.pam_usb}/lib/security/pam_usb.so
527 (let ussh = config.security.pam.ussh; in optionalString (config.security.pam.ussh.enable && cfg.usshAuth) ''
528 auth ${ussh.control} ${pkgs.pam_ussh}/lib/security/pam_ussh.so ${optionalString (ussh.caFile != null) "ca_file=${ussh.caFile}"} ${optionalString (ussh.authorizedPrincipals != null) "authorized_principals=${ussh.authorizedPrincipals}"} ${optionalString (ussh.authorizedPrincipalsFile != null) "authorized_principals_file=${ussh.authorizedPrincipalsFile}"} ${optionalString (ussh.group != null) "group=${ussh.group}"}
530 (let oath = config.security.pam.oath; in optionalString cfg.oathAuth ''
531 auth requisite ${pkgs.oath-toolkit}/lib/security/pam_oath.so window=${toString oath.window} usersfile=${toString oath.usersFile} digits=${toString oath.digits}
533 (let yubi = config.security.pam.yubico; in optionalString cfg.yubicoAuth ''
534 auth ${yubi.control} ${pkgs.yubico-pam}/lib/security/pam_yubico.so mode=${toString yubi.mode} ${optionalString (yubi.challengeResponsePath != null) "chalresp_path=${yubi.challengeResponsePath}"} ${optionalString (yubi.mode == "client") "id=${toString yubi.id}"} ${optionalString yubi.debug "debug"}
536 optionalString cfg.fprintAuth ''
537 auth sufficient ${pkgs.fprintd}/lib/security/pam_fprintd.so
539 # Modules in this block require having the password set in PAM_AUTHTOK.
540 # pam_unix is marked as 'sufficient' on NixOS which means nothing will run
541 # after it succeeds. Certain modules need to run after pam_unix
542 # prompts the user for password so we run it once with 'optional' at an
543 # earlier point and it will run again with 'sufficient' further down.
544 # We use try_first_pass the second time to avoid prompting password twice
545 (optionalString (cfg.unixAuth &&
546 (config.security.pam.enableEcryptfs
549 || cfg.enableGnomeKeyring
550 || cfg.googleAuthenticator.enable
552 || cfg.failDelay.enable
553 || cfg.duoSecurity.enable))
556 auth optional pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} ${optionalString cfg.nodelay "nodelay"} likeauth
558 optionalString config.security.pam.enableEcryptfs ''
559 auth optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap
561 optionalString cfg.pamMount ''
562 auth optional ${pkgs.pam_mount}/lib/security/pam_mount.so disable_interactive
564 optionalString cfg.enableKwallet ''
565 auth optional ${pkgs.plasma5Packages.kwallet-pam}/lib/security/pam_kwallet5.so kwalletd=${pkgs.plasma5Packages.kwallet.bin}/bin/kwalletd5
567 optionalString cfg.enableGnomeKeyring ''
568 auth optional ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so
570 optionalString cfg.gnupg.enable ''
571 auth optional ${pkgs.pam_gnupg}/lib/security/pam_gnupg.so ${optionalString cfg.gnupg.storeOnly " store-only"}
573 optionalString cfg.failDelay.enable ''
574 auth optional ${pkgs.pam}/lib/security/pam_faildelay.so delay=${toString cfg.failDelay.delay}
576 optionalString cfg.googleAuthenticator.enable ''
577 auth required ${pkgs.google-authenticator}/lib/security/pam_google_authenticator.so no_increment_hotp
579 optionalString cfg.duoSecurity.enable ''
580 auth required ${pkgs.duo-unix}/lib/security/pam_duo.so
583 optionalString cfg.unixAuth ''
584 auth sufficient pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} ${optionalString cfg.nodelay "nodelay"} likeauth try_first_pass
586 optionalString cfg.otpwAuth ''
587 auth sufficient ${pkgs.otpw}/lib/security/pam_otpw.so
589 optionalString use_ldap ''
590 auth sufficient ${pam_ldap}/lib/security/pam_ldap.so use_first_pass
592 optionalString config.services.sssd.enable ''
593 auth sufficient ${pkgs.sssd}/lib/security/pam_sss.so use_first_pass
595 optionalString config.security.pam.krb5.enable ''
596 auth [default=ignore success=1 service_err=reset] ${pam_krb5}/lib/security/pam_krb5.so use_first_pass
597 auth [default=die success=done] ${pam_ccreds}/lib/security/pam_ccreds.so action=validate use_first_pass
598 auth sufficient ${pam_ccreds}/lib/security/pam_ccreds.so action=store use_first_pass
601 auth required pam_deny.so
603 # Password management.
604 password sufficient pam_unix.so nullok sha512
606 optionalString config.security.pam.enableEcryptfs ''
607 password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so
609 optionalString cfg.pamMount ''
610 password optional ${pkgs.pam_mount}/lib/security/pam_mount.so
612 optionalString use_ldap ''
613 password sufficient ${pam_ldap}/lib/security/pam_ldap.so
615 optionalString cfg.mysqlAuth ''
616 password sufficient ${pkgs.pam_mysql}/lib/security/pam_mysql.so config_file=/etc/security/pam_mysql.conf
618 optionalString config.services.sssd.enable ''
619 password sufficient ${pkgs.sssd}/lib/security/pam_sss.so use_authtok
621 optionalString config.security.pam.krb5.enable ''
622 password sufficient ${pam_krb5}/lib/security/pam_krb5.so use_first_pass
624 optionalString cfg.enableGnomeKeyring ''
625 password optional ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so use_authtok
629 # Session management.
631 optionalString cfg.setEnvironment ''
632 session required pam_env.so conffile=/etc/pam/environment readenv=0
635 session required pam_unix.so
637 optionalString cfg.setLoginUid ''
638 session ${if config.boot.isContainer then "optional" else "required"} pam_loginuid.so
640 optionalString cfg.ttyAudit.enable (concatStringsSep " \\\n " ([
641 "session required ${pkgs.pam}/lib/security/pam_tty_audit.so"
642 ] ++ optional cfg.ttyAudit.openOnly "open_only"
643 ++ optional (cfg.ttyAudit.enablePattern != null) "enable=${cfg.ttyAudit.enablePattern}"
644 ++ optional (cfg.ttyAudit.disablePattern != null) "disable=${cfg.ttyAudit.disablePattern}"
646 optionalString cfg.makeHomeDir ''
647 session required ${pkgs.pam}/lib/security/pam_mkhomedir.so silent skel=${config.security.pam.makeHomeDir.skelDirectory} umask=0077
649 optionalString cfg.updateWtmp ''
650 session required ${pkgs.pam}/lib/security/pam_lastlog.so silent
652 optionalString config.security.pam.enableEcryptfs ''
653 session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so
655 optionalString cfg.pamMount ''
656 session optional ${pkgs.pam_mount}/lib/security/pam_mount.so disable_interactive
658 optionalString use_ldap ''
659 session optional ${pam_ldap}/lib/security/pam_ldap.so
661 optionalString cfg.mysqlAuth ''
662 session optional ${pkgs.pam_mysql}/lib/security/pam_mysql.so config_file=/etc/security/pam_mysql.conf
664 optionalString config.services.sssd.enable ''
665 session optional ${pkgs.sssd}/lib/security/pam_sss.so
667 optionalString config.security.pam.krb5.enable ''
668 session optional ${pam_krb5}/lib/security/pam_krb5.so
670 optionalString cfg.otpwAuth ''
671 session optional ${pkgs.otpw}/lib/security/pam_otpw.so
673 optionalString cfg.startSession ''
674 session optional ${config.systemd.package}/lib/security/pam_systemd.so
676 optionalString cfg.forwardXAuth ''
677 session optional pam_xauth.so xauthpath=${pkgs.xorg.xauth}/bin/xauth systemuser=99
679 optionalString (cfg.limits != []) ''
680 session required ${pkgs.pam}/lib/security/pam_limits.so conf=${makeLimitsConf cfg.limits}
682 optionalString (cfg.showMotd && config.users.motd != null) ''
683 session optional ${pkgs.pam}/lib/security/pam_motd.so motd=${motd}
685 optionalString (cfg.enableAppArmor && config.security.apparmor.enable) ''
686 session optional ${pkgs.apparmor-pam}/lib/security/pam_apparmor.so order=user,group,default debug
688 optionalString (cfg.enableKwallet) ''
689 session optional ${pkgs.plasma5Packages.kwallet-pam}/lib/security/pam_kwallet5.so kwalletd=${pkgs.plasma5Packages.kwallet.bin}/bin/kwalletd5
691 optionalString (cfg.enableGnomeKeyring) ''
692 session optional ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so auto_start
694 optionalString cfg.gnupg.enable ''
695 session optional ${pkgs.pam_gnupg}/lib/security/pam_gnupg.so ${optionalString cfg.gnupg.noAutostart " no-autostart"}
697 optionalString (config.virtualisation.lxc.lxcfs.enable) ''
698 session optional ${pkgs.lxc}/lib/security/pam_cgfs.so -c all
706 inherit (pkgs) pam_krb5 pam_ccreds;
708 use_ldap = (config.users.ldap.enable && config.users.ldap.loginPam);
709 pam_ldap = if config.users.ldap.daemon.enable then pkgs.nss_pam_ldapd else pkgs.pam_ldap;
711 # Create a limits.conf(5) file.
712 makeLimitsConf = limits:
713 pkgs.writeText "limits.conf"
714 (concatMapStrings ({ domain, type, item, value }:
715 "${domain} ${type} ${item} ${toString value}\n")
718 limitsType = with lib.types; listOf (submodule ({ ... }: {
721 description = lib.mdDoc "Username, groupname, or wildcard this limit applies to";
727 description = lib.mdDoc "Type of this limit";
728 type = enum [ "-" "hard" "soft" ];
733 description = lib.mdDoc "Item this limit applies to";
757 description = lib.mdDoc "Value of this limit";
758 type = oneOf [ str int ];
763 motd = pkgs.writeText "motd" config.users.motd;
765 makePAMService = name: service:
766 { name = "pam.d/${name}";
767 value.source = pkgs.writeText "${name}.pam" service.text;
775 (mkRenamedOptionModule [ "security" "pam" "enableU2F" ] [ "security" "pam" "u2f" "enable" ])
782 security.pam.loginLimits = mkOption {
791 { domain = "@student";
798 description = lib.mdDoc ''
799 Define resource limits that should apply to users or groups.
800 Each item in the list should be an attribute set with a
801 {var}`domain`, {var}`type`,
802 {var}`item`, and {var}`value`
803 attribute. The syntax and semantics of these attributes
804 must be that described in {manpage}`limits.conf(5)`.
806 Note that these limits do not apply to systemd services,
807 whose limits can be changed via {option}`systemd.extraConfig`
812 security.pam.services = mkOption {
814 type = with types; attrsOf (submodule pamOpts);
817 This option defines the PAM services. A service typically
818 corresponds to a program that uses PAM,
819 e.g. {command}`login` or {command}`passwd`.
820 Each attribute of this set defines a PAM service, with the attribute name
821 defining the name of the service.
825 security.pam.makeHomeDir.skelDirectory = mkOption {
827 default = "/var/empty";
828 example = "/etc/skel";
829 description = lib.mdDoc ''
830 Path to skeleton directory whose contents are copied to home
831 directories newly created by `pam_mkhomedir`.
835 security.pam.enableSSHAgentAuth = mkOption {
840 Enable sudo logins if the user's SSH agent provides a key
841 present in {file}`~/.ssh/authorized_keys`.
842 This allows machines to exclusively use SSH keys instead of
847 security.pam.enableOTPW = mkEnableOption (lib.mdDoc "the OTPW (one-time password) PAM module");
849 security.pam.krb5 = {
851 default = config.krb5.enable;
852 defaultText = literalExpression "config.krb5.enable";
854 description = lib.mdDoc ''
855 Enables Kerberos PAM modules (`pam-krb5`,
858 If set, users can authenticate with their Kerberos password.
859 This requires a valid Kerberos configuration
860 (`config.krb5.enable` should be set to
863 Note that the Kerberos PAM modules are not necessary when using SSS
864 to handle Kerberos authentication.
873 description = lib.mdDoc ''
874 Enables P11 PAM (`pam_p11`) module.
876 If set, users can log in with SSH keys and PKCS#11 tokens.
878 More information can be found [here](https://github.com/OpenSC/pam_p11).
883 default = "sufficient";
884 type = types.enum [ "required" "requisite" "sufficient" "optional" ];
885 description = lib.mdDoc ''
886 This option sets pam "control".
887 If you want to have multi factor authentication, use "required".
888 If you want to use the PKCS#11 device instead of the regular password,
892 {manpage}`pam.conf(5)`
893 for better understanding of this option.
902 description = lib.mdDoc ''
903 Enables U2F PAM (`pam-u2f`) module.
905 If set, users listed in
906 {file}`$XDG_CONFIG_HOME/Yubico/u2f_keys` (or
907 {file}`$HOME/.config/Yubico/u2f_keys` if XDG variable is
908 not set) are able to log in with the associated U2F key. The path can
909 be changed using {option}`security.pam.u2f.authFile` option.
912 `username:first_keyHandle,first_public_key: second_keyHandle,second_public_key`
913 This file can be generated using {command}`pamu2fcfg` command.
915 More information can be found [here](https://developers.yubico.com/pam-u2f/).
919 authFile = mkOption {
921 type = with types; nullOr path;
922 description = lib.mdDoc ''
923 By default `pam-u2f` module reads the keys from
924 {file}`$XDG_CONFIG_HOME/Yubico/u2f_keys` (or
925 {file}`$HOME/.config/Yubico/u2f_keys` if XDG variable is
928 If you want to change auth file locations or centralize database (for
929 example use {file}`/etc/u2f-mappings`) you can set this
933 `username:first_keyHandle,first_public_key: second_keyHandle,second_public_key`
934 This file can be generated using {command}`pamu2fcfg` command.
936 More information can be found [here](https://developers.yubico.com/pam-u2f/).
942 type = with types; nullOr str;
943 description = lib.mdDoc ''
944 By default `pam-u2f` module sets the application
945 ID to `pam://$HOSTNAME`.
947 When using {command}`pamu2fcfg`, you can specify your
948 application ID with the `-i` flag.
950 More information can be found [here](https://developers.yubico.com/pam-u2f/Manuals/pam_u2f.8.html)
956 type = with types; nullOr str;
957 description = lib.mdDoc ''
958 By default `pam-u2f` module sets the origin
959 to `pam://$HOSTNAME`.
960 Setting origin to an host independent value will allow you to
961 reuse credentials across machines
963 When using {command}`pamu2fcfg`, you can specify your
964 application ID with the `-o` flag.
966 More information can be found [here](https://developers.yubico.com/pam-u2f/Manuals/pam_u2f.8.html)
971 default = "sufficient";
972 type = types.enum [ "required" "requisite" "sufficient" "optional" ];
973 description = lib.mdDoc ''
974 This option sets pam "control".
975 If you want to have multi factor authentication, use "required".
976 If you want to use U2F device instead of regular password, use "sufficient".
979 {manpage}`pam.conf(5)`
980 for better understanding of this option.
987 description = lib.mdDoc ''
988 Debug output to stderr.
992 interactive = mkOption {
995 description = lib.mdDoc ''
996 Set to prompt a message and wait before testing the presence of a U2F device.
997 Recommended if your device doesn’t have a tactile trigger.
1004 description = lib.mdDoc ''
1005 By default `pam-u2f` module does not inform user
1006 that he needs to use the u2f device, it just waits without a prompt.
1008 If you set this option to `true`,
1009 `cue` option is added to `pam-u2f`
1010 module and reminder message will be displayed.
1015 security.pam.ussh = {
1019 description = lib.mdDoc ''
1020 Enables Uber's USSH PAM (`pam-ussh`) module.
1022 This is similar to `pam-ssh-agent`, except that
1023 the presence of a CA-signed SSH key with a valid principal is checked
1026 Note that this module must both be enabled using this option and on a
1027 per-PAM-service level as well (using `usshAuth`).
1029 More information can be found [here](https://github.com/uber/pam-ussh).
1035 type = with types; nullOr path;
1036 description = lib.mdDoc ''
1037 By default `pam-ussh` reads the trusted user CA keys
1038 from {file}`/etc/ssh/trusted_user_ca`.
1040 This should be set the same as your `TrustedUserCAKeys`
1045 authorizedPrincipals = mkOption {
1047 type = with types; nullOr commas;
1048 description = lib.mdDoc ''
1049 Comma-separated list of authorized principals to permit; if the user
1050 presents a certificate with one of these principals, then they will be
1053 Note that `pam-ussh` also requires that the certificate
1054 contain a principal matching the user's username. The principals from
1055 this list are in addition to those principals.
1057 Mutually exclusive with `authorizedPrincipalsFile`.
1061 authorizedPrincipalsFile = mkOption {
1063 type = with types; nullOr path;
1064 description = lib.mdDoc ''
1065 Path to a list of principals; if the user presents a certificate with
1066 one of these principals, then they will be authorized.
1068 Note that `pam-ussh` also requires that the certificate
1069 contain a principal matching the user's username. The principals from
1070 this file are in addition to those principals.
1072 Mutually exclusive with `authorizedPrincipals`.
1078 type = with types; nullOr str;
1079 description = lib.mdDoc ''
1080 If set, then the authenticating user must be a member of this group
1085 control = mkOption {
1086 default = "sufficient";
1087 type = types.enum [ "required" "requisite" "sufficient" "optional" ];
1088 description = lib.mdDoc ''
1089 This option sets pam "control".
1090 If you want to have multi factor authentication, use "required".
1091 If you want to use the SSH certificate instead of the regular password,
1095 {manpage}`pam.conf(5)`
1096 for better understanding of this option.
1101 security.pam.yubico = {
1105 description = lib.mdDoc ''
1106 Enables Yubico PAM (`yubico-pam`) module.
1108 If set, users listed in
1109 {file}`~/.yubico/authorized_yubikeys`
1110 are able to log in with the associated Yubikey tokens.
1112 The file must have only one line:
1113 `username:yubikey_token_id1:yubikey_token_id2`
1114 More information can be found [here](https://developers.yubico.com/yubico-pam/).
1117 control = mkOption {
1118 default = "sufficient";
1119 type = types.enum [ "required" "requisite" "sufficient" "optional" ];
1120 description = lib.mdDoc ''
1121 This option sets pam "control".
1122 If you want to have multi factor authentication, use "required".
1123 If you want to use Yubikey instead of regular password, use "sufficient".
1126 {manpage}`pam.conf(5)`
1127 for better understanding of this option.
1133 description = lib.mdDoc "client id";
1139 description = lib.mdDoc ''
1140 Debug output to stderr.
1145 type = types.enum [ "client" "challenge-response" ];
1146 description = lib.mdDoc ''
1149 Use "client" for online validation with a YubiKey validation service such as
1152 Use "challenge-response" for offline validation using YubiKeys with HMAC-SHA-1
1153 Challenge-Response configurations. See the man-page ykpamcfg(1) for further
1154 details on how to configure offline Challenge-Response validation.
1156 More information can be found [here](https://developers.yubico.com/yubico-pam/Authentication_Using_Challenge-Response.html).
1159 challengeResponsePath = mkOption {
1161 type = types.nullOr types.path;
1162 description = lib.mdDoc ''
1163 If not null, set the path used by yubico pam module where the challenge expected response is stored.
1165 More information can be found [here](https://developers.yubico.com/yubico-pam/Authentication_Using_Challenge-Response.html).
1170 security.pam.enableEcryptfs = mkEnableOption (lib.mdDoc "eCryptfs PAM module (mounting ecryptfs home directory on login)");
1172 users.motd = mkOption {
1174 example = "Today is Sweetmorn, the 4th day of The Aftermath in the YOLD 3178.";
1175 type = types.nullOr types.lines;
1176 description = lib.mdDoc "Message of the day shown to users when they log in.";
1182 ###### implementation
1186 environment.systemPackages =
1187 # Include the PAM modules in the system path mostly for the manpages.
1189 ++ optional config.users.ldap.enable pam_ldap
1190 ++ optional config.services.sssd.enable pkgs.sssd
1191 ++ optionals config.security.pam.krb5.enable [pam_krb5 pam_ccreds]
1192 ++ optionals config.security.pam.enableOTPW [ pkgs.otpw ]
1193 ++ optionals config.security.pam.oath.enable [ pkgs.oath-toolkit ]
1194 ++ optionals config.security.pam.p11.enable [ pkgs.pam_p11 ]
1195 ++ optionals config.security.pam.u2f.enable [ pkgs.pam_u2f ];
1197 boot.supportedFilesystems = optionals config.security.pam.enableEcryptfs [ "ecryptfs" ];
1199 security.wrappers = {
1204 source = "${pkgs.pam}/bin/unix_chkpwd";
1208 environment.etc = mapAttrs' makePAMService config.security.pam.services;
1210 security.pam.services =
1213 auth required pam_warn.so
1214 auth required pam_deny.so
1215 account required pam_warn.so
1216 account required pam_deny.so
1217 password required pam_warn.so
1218 password required pam_deny.so
1219 session required pam_warn.so
1220 session required pam_deny.so
1223 # Most of these should be moved to specific modules.
1230 runuser = { rootOK = true; unixAuth = false; setEnvironment = false; };
1232 /* FIXME: should runuser -l start a systemd session? Currently
1233 it complains "Cannot create session: Already running in a
1235 runuser-l = { rootOK = true; unixAuth = false; };
1238 security.apparmor.includes."abstractions/pam" = let
1239 isEnabled = test: fold or false (map test (attrValues config.security.pam.services));
1241 lib.concatMapStrings
1242 (name: "r ${config.environment.etc."pam.d/${name}".source},\n")
1243 (attrNames config.security.pam.services) +
1245 mr ${getLib pkgs.pam}/lib/security/pam_filter/*,
1246 mr ${getLib pkgs.pam}/lib/security/pam_*.so,
1247 r ${getLib pkgs.pam}/lib/security/,
1249 optionalString use_ldap ''
1250 mr ${pam_ldap}/lib/security/pam_ldap.so,
1252 optionalString config.services.sssd.enable ''
1253 mr ${pkgs.sssd}/lib/security/pam_sss.so,
1255 optionalString config.security.pam.krb5.enable ''
1256 mr ${pam_krb5}/lib/security/pam_krb5.so,
1257 mr ${pam_ccreds}/lib/security/pam_ccreds.so,
1259 optionalString (isEnabled (cfg: cfg.googleOsLoginAccountVerification)) ''
1260 mr ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so,
1261 mr ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_admin.so,
1263 optionalString (isEnabled (cfg: cfg.googleOsLoginAuthentication)) ''
1264 mr ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so,
1266 optionalString (config.security.pam.enableSSHAgentAuth
1267 && isEnabled (cfg: cfg.sshAgentAuth)) ''
1268 mr ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so,
1270 optionalString (isEnabled (cfg: cfg.fprintAuth)) ''
1271 mr ${pkgs.fprintd}/lib/security/pam_fprintd.so,
1273 optionalString (isEnabled (cfg: cfg.u2fAuth)) ''
1274 mr ${pkgs.pam_u2f}/lib/security/pam_u2f.so,
1276 optionalString (isEnabled (cfg: cfg.usbAuth)) ''
1277 mr ${pkgs.pam_usb}/lib/security/pam_usb.so,
1279 optionalString (isEnabled (cfg: cfg.usshAuth)) ''
1280 mr ${pkgs.pam_ussh}/lib/security/pam_ussh.so,
1282 optionalString (isEnabled (cfg: cfg.oathAuth)) ''
1283 "mr ${pkgs.oath-toolkit}/lib/security/pam_oath.so,
1285 optionalString (isEnabled (cfg: cfg.mysqlAuth)) ''
1286 mr ${pkgs.pam_mysql}/lib/security/pam_mysql.so,
1288 optionalString (isEnabled (cfg: cfg.yubicoAuth)) ''
1289 mr ${pkgs.yubico-pam}/lib/security/pam_yubico.so,
1291 optionalString (isEnabled (cfg: cfg.duoSecurity.enable)) ''
1292 mr ${pkgs.duo-unix}/lib/security/pam_duo.so,
1294 optionalString (isEnabled (cfg: cfg.otpwAuth)) ''
1295 mr ${pkgs.otpw}/lib/security/pam_otpw.so,
1297 optionalString config.security.pam.enableEcryptfs ''
1298 mr ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so,
1300 optionalString (isEnabled (cfg: cfg.pamMount)) ''
1301 mr ${pkgs.pam_mount}/lib/security/pam_mount.so,
1303 optionalString (isEnabled (cfg: cfg.enableGnomeKeyring)) ''
1304 mr ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so,
1306 optionalString (isEnabled (cfg: cfg.startSession)) ''
1307 mr ${config.systemd.package}/lib/security/pam_systemd.so,
1309 optionalString (isEnabled (cfg: cfg.enableAppArmor)
1310 && config.security.apparmor.enable) ''
1311 mr ${pkgs.apparmor-pam}/lib/security/pam_apparmor.so,
1313 optionalString (isEnabled (cfg: cfg.enableKwallet)) ''
1314 mr ${pkgs.plasma5Packages.kwallet-pam}/lib/security/pam_kwallet5.so,
1316 optionalString config.virtualisation.lxc.lxcfs.enable ''
1317 mr ${pkgs.lxc}/lib/security/pam_cgfs.so