at 22.05-pre 40 kB view raw
1# This module provides configuration for the PAM (Pluggable 2# Authentication Modules) system. 3 4{ config, lib, pkgs, ... }: 5 6with lib; 7 8let 9 parentConfig = config; 10 11 pamOpts = { config, name, ... }: let cfg = config; in let config = parentConfig; in { 12 13 options = { 14 15 name = mkOption { 16 example = "sshd"; 17 type = types.str; 18 description = "Name of the PAM service."; 19 }; 20 21 unixAuth = mkOption { 22 default = true; 23 type = types.bool; 24 description = '' 25 Whether users can log in with passwords defined in 26 <filename>/etc/shadow</filename>. 27 ''; 28 }; 29 30 rootOK = mkOption { 31 default = false; 32 type = types.bool; 33 description = '' 34 If set, root doesn't need to authenticate (e.g. for the 35 <command>useradd</command> service). 36 ''; 37 }; 38 39 p11Auth = mkOption { 40 default = config.security.pam.p11.enable; 41 type = types.bool; 42 description = '' 43 If set, keys listed in 44 <filename>~/.ssh/authorized_keys</filename> and 45 <filename>~/.eid/authorized_certificates</filename> 46 can be used to log in with the associated PKCS#11 tokens. 47 ''; 48 }; 49 50 u2fAuth = mkOption { 51 default = config.security.pam.u2f.enable; 52 type = types.bool; 53 description = '' 54 If set, users listed in 55 <filename>$XDG_CONFIG_HOME/Yubico/u2f_keys</filename> (or 56 <filename>$HOME/.config/Yubico/u2f_keys</filename> if XDG variable is 57 not set) are able to log in with the associated U2F key. Path can be 58 changed using <option>security.pam.u2f.authFile</option> option. 59 ''; 60 }; 61 62 yubicoAuth = mkOption { 63 default = config.security.pam.yubico.enable; 64 type = types.bool; 65 description = '' 66 If set, users listed in 67 <filename>~/.yubico/authorized_yubikeys</filename> 68 are able to log in with the associated Yubikey tokens. 69 ''; 70 }; 71 72 googleAuthenticator = { 73 enable = mkOption { 74 default = false; 75 type = types.bool; 76 description = '' 77 If set, users with enabled Google Authenticator (created 78 <filename>~/.google_authenticator</filename>) will be required 79 to provide Google Authenticator token to log in. 80 ''; 81 }; 82 }; 83 84 usbAuth = mkOption { 85 default = config.security.pam.usb.enable; 86 type = types.bool; 87 description = '' 88 If set, users listed in 89 <filename>/etc/pamusb.conf</filename> are able to log in 90 with the associated USB key. 91 ''; 92 }; 93 94 otpwAuth = mkOption { 95 default = config.security.pam.enableOTPW; 96 type = types.bool; 97 description = '' 98 If set, the OTPW system will be used (if 99 <filename>~/.otpw</filename> exists). 100 ''; 101 }; 102 103 googleOsLoginAccountVerification = mkOption { 104 default = false; 105 type = types.bool; 106 description = '' 107 If set, will use the Google OS Login PAM modules 108 (<literal>pam_oslogin_login</literal>, 109 <literal>pam_oslogin_admin</literal>) to verify possible OS Login 110 users and set sudoers configuration accordingly. 111 This only makes sense to enable for the <literal>sshd</literal> PAM 112 service. 113 ''; 114 }; 115 116 googleOsLoginAuthentication = mkOption { 117 default = false; 118 type = types.bool; 119 description = '' 120 If set, will use the <literal>pam_oslogin_login</literal>'s user 121 authentication methods to authenticate users using 2FA. 122 This only makes sense to enable for the <literal>sshd</literal> PAM 123 service. 124 ''; 125 }; 126 127 fprintAuth = mkOption { 128 default = config.services.fprintd.enable; 129 type = types.bool; 130 description = '' 131 If set, fingerprint reader will be used (if exists and 132 your fingerprints are enrolled). 133 ''; 134 }; 135 136 oathAuth = mkOption { 137 default = config.security.pam.oath.enable; 138 type = types.bool; 139 description = '' 140 If set, the OATH Toolkit will be used. 141 ''; 142 }; 143 144 sshAgentAuth = mkOption { 145 default = false; 146 type = types.bool; 147 description = '' 148 If set, the calling user's SSH agent is used to authenticate 149 against the keys in the calling user's 150 <filename>~/.ssh/authorized_keys</filename>. This is useful 151 for <command>sudo</command> on password-less remote systems. 152 ''; 153 }; 154 155 duoSecurity = { 156 enable = mkOption { 157 default = false; 158 type = types.bool; 159 description = '' 160 If set, use the Duo Security pam module 161 <literal>pam_duo</literal> for authentication. Requires 162 configuration of <option>security.duosec</option> options. 163 ''; 164 }; 165 }; 166 167 startSession = mkOption { 168 default = false; 169 type = types.bool; 170 description = '' 171 If set, the service will register a new session with 172 systemd's login manager. For local sessions, this will give 173 the user access to audio devices, CD-ROM drives. In the 174 default PolicyKit configuration, it also allows the user to 175 reboot the system. 176 ''; 177 }; 178 179 setEnvironment = mkOption { 180 type = types.bool; 181 default = true; 182 description = '' 183 Whether the service should set the environment variables 184 listed in <option>environment.sessionVariables</option> 185 using <literal>pam_env.so</literal>. 186 ''; 187 }; 188 189 setLoginUid = mkOption { 190 type = types.bool; 191 description = '' 192 Set the login uid of the process 193 (<filename>/proc/self/loginuid</filename>) for auditing 194 purposes. The login uid is only set by entry points like 195 <command>login</command> and <command>sshd</command>, not by 196 commands like <command>sudo</command>. 197 ''; 198 }; 199 200 ttyAudit = { 201 enable = mkOption { 202 type = types.bool; 203 default = false; 204 description = '' 205 Enable or disable TTY auditing for specified users 206 ''; 207 }; 208 209 enablePattern = mkOption { 210 type = types.nullOr types.str; 211 default = null; 212 description = '' 213 For each user matching one of comma-separated 214 glob patterns, enable TTY auditing 215 ''; 216 }; 217 218 disablePattern = mkOption { 219 type = types.nullOr types.str; 220 default = null; 221 description = '' 222 For each user matching one of comma-separated 223 glob patterns, disable TTY auditing 224 ''; 225 }; 226 227 openOnly = mkOption { 228 type = types.bool; 229 default = false; 230 description = '' 231 Set the TTY audit flag when opening the session, 232 but do not restore it when closing the session. 233 Using this option is necessary for some services 234 that don't fork() to run the authenticated session, 235 such as sudo. 236 ''; 237 }; 238 }; 239 240 forwardXAuth = mkOption { 241 default = false; 242 type = types.bool; 243 description = '' 244 Whether X authentication keys should be passed from the 245 calling user to the target user (e.g. for 246 <command>su</command>) 247 ''; 248 }; 249 250 pamMount = mkOption { 251 default = config.security.pam.mount.enable; 252 type = types.bool; 253 description = '' 254 Enable PAM mount (pam_mount) system to mount fileystems on user login. 255 ''; 256 }; 257 258 allowNullPassword = mkOption { 259 default = false; 260 type = types.bool; 261 description = '' 262 Whether to allow logging into accounts that have no password 263 set (i.e., have an empty password field in 264 <filename>/etc/passwd</filename> or 265 <filename>/etc/group</filename>). This does not enable 266 logging into disabled accounts (i.e., that have the password 267 field set to <literal>!</literal>). Note that regardless of 268 what the pam_unix documentation says, accounts with hashed 269 empty passwords are always allowed to log in. 270 ''; 271 }; 272 273 nodelay = mkOption { 274 default = false; 275 type = types.bool; 276 description = '' 277 Wheather the delay after typing a wrong password should be disabled. 278 ''; 279 }; 280 281 requireWheel = mkOption { 282 default = false; 283 type = types.bool; 284 description = '' 285 Whether to permit root access only to members of group wheel. 286 ''; 287 }; 288 289 limits = mkOption { 290 description = '' 291 Attribute set describing resource limits. Defaults to the 292 value of <option>security.pam.loginLimits</option>. 293 ''; 294 }; 295 296 showMotd = mkOption { 297 default = false; 298 type = types.bool; 299 description = "Whether to show the message of the day."; 300 }; 301 302 makeHomeDir = mkOption { 303 default = false; 304 type = types.bool; 305 description = '' 306 Whether to try to create home directories for users 307 with <literal>$HOME</literal>s pointing to nonexistent 308 locations on session login. 309 ''; 310 }; 311 312 updateWtmp = mkOption { 313 default = false; 314 type = types.bool; 315 description = "Whether to update <filename>/var/log/wtmp</filename>."; 316 }; 317 318 logFailures = mkOption { 319 default = false; 320 type = types.bool; 321 description = "Whether to log authentication failures in <filename>/var/log/faillog</filename>."; 322 }; 323 324 enableAppArmor = mkOption { 325 default = false; 326 type = types.bool; 327 description = '' 328 Enable support for attaching AppArmor profiles at the 329 user/group level, e.g., as part of a role based access 330 control scheme. 331 ''; 332 }; 333 334 enableKwallet = mkOption { 335 default = false; 336 type = types.bool; 337 description = '' 338 If enabled, pam_wallet will attempt to automatically unlock the 339 user's default KDE wallet upon login. If the user has no wallet named 340 "kdewallet", or the login password does not match their wallet 341 password, KDE will prompt separately after login. 342 ''; 343 }; 344 sssdStrictAccess = mkOption { 345 default = false; 346 type = types.bool; 347 description = "enforce sssd access control"; 348 }; 349 350 enableGnomeKeyring = mkOption { 351 default = false; 352 type = types.bool; 353 description = '' 354 If enabled, pam_gnome_keyring will attempt to automatically unlock the 355 user's default Gnome keyring upon login. If the user login password does 356 not match their keyring password, Gnome Keyring will prompt separately 357 after login. 358 ''; 359 }; 360 361 gnupg = { 362 enable = mkOption { 363 type = types.bool; 364 default = false; 365 description = '' 366 If enabled, pam_gnupg will attempt to automatically unlock the 367 user's GPG keys with the login password via 368 <command>gpg-agent</command>. The keygrips of all keys to be 369 unlocked should be written to <filename>~/.pam-gnupg</filename>, 370 and can be queried with <command>gpg -K --with-keygrip</command>. 371 Presetting passphrases must be enabled by adding 372 <literal>allow-preset-passphrase</literal> in 373 <filename>~/.gnupg/gpg-agent.conf</filename>. 374 ''; 375 }; 376 377 noAutostart = mkOption { 378 type = types.bool; 379 default = false; 380 description = '' 381 Don't start <command>gpg-agent</command> if it is not running. 382 Useful in conjunction with starting <command>gpg-agent</command> as 383 a systemd user service. 384 ''; 385 }; 386 387 storeOnly = mkOption { 388 type = types.bool; 389 default = false; 390 description = '' 391 Don't send the password immediately after login, but store for PAM 392 <literal>session</literal>. 393 ''; 394 }; 395 }; 396 397 text = mkOption { 398 type = types.nullOr types.lines; 399 description = "Contents of the PAM service file."; 400 }; 401 402 }; 403 404 config = { 405 name = mkDefault name; 406 setLoginUid = mkDefault cfg.startSession; 407 limits = mkDefault config.security.pam.loginLimits; 408 409 # !!! TODO: move the LDAP stuff to the LDAP module, and the 410 # Samba stuff to the Samba module. This requires that the PAM 411 # module provides the right hooks. 412 text = mkDefault 413 ( 414 '' 415 # Account management. 416 account required pam_unix.so 417 '' + 418 optionalString use_ldap '' 419 account sufficient ${pam_ldap}/lib/security/pam_ldap.so 420 '' + 421 optionalString (config.services.sssd.enable && cfg.sssdStrictAccess==false) '' 422 account sufficient ${pkgs.sssd}/lib/security/pam_sss.so 423 '' + 424 optionalString (config.services.sssd.enable && cfg.sssdStrictAccess) '' 425 account [default=bad success=ok user_unknown=ignore] ${pkgs.sssd}/lib/security/pam_sss.so 426 '' + 427 optionalString config.krb5.enable '' 428 account sufficient ${pam_krb5}/lib/security/pam_krb5.so 429 '' + 430 optionalString cfg.googleOsLoginAccountVerification '' 431 account [success=ok ignore=ignore default=die] ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_login.so 432 account [success=ok default=ignore] ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_admin.so 433 '' + 434 '' 435 436 # Authentication management. 437 '' + 438 optionalString cfg.googleOsLoginAuthentication '' 439 auth [success=done perm_denied=bad default=ignore] ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_login.so 440 '' + 441 optionalString cfg.rootOK '' 442 auth sufficient pam_rootok.so 443 '' + 444 optionalString cfg.requireWheel '' 445 auth required pam_wheel.so use_uid 446 '' + 447 optionalString cfg.logFailures '' 448 auth required pam_faillock.so 449 '' + 450 optionalString (config.security.pam.enableSSHAgentAuth && cfg.sshAgentAuth) '' 451 auth sufficient ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so file=${lib.concatStringsSep ":" config.services.openssh.authorizedKeysFiles} 452 '' + 453 (let p11 = config.security.pam.p11; in optionalString cfg.p11Auth '' 454 auth ${p11.control} ${pkgs.pam_p11}/lib/security/pam_p11.so ${pkgs.opensc}/lib/opensc-pkcs11.so 455 '') + 456 (let u2f = config.security.pam.u2f; in optionalString cfg.u2fAuth '' 457 auth ${u2f.control} ${pkgs.pam_u2f}/lib/security/pam_u2f.so ${optionalString u2f.debug "debug"} ${optionalString (u2f.authFile != null) "authfile=${u2f.authFile}"} ${optionalString u2f.interactive "interactive"} ${optionalString u2f.cue "cue"} ${optionalString (u2f.appId != null) "appid=${u2f.appId}"} 458 '') + 459 optionalString cfg.usbAuth '' 460 auth sufficient ${pkgs.pam_usb}/lib/security/pam_usb.so 461 '' + 462 (let oath = config.security.pam.oath; in optionalString cfg.oathAuth '' 463 auth requisite ${pkgs.oathToolkit}/lib/security/pam_oath.so window=${toString oath.window} usersfile=${toString oath.usersFile} digits=${toString oath.digits} 464 '') + 465 (let yubi = config.security.pam.yubico; in optionalString cfg.yubicoAuth '' 466 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"} 467 '') + 468 optionalString cfg.fprintAuth '' 469 auth sufficient ${pkgs.fprintd}/lib/security/pam_fprintd.so 470 '' + 471 # Modules in this block require having the password set in PAM_AUTHTOK. 472 # pam_unix is marked as 'sufficient' on NixOS which means nothing will run 473 # after it succeeds. Certain modules need to run after pam_unix 474 # prompts the user for password so we run it once with 'required' at an 475 # earlier point and it will run again with 'sufficient' further down. 476 # We use try_first_pass the second time to avoid prompting password twice 477 (optionalString (cfg.unixAuth && 478 (config.security.pam.enableEcryptfs 479 || cfg.pamMount 480 || cfg.enableKwallet 481 || cfg.enableGnomeKeyring 482 || cfg.googleAuthenticator.enable 483 || cfg.gnupg.enable 484 || cfg.duoSecurity.enable)) 485 ( 486 '' 487 auth required pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} ${optionalString cfg.nodelay "nodelay"} likeauth 488 '' + 489 optionalString config.security.pam.enableEcryptfs '' 490 auth optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap 491 '' + 492 optionalString cfg.pamMount '' 493 auth optional ${pkgs.pam_mount}/lib/security/pam_mount.so disable_interactive 494 '' + 495 optionalString cfg.enableKwallet '' 496 auth optional ${pkgs.plasma5Packages.kwallet-pam}/lib/security/pam_kwallet5.so kwalletd=${pkgs.plasma5Packages.kwallet.bin}/bin/kwalletd5 497 '' + 498 optionalString cfg.enableGnomeKeyring '' 499 auth optional ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so 500 '' + 501 optionalString cfg.gnupg.enable '' 502 auth optional ${pkgs.pam_gnupg}/lib/security/pam_gnupg.so ${optionalString cfg.gnupg.storeOnly " store-only"} 503 '' + 504 optionalString cfg.googleAuthenticator.enable '' 505 auth required ${pkgs.googleAuthenticator}/lib/security/pam_google_authenticator.so no_increment_hotp 506 '' + 507 optionalString cfg.duoSecurity.enable '' 508 auth required ${pkgs.duo-unix}/lib/security/pam_duo.so 509 '' 510 )) + 511 optionalString cfg.unixAuth '' 512 auth sufficient pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} ${optionalString cfg.nodelay "nodelay"} likeauth try_first_pass 513 '' + 514 optionalString cfg.otpwAuth '' 515 auth sufficient ${pkgs.otpw}/lib/security/pam_otpw.so 516 '' + 517 optionalString use_ldap '' 518 auth sufficient ${pam_ldap}/lib/security/pam_ldap.so use_first_pass 519 '' + 520 optionalString config.services.sssd.enable '' 521 auth sufficient ${pkgs.sssd}/lib/security/pam_sss.so use_first_pass 522 '' + 523 optionalString config.krb5.enable '' 524 auth [default=ignore success=1 service_err=reset] ${pam_krb5}/lib/security/pam_krb5.so use_first_pass 525 auth [default=die success=done] ${pam_ccreds}/lib/security/pam_ccreds.so action=validate use_first_pass 526 auth sufficient ${pam_ccreds}/lib/security/pam_ccreds.so action=store use_first_pass 527 '' + 528 '' 529 auth required pam_deny.so 530 531 # Password management. 532 password sufficient pam_unix.so nullok sha512 533 '' + 534 optionalString config.security.pam.enableEcryptfs '' 535 password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so 536 '' + 537 optionalString cfg.pamMount '' 538 password optional ${pkgs.pam_mount}/lib/security/pam_mount.so 539 '' + 540 optionalString use_ldap '' 541 password sufficient ${pam_ldap}/lib/security/pam_ldap.so 542 '' + 543 optionalString config.services.sssd.enable '' 544 password sufficient ${pkgs.sssd}/lib/security/pam_sss.so use_authtok 545 '' + 546 optionalString config.krb5.enable '' 547 password sufficient ${pam_krb5}/lib/security/pam_krb5.so use_first_pass 548 '' + 549 optionalString cfg.enableGnomeKeyring '' 550 password optional ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so use_authtok 551 '' + 552 '' 553 554 # Session management. 555 '' + 556 optionalString cfg.setEnvironment '' 557 session required pam_env.so conffile=/etc/pam/environment readenv=0 558 '' + 559 '' 560 session required pam_unix.so 561 '' + 562 optionalString cfg.setLoginUid '' 563 session ${if config.boot.isContainer then "optional" else "required"} pam_loginuid.so 564 '' + 565 optionalString cfg.ttyAudit.enable '' 566 session required ${pkgs.pam}/lib/security/pam_tty_audit.so 567 open_only=${toString cfg.ttyAudit.openOnly} 568 ${optionalString (cfg.ttyAudit.enablePattern != null) "enable=${cfg.ttyAudit.enablePattern}"} 569 ${optionalString (cfg.ttyAudit.disablePattern != null) "disable=${cfg.ttyAudit.disablePattern}"} 570 '' + 571 optionalString cfg.makeHomeDir '' 572 session required ${pkgs.pam}/lib/security/pam_mkhomedir.so silent skel=${config.security.pam.makeHomeDir.skelDirectory} umask=0077 573 '' + 574 optionalString cfg.updateWtmp '' 575 session required ${pkgs.pam}/lib/security/pam_lastlog.so silent 576 '' + 577 optionalString config.security.pam.enableEcryptfs '' 578 session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so 579 '' + 580 optionalString cfg.pamMount '' 581 session optional ${pkgs.pam_mount}/lib/security/pam_mount.so disable_interactive 582 '' + 583 optionalString use_ldap '' 584 session optional ${pam_ldap}/lib/security/pam_ldap.so 585 '' + 586 optionalString config.services.sssd.enable '' 587 session optional ${pkgs.sssd}/lib/security/pam_sss.so 588 '' + 589 optionalString config.krb5.enable '' 590 session optional ${pam_krb5}/lib/security/pam_krb5.so 591 '' + 592 optionalString cfg.otpwAuth '' 593 session optional ${pkgs.otpw}/lib/security/pam_otpw.so 594 '' + 595 optionalString cfg.startSession '' 596 session optional ${pkgs.systemd}/lib/security/pam_systemd.so 597 '' + 598 optionalString cfg.forwardXAuth '' 599 session optional pam_xauth.so xauthpath=${pkgs.xorg.xauth}/bin/xauth systemuser=99 600 '' + 601 optionalString (cfg.limits != []) '' 602 session required ${pkgs.pam}/lib/security/pam_limits.so conf=${makeLimitsConf cfg.limits} 603 '' + 604 optionalString (cfg.showMotd && config.users.motd != null) '' 605 session optional ${pkgs.pam}/lib/security/pam_motd.so motd=${motd} 606 '' + 607 optionalString (cfg.enableAppArmor && config.security.apparmor.enable) '' 608 session optional ${pkgs.apparmor-pam}/lib/security/pam_apparmor.so order=user,group,default debug 609 '' + 610 optionalString (cfg.enableKwallet) '' 611 session optional ${pkgs.plasma5Packages.kwallet-pam}/lib/security/pam_kwallet5.so kwalletd=${pkgs.plasma5Packages.kwallet.bin}/bin/kwalletd5 612 '' + 613 optionalString (cfg.enableGnomeKeyring) '' 614 session optional ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so auto_start 615 '' + 616 optionalString cfg.gnupg.enable '' 617 session optional ${pkgs.pam_gnupg}/lib/security/pam_gnupg.so ${optionalString cfg.gnupg.noAutostart " no-autostart"} 618 '' + 619 optionalString (config.virtualisation.lxc.lxcfs.enable) '' 620 session optional ${pkgs.lxc}/lib/security/pam_cgfs.so -c all 621 '' 622 ); 623 }; 624 625 }; 626 627 628 inherit (pkgs) pam_krb5 pam_ccreds; 629 630 use_ldap = (config.users.ldap.enable && config.users.ldap.loginPam); 631 pam_ldap = if config.users.ldap.daemon.enable then pkgs.nss_pam_ldapd else pkgs.pam_ldap; 632 633 # Create a limits.conf(5) file. 634 makeLimitsConf = limits: 635 pkgs.writeText "limits.conf" 636 (concatMapStrings ({ domain, type, item, value }: 637 "${domain} ${type} ${item} ${toString value}\n") 638 limits); 639 640 motd = pkgs.writeText "motd" config.users.motd; 641 642 makePAMService = name: service: 643 { name = "pam.d/${name}"; 644 value.source = pkgs.writeText "${name}.pam" service.text; 645 }; 646 647in 648 649{ 650 651 imports = [ 652 (mkRenamedOptionModule [ "security" "pam" "enableU2F" ] [ "security" "pam" "u2f" "enable" ]) 653 ]; 654 655 ###### interface 656 657 options = { 658 659 security.pam.loginLimits = mkOption { 660 default = []; 661 example = 662 [ { domain = "ftp"; 663 type = "hard"; 664 item = "nproc"; 665 value = "0"; 666 } 667 { domain = "@student"; 668 type = "-"; 669 item = "maxlogins"; 670 value = "4"; 671 } 672 ]; 673 674 description = 675 '' Define resource limits that should apply to users or groups. 676 Each item in the list should be an attribute set with a 677 <varname>domain</varname>, <varname>type</varname>, 678 <varname>item</varname>, and <varname>value</varname> 679 attribute. The syntax and semantics of these attributes 680 must be that described in the limits.conf(5) man page. 681 682 Note that these limits do not apply to systemd services, 683 whose limits can be changed via <option>systemd.extraConfig</option> 684 instead. 685 ''; 686 }; 687 688 security.pam.services = mkOption { 689 default = {}; 690 type = with types; attrsOf (submodule pamOpts); 691 description = 692 '' 693 This option defines the PAM services. A service typically 694 corresponds to a program that uses PAM, 695 e.g. <command>login</command> or <command>passwd</command>. 696 Each attribute of this set defines a PAM service, with the attribute name 697 defining the name of the service. 698 ''; 699 }; 700 701 security.pam.makeHomeDir.skelDirectory = mkOption { 702 type = types.str; 703 default = "/var/empty"; 704 example = "/etc/skel"; 705 description = '' 706 Path to skeleton directory whose contents are copied to home 707 directories newly created by <literal>pam_mkhomedir</literal>. 708 ''; 709 }; 710 711 security.pam.enableSSHAgentAuth = mkOption { 712 type = types.bool; 713 default = false; 714 description = 715 '' 716 Enable sudo logins if the user's SSH agent provides a key 717 present in <filename>~/.ssh/authorized_keys</filename>. 718 This allows machines to exclusively use SSH keys instead of 719 passwords. 720 ''; 721 }; 722 723 security.pam.enableOTPW = mkEnableOption "the OTPW (one-time password) PAM module"; 724 725 security.pam.p11 = { 726 enable = mkOption { 727 default = false; 728 type = types.bool; 729 description = '' 730 Enables P11 PAM (<literal>pam_p11</literal>) module. 731 732 If set, users can log in with SSH keys and PKCS#11 tokens. 733 734 More information can be found <link 735 xlink:href="https://github.com/OpenSC/pam_p11">here</link>. 736 ''; 737 }; 738 739 control = mkOption { 740 default = "sufficient"; 741 type = types.enum [ "required" "requisite" "sufficient" "optional" ]; 742 description = '' 743 This option sets pam "control". 744 If you want to have multi factor authentication, use "required". 745 If you want to use the PKCS#11 device instead of the regular password, 746 use "sufficient". 747 748 Read 749 <citerefentry> 750 <refentrytitle>pam.conf</refentrytitle> 751 <manvolnum>5</manvolnum> 752 </citerefentry> 753 for better understanding of this option. 754 ''; 755 }; 756 }; 757 758 security.pam.u2f = { 759 enable = mkOption { 760 default = false; 761 type = types.bool; 762 description = '' 763 Enables U2F PAM (<literal>pam-u2f</literal>) module. 764 765 If set, users listed in 766 <filename>$XDG_CONFIG_HOME/Yubico/u2f_keys</filename> (or 767 <filename>$HOME/.config/Yubico/u2f_keys</filename> if XDG variable is 768 not set) are able to log in with the associated U2F key. The path can 769 be changed using <option>security.pam.u2f.authFile</option> option. 770 771 File format is: 772 <literal>username:first_keyHandle,first_public_key: second_keyHandle,second_public_key</literal> 773 This file can be generated using <command>pamu2fcfg</command> command. 774 775 More information can be found <link 776 xlink:href="https://developers.yubico.com/pam-u2f/">here</link>. 777 ''; 778 }; 779 780 authFile = mkOption { 781 default = null; 782 type = with types; nullOr path; 783 description = '' 784 By default <literal>pam-u2f</literal> module reads the keys from 785 <filename>$XDG_CONFIG_HOME/Yubico/u2f_keys</filename> (or 786 <filename>$HOME/.config/Yubico/u2f_keys</filename> if XDG variable is 787 not set). 788 789 If you want to change auth file locations or centralize database (for 790 example use <filename>/etc/u2f-mappings</filename>) you can set this 791 option. 792 793 File format is: 794 <literal>username:first_keyHandle,first_public_key: second_keyHandle,second_public_key</literal> 795 This file can be generated using <command>pamu2fcfg</command> command. 796 797 More information can be found <link 798 xlink:href="https://developers.yubico.com/pam-u2f/">here</link>. 799 ''; 800 }; 801 802 appId = mkOption { 803 default = null; 804 type = with types; nullOr str; 805 description = '' 806 By default <literal>pam-u2f</literal> module sets the application 807 ID to <literal>pam://$HOSTNAME</literal>. 808 809 When using <command>pamu2fcfg</command>, you can specify your 810 application ID with the <literal>-i</literal> flag. 811 812 More information can be found <link 813 xlink:href="https://developers.yubico.com/pam-u2f/Manuals/pam_u2f.8.html"> 814 here</link> 815 ''; 816 }; 817 818 control = mkOption { 819 default = "sufficient"; 820 type = types.enum [ "required" "requisite" "sufficient" "optional" ]; 821 description = '' 822 This option sets pam "control". 823 If you want to have multi factor authentication, use "required". 824 If you want to use U2F device instead of regular password, use "sufficient". 825 826 Read 827 <citerefentry> 828 <refentrytitle>pam.conf</refentrytitle> 829 <manvolnum>5</manvolnum> 830 </citerefentry> 831 for better understanding of this option. 832 ''; 833 }; 834 835 debug = mkOption { 836 default = false; 837 type = types.bool; 838 description = '' 839 Debug output to stderr. 840 ''; 841 }; 842 843 interactive = mkOption { 844 default = false; 845 type = types.bool; 846 description = '' 847 Set to prompt a message and wait before testing the presence of a U2F device. 848 Recommended if your device doesnt have a tactile trigger. 849 ''; 850 }; 851 852 cue = mkOption { 853 default = false; 854 type = types.bool; 855 description = '' 856 By default <literal>pam-u2f</literal> module does not inform user 857 that he needs to use the u2f device, it just waits without a prompt. 858 859 If you set this option to <literal>true</literal>, 860 <literal>cue</literal> option is added to <literal>pam-u2f</literal> 861 module and reminder message will be displayed. 862 ''; 863 }; 864 }; 865 866 security.pam.yubico = { 867 enable = mkOption { 868 default = false; 869 type = types.bool; 870 description = '' 871 Enables Yubico PAM (<literal>yubico-pam</literal>) module. 872 873 If set, users listed in 874 <filename>~/.yubico/authorized_yubikeys</filename> 875 are able to log in with the associated Yubikey tokens. 876 877 The file must have only one line: 878 <literal>username:yubikey_token_id1:yubikey_token_id2</literal> 879 More information can be found <link 880 xlink:href="https://developers.yubico.com/yubico-pam/">here</link>. 881 ''; 882 }; 883 control = mkOption { 884 default = "sufficient"; 885 type = types.enum [ "required" "requisite" "sufficient" "optional" ]; 886 description = '' 887 This option sets pam "control". 888 If you want to have multi factor authentication, use "required". 889 If you want to use Yubikey instead of regular password, use "sufficient". 890 891 Read 892 <citerefentry> 893 <refentrytitle>pam.conf</refentrytitle> 894 <manvolnum>5</manvolnum> 895 </citerefentry> 896 for better understanding of this option. 897 ''; 898 }; 899 id = mkOption { 900 example = "42"; 901 type = types.str; 902 description = "client id"; 903 }; 904 905 debug = mkOption { 906 default = false; 907 type = types.bool; 908 description = '' 909 Debug output to stderr. 910 ''; 911 }; 912 mode = mkOption { 913 default = "client"; 914 type = types.enum [ "client" "challenge-response" ]; 915 description = '' 916 Mode of operation. 917 918 Use "client" for online validation with a YubiKey validation service such as 919 the YubiCloud. 920 921 Use "challenge-response" for offline validation using YubiKeys with HMAC-SHA-1 922 Challenge-Response configurations. See the man-page ykpamcfg(1) for further 923 details on how to configure offline Challenge-Response validation. 924 925 More information can be found <link 926 xlink:href="https://developers.yubico.com/yubico-pam/Authentication_Using_Challenge-Response.html">here</link>. 927 ''; 928 }; 929 challengeResponsePath = mkOption { 930 default = null; 931 type = types.nullOr types.path; 932 description = '' 933 If not null, set the path used by yubico pam module where the challenge expected response is stored. 934 935 More information can be found <link 936 xlink:href="https://developers.yubico.com/yubico-pam/Authentication_Using_Challenge-Response.html">here</link>. 937 ''; 938 }; 939 }; 940 941 security.pam.enableEcryptfs = mkEnableOption "eCryptfs PAM module (mounting ecryptfs home directory on login)"; 942 943 users.motd = mkOption { 944 default = null; 945 example = "Today is Sweetmorn, the 4th day of The Aftermath in the YOLD 3178."; 946 type = types.nullOr types.lines; 947 description = "Message of the day shown to users when they log in."; 948 }; 949 950 }; 951 952 953 ###### implementation 954 955 config = { 956 957 environment.systemPackages = 958 # Include the PAM modules in the system path mostly for the manpages. 959 [ pkgs.pam ] 960 ++ optional config.users.ldap.enable pam_ldap 961 ++ optional config.services.sssd.enable pkgs.sssd 962 ++ optionals config.krb5.enable [pam_krb5 pam_ccreds] 963 ++ optionals config.security.pam.enableOTPW [ pkgs.otpw ] 964 ++ optionals config.security.pam.oath.enable [ pkgs.oathToolkit ] 965 ++ optionals config.security.pam.p11.enable [ pkgs.pam_p11 ] 966 ++ optionals config.security.pam.u2f.enable [ pkgs.pam_u2f ]; 967 968 boot.supportedFilesystems = optionals config.security.pam.enableEcryptfs [ "ecryptfs" ]; 969 970 security.wrappers = { 971 unix_chkpwd = { 972 setuid = true; 973 owner = "root"; 974 group = "root"; 975 source = "${pkgs.pam}/sbin/unix_chkpwd.orig"; 976 }; 977 }; 978 979 environment.etc = mapAttrs' makePAMService config.security.pam.services; 980 981 security.pam.services = 982 { other.text = 983 '' 984 auth required pam_warn.so 985 auth required pam_deny.so 986 account required pam_warn.so 987 account required pam_deny.so 988 password required pam_warn.so 989 password required pam_deny.so 990 session required pam_warn.so 991 session required pam_deny.so 992 ''; 993 994 # Most of these should be moved to specific modules. 995 i3lock = {}; 996 i3lock-color = {}; 997 vlock = {}; 998 xlock = {}; 999 xscreensaver = {}; 1000 1001 runuser = { rootOK = true; unixAuth = false; setEnvironment = false; }; 1002 1003 /* FIXME: should runuser -l start a systemd session? Currently 1004 it complains "Cannot create session: Already running in a 1005 session". */ 1006 runuser-l = { rootOK = true; unixAuth = false; }; 1007 }; 1008 1009 security.apparmor.includes."abstractions/pam" = let 1010 isEnabled = test: fold or false (map test (attrValues config.security.pam.services)); 1011 in 1012 lib.concatMapStringsSep "\n" 1013 (name: "r ${config.environment.etc."pam.d/${name}".source},") 1014 (attrNames config.security.pam.services) + 1015 '' 1016 mr ${getLib pkgs.pam}/lib/security/pam_filter/*, 1017 mr ${getLib pkgs.pam}/lib/security/pam_*.so, 1018 r ${getLib pkgs.pam}/lib/security/, 1019 '' + 1020 optionalString use_ldap '' 1021 mr ${pam_ldap}/lib/security/pam_ldap.so, 1022 '' + 1023 optionalString config.services.sssd.enable '' 1024 mr ${pkgs.sssd}/lib/security/pam_sss.so, 1025 '' + 1026 optionalString config.krb5.enable '' 1027 mr ${pam_krb5}/lib/security/pam_krb5.so, 1028 mr ${pam_ccreds}/lib/security/pam_ccreds.so, 1029 '' + 1030 optionalString (isEnabled (cfg: cfg.googleOsLoginAccountVerification)) '' 1031 mr ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_login.so, 1032 mr ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_admin.so, 1033 '' + 1034 optionalString (isEnabled (cfg: cfg.googleOsLoginAuthentication)) '' 1035 mr ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_login.so, 1036 '' + 1037 optionalString (config.security.pam.enableSSHAgentAuth 1038 && isEnabled (cfg: cfg.sshAgentAuth)) '' 1039 mr ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so, 1040 '' + 1041 optionalString (isEnabled (cfg: cfg.fprintAuth)) '' 1042 mr ${pkgs.fprintd}/lib/security/pam_fprintd.so, 1043 '' + 1044 optionalString (isEnabled (cfg: cfg.u2fAuth)) '' 1045 mr ${pkgs.pam_u2f}/lib/security/pam_u2f.so, 1046 '' + 1047 optionalString (isEnabled (cfg: cfg.usbAuth)) '' 1048 mr ${pkgs.pam_usb}/lib/security/pam_usb.so, 1049 '' + 1050 optionalString (isEnabled (cfg: cfg.oathAuth)) '' 1051 "mr ${pkgs.oathToolkit}/lib/security/pam_oath.so, 1052 '' + 1053 optionalString (isEnabled (cfg: cfg.yubicoAuth)) '' 1054 mr ${pkgs.yubico-pam}/lib/security/pam_yubico.so, 1055 '' + 1056 optionalString (isEnabled (cfg: cfg.duoSecurity.enable)) '' 1057 mr ${pkgs.duo-unix}/lib/security/pam_duo.so, 1058 '' + 1059 optionalString (isEnabled (cfg: cfg.otpwAuth)) '' 1060 mr ${pkgs.otpw}/lib/security/pam_otpw.so, 1061 '' + 1062 optionalString config.security.pam.enableEcryptfs '' 1063 mr ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so, 1064 '' + 1065 optionalString (isEnabled (cfg: cfg.pamMount)) '' 1066 mr ${pkgs.pam_mount}/lib/security/pam_mount.so, 1067 '' + 1068 optionalString (isEnabled (cfg: cfg.enableGnomeKeyring)) '' 1069 mr ${pkgs.gnome3.gnome-keyring}/lib/security/pam_gnome_keyring.so, 1070 '' + 1071 optionalString (isEnabled (cfg: cfg.startSession)) '' 1072 mr ${pkgs.systemd}/lib/security/pam_systemd.so, 1073 '' + 1074 optionalString (isEnabled (cfg: cfg.enableAppArmor) 1075 && config.security.apparmor.enable) '' 1076 mr ${pkgs.apparmor-pam}/lib/security/pam_apparmor.so, 1077 '' + 1078 optionalString (isEnabled (cfg: cfg.enableKwallet)) '' 1079 mr ${pkgs.plasma5Packages.kwallet-pam}/lib/security/pam_kwallet5.so, 1080 '' + 1081 optionalString config.virtualisation.lxc.lxcfs.enable '' 1082 mr ${pkgs.lxc}/lib/security/pam_cgfs.so 1083 ''; 1084 }; 1085 1086}