From 257b5c199490aa073ab60c1d22d213025661dd44 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Wed, 31 May 2023 22:22:02 +1000 Subject: [PATCH] ssh: fix public keys in home directory not working Added `services.openssh.authorizedKeysFiles` option from NixOS. --- modules/programs/ssh/default.nix | 51 +++++++++++++++++++++++++------- tests/programs-ssh.nix | 2 +- 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/modules/programs/ssh/default.nix b/modules/programs/ssh/default.nix index f1dde9a..a230dde 100644 --- a/modules/programs/ssh/default.nix +++ b/modules/programs/ssh/default.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, ... }: +{ config, lib, ... }: with lib; @@ -79,6 +79,7 @@ let }; }; + authKeysFiles = let mkAuthKeyFile = u: nameValuePair "ssh/authorized_keys.d/${u.name}" { copy = true; @@ -91,22 +92,33 @@ let length u.openssh.authorizedKeys.keys != 0 || length u.openssh.authorizedKeys.keyFiles != 0 )); in listToAttrs (map mkAuthKeyFile usersWithKeys); - authKeysConfiguration = - { - "ssh/sshd_config.d/101-authorized-keys.conf" = { - copy = true; - text = "AuthorizedKeysFile /etc/ssh/authorized_keys.d/%u\n"; - }; - }; + + oldAuthorizedKeysHash = "5a5dc1e20e8abc162ad1cc0259bfd1dbb77981013d87625f97d9bd215175fc0a"; in { options = { - + users.users = mkOption { type = with types; attrsOf (submodule userOptions); }; + services.openssh.authorizedKeysFiles = mkOption { + type = types.listOf types.str; + default = []; + description = lib.mdDoc '' + Specify the rules for which files to read on the host. + + This is an advanced option. If you're looking to configure user + keys, you can generally use [](#opt-users.users._name_.openssh.authorizedKeys.keys) + or [](#opt-users.users._name_.openssh.authorizedKeys.keyFiles). + + These are paths relative to the host root file system or home + directories and they are subject to certain token expansion rules. + See AuthorizedKeysFile in man sshd_config for details. + ''; + }; + programs.ssh.knownHosts = mkOption { default = {}; type = types.attrsOf (types.submodule host); @@ -135,13 +147,30 @@ in (data.publicKey != null && data.publicKeyFile == null); message = "knownHost ${name} must contain either a publicKey or publicKeyFile"; }); - - environment.etc = authKeysFiles // authKeysConfiguration // + + services.openssh.authorizedKeysFiles = [ "%h/.ssh/authorized_keys" "/etc/ssh/authorized_keys.d/%u" ]; + + environment.etc = authKeysFiles // { "ssh/ssh_known_hosts".text = (flip (concatMapStringsSep "\n") knownHosts (h: assert h.hostNames != []; concatStringsSep "," h.hostNames + " " + (if h.publicKey != null then h.publicKey else readFile h.publicKeyFile) )) + "\n"; + + "ssh/sshd_config.d/101-authorized-keys.conf" = { + text = "AuthorizedKeysFile ${toString config.services.openssh.authorizedKeysFiles}\n"; + # Allows us to automatically migrate from using a file to a symlink + knownSha256Hashes = [ oldAuthorizedKeysHash ]; + }; }; + + # Clean up .orig file left over from using knownSha256Hashes + system.activationScripts.etc.text = '' + auth_keys_orig=/etc/ssh/sshd_config.d/101-authorized-keys.conf.orig + + if [ -e "$auth_keys_orig" ] && [ "$(shasum -a 256 $auth_keys_orig | cut -d ' ' -f 1)" = "${oldAuthorizedKeysHash}" ]; then + rm "$auth_keys_orig" + fi + ''; }; } diff --git a/tests/programs-ssh.nix b/tests/programs-ssh.nix index 2928cfb..ad4f7ab 100644 --- a/tests/programs-ssh.nix +++ b/tests/programs-ssh.nix @@ -15,6 +15,6 @@ echo >&2 "checking for authorized keys for foo in /etc/ssh/authorized_keys.d/foo" grep 'ssh-ed25519 AAAA...' ${config.out}/etc/ssh/authorized_keys.d/foo echo >&2 "checking for authorized keys' path in /etc/ssh/sshd_config.d/101-authorized-keys.conf" - grep 'AuthorizedKeysFile /etc/ssh/authorized_keys.d/%u' ${config.out}/etc/ssh/sshd_config.d/101-authorized-keys.conf + grep 'AuthorizedKeysFile %h/.ssh/authorized_keys /etc/ssh/authorized_keys.d/%u' ${config.out}/etc/ssh/sshd_config.d/101-authorized-keys.conf ''; }