From a46ea51ca3b5c57db08978a5bde3910bccada760 Mon Sep 17 00:00:00 2001 From: nicoo Date: Fri, 29 Dec 2023 21:13:02 +0000 Subject: [PATCH 1/5] nixos/pam: Rename option `enableSSHAgentAuth` to `sshAgentAuth.enable` --- nixos/modules/security/pam.nix | 20 ++++++++------------ nixos/tests/ssh-agent-auth.nix | 2 +- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index c99615d5a636..a361464b9438 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -654,7 +654,7 @@ let { name = "mysql"; enable = cfg.mysqlAuth; control = "sufficient"; modulePath = "${pkgs.pam_mysql}/lib/security/pam_mysql.so"; settings = { config_file = "/etc/security/pam_mysql.conf"; }; } - { name = "ssh_agent_auth"; enable = config.security.pam.enableSSHAgentAuth && cfg.sshAgentAuth; control = "sufficient"; modulePath = "${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so"; settings = { + { name = "ssh_agent_auth"; enable = config.security.pam.sshAgentAuth.enable && cfg.sshAgentAuth; control = "sufficient"; modulePath = "${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so"; settings = { file = lib.concatStringsSep ":" config.services.openssh.authorizedKeysFiles; }; } (let p11 = config.security.pam.p11; in { name = "p11"; enable = cfg.p11Auth; control = p11.control; modulePath = "${pkgs.pam_p11}/lib/security/pam_p11.so"; args = [ @@ -943,7 +943,7 @@ let value.source = pkgs.writeText "${name}.pam" service.text; }; - optionalSudoConfigForSSHAgentAuth = optionalString config.security.pam.enableSSHAgentAuth '' + optionalSudoConfigForSSHAgentAuth = optionalString config.security.pam.sshAgentAuth.enable '' # Keep SSH_AUTH_SOCK so that pam_ssh_agent_auth.so can do its magic. Defaults env_keep+=SSH_AUTH_SOCK ''; @@ -956,6 +956,7 @@ in imports = [ (mkRenamedOptionModule [ "security" "pam" "enableU2F" ] [ "security" "pam" "u2f" "enable" ]) + (mkRenamedOptionModule [ "security" "pam" "enableSSHAgentAuth" ] [ "security" "pam" "sshAgentAuth" "enable" ]) ]; ###### interface @@ -1025,16 +1026,11 @@ in ''; }; - security.pam.enableSSHAgentAuth = mkOption { - type = types.bool; - default = false; - description = - lib.mdDoc '' - Enable sudo logins if the user's SSH agent provides a key - present in {file}`~/.ssh/authorized_keys`. - This allows machines to exclusively use SSH keys instead of - passwords. - ''; + security.pam.sshAgentAuth = { + enable = mkEnableOption '' + authenticating using a signature performed by the ssh-agent. + This allows using SSH keys exclusively, instead of passwords, for instance on remote machines + ''; }; security.pam.enableOTPW = mkEnableOption (lib.mdDoc "the OTPW (one-time password) PAM module"); diff --git a/nixos/tests/ssh-agent-auth.nix b/nixos/tests/ssh-agent-auth.nix index 2274e463ce95..f4a282502cf3 100644 --- a/nixos/tests/ssh-agent-auth.nix +++ b/nixos/tests/ssh-agent-auth.nix @@ -15,7 +15,7 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: foo.isNormalUser = true; }; - security.pam.enableSSHAgentAuth = true; + security.pam.sshAgentAuth.enable = true; security.${lib.replaceStrings [ "_" ] [ "-" ] n} = { enable = true; wheelNeedsPassword = true; # We are checking `pam_ssh_agent_auth(8)` works for a sudoer From 822c0a86bd3b3c877177e2284a5cfc9222b365cc Mon Sep 17 00:00:00 2001 From: nicoo Date: Fri, 29 Dec 2023 21:30:56 +0000 Subject: [PATCH 2/5] nixos/pam: Add `sshAgentAuth.authorizedKeysFiles` option --- nixos/modules/security/pam.nix | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index a361464b9438..38dcbc2b0016 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -655,7 +655,7 @@ let config_file = "/etc/security/pam_mysql.conf"; }; } { name = "ssh_agent_auth"; enable = config.security.pam.sshAgentAuth.enable && cfg.sshAgentAuth; control = "sufficient"; modulePath = "${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so"; settings = { - file = lib.concatStringsSep ":" config.services.openssh.authorizedKeysFiles; + file = lib.concatStringsSep ":" config.security.pam.sshAgentAuth.authorizedKeysFiles; }; } (let p11 = config.security.pam.p11; in { name = "p11"; enable = cfg.p11Auth; control = p11.control; modulePath = "${pkgs.pam_p11}/lib/security/pam_p11.so"; args = [ "${pkgs.opensc}/lib/opensc-pkcs11.so" @@ -1031,6 +1031,29 @@ in authenticating using a signature performed by the ssh-agent. This allows using SSH keys exclusively, instead of passwords, for instance on remote machines ''; + + authorizedKeysFiles = mkOption { + type = with types; listOf str; + description = '' + A list of paths to files in OpenSSH's `authorized_keys` format, containing + the keys that will be trusted by the `pam_ssh_agent_auth` module. + + The following patterns are expanded when interpreting the path: + - `%f` and `%H` respectively expand to the fully-qualified and short hostname ; + - `%u` expands to the username ; + - `~` or `%h` expands to the user's home directory. + + ::: {.note} + Specifying user-writeable files here result in an insecure configuration: a malicious process + can then edit such an authorized_keys file and bypass the ssh-agent-based authentication. + + See [issue #31611](https://github.com/NixOS/nixpkgs/issues/31611) + ::: + ''; + example = [ "/etc/ssh/authorized_keys.d/%u" ]; + default = config.services.openssh.authorizedKeysFiles; + defaultText = literalExpression "config.services.openssh.authorizedKeysFiles"; + }; }; security.pam.enableOTPW = mkEnableOption (lib.mdDoc "the OTPW (one-time password) PAM module"); From 9ed1423dcf61aa33e0192dd396b216cd02bd505c Mon Sep 17 00:00:00 2001 From: nicoo Date: Fri, 29 Dec 2023 21:35:46 +0000 Subject: [PATCH 3/5] nixos/pam: Warn on insecure `sshAgentAuth` configurations --- nixos/modules/security/pam.nix | 10 ++++++++++ nixos/tests/ssh-agent-auth.nix | 6 +++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index 38dcbc2b0016..95f4de3fe3a0 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -1477,6 +1477,16 @@ in } ]; + warnings = optional + (with lib; with config.security.pam.sshAgentAuth; + enable && any (s: hasPrefix "%h" s || hasPrefix "~" s) authorizedKeysFiles) + ''config.security.pam.sshAgentAuth.authorizedKeysFiles contains files in the user's home directory. + + Specifying user-writeable files there result in an insecure configuration: + a malicious process can then edit such an authorized_keys file and bypass the ssh-agent-based authentication. + See https://github.com/NixOS/nixpkgs/issues/31611 + ''; + environment.systemPackages = # Include the PAM modules in the system path mostly for the manpages. [ pkgs.pam ] diff --git a/nixos/tests/ssh-agent-auth.nix b/nixos/tests/ssh-agent-auth.nix index f4a282502cf3..fee40afd6153 100644 --- a/nixos/tests/ssh-agent-auth.nix +++ b/nixos/tests/ssh-agent-auth.nix @@ -15,7 +15,11 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: foo.isNormalUser = true; }; - security.pam.sshAgentAuth.enable = true; + security.pam.sshAgentAuth = { + # Must be specified, as nixpkgs CI expects everything to eval without warning + authorizedKeysFiles = [ "/etc/ssh/authorized_keys.d/%u" ]; + enable = true; + }; security.${lib.replaceStrings [ "_" ] [ "-" ] n} = { enable = true; wheelNeedsPassword = true; # We are checking `pam_ssh_agent_auth(8)` works for a sudoer From b917ee427a9536d352402995641430083f2acf6d Mon Sep 17 00:00:00 2001 From: nicoo Date: Fri, 29 Dec 2023 22:09:21 +0000 Subject: [PATCH 4/5] nixos/doc: Add release note for `pam.sshAgentAuth` --- nixos/doc/manual/release-notes/rl-2405.section.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nixos/doc/manual/release-notes/rl-2405.section.md b/nixos/doc/manual/release-notes/rl-2405.section.md index b347992031d9..b77d76dba8a2 100644 --- a/nixos/doc/manual/release-notes/rl-2405.section.md +++ b/nixos/doc/manual/release-notes/rl-2405.section.md @@ -132,6 +132,10 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m - The source of the `mockgen` package has changed to the [go.uber.org/mock](https://github.com/uber-go/mock) fork because [the original repository is no longer maintained](https://github.com/golang/mock#gomock). +- `security.pam.enableSSHAgentAuth` was renamed to `security.pam.sshAgentAuth.enable` and an `authorizedKeysFiles` + option was added, to control which `authorized_keys` files are trusted. It defaults to the previous behaviour, + **which is insecure**: see [#31611](https://github.com/NixOS/nixpkgs/issues/31611). + - [](#opt-boot.kernel.sysctl._net.core.wmem_max_) changed from a string to an integer because of the addition of a custom merge option (taking the highest value defined to avoid conflicts between 2 services trying to set that value), just as [](#opt-boot.kernel.sysctl._net.core.rmem_max_) since 22.11. - `services.zfs.zed.enableMail` now uses the global `sendmail` wrapper defined by an email module From 2eac5106f1f9628025e9b1bf269f25642ff9690c Mon Sep 17 00:00:00 2001 From: nicoo Date: Mon, 1 Jan 2024 13:49:23 +0000 Subject: [PATCH 5/5] nixos/sudo: Remove unused `enableSSHAgentAuth` let-binding --- nixos/modules/security/sudo.nix | 2 -- 1 file changed, 2 deletions(-) diff --git a/nixos/modules/security/sudo.nix b/nixos/modules/security/sudo.nix index 3dd5d2e525d9..6aa9445eab65 100644 --- a/nixos/modules/security/sudo.nix +++ b/nixos/modules/security/sudo.nix @@ -6,8 +6,6 @@ let cfg = config.security.sudo; - inherit (config.security.pam) enableSSHAgentAuth; - toUserString = user: if (isInt user) then "#${toString user}" else "${user}"; toGroupString = group: if (isInt group) then "%#${toString group}" else "%${group}";