openssh: Change the way authorized keys are added to the system.

Instead of the somewhat hacky script that inserted public keys
into the users' .ssh/authorized_keys files, use the AuthorizedKeysFile
configuration directive in sshd_config and generate extra key
files for each user (placed in /etc/authorized_keys.d/).
This commit is contained in:
Rickard Nilsson 2012-11-20 15:13:17 +01:00 committed by Eelco Dolstra
parent 13617b803b
commit 68872f81cf

View File

@ -40,102 +40,44 @@ let
userOptions = { userOptions = {
openssh.authorizedKeys = { openssh.authorizedKeys = {
preserveExistingKeys = mkOption {
type = types.bool;
default = true;
description = ''
If this option is enabled, the keys specified in
<literal>keys</literal> and/or <literal>keyFiles</literal> will be
placed in a special section of the user's authorized_keys file
and any existing keys will be preserved. That section will be
regenerated each time NixOS is activated. However, if
<literal>preserveExisting</literal> isn't enabled, the complete file
will be generated, and any user modifications will be wiped out.
'';
};
keys = mkOption { keys = mkOption {
type = types.listOf types.string; type = types.listOf types.string;
default = []; default = [];
description = '' description = ''
A list of verbatim OpenSSH public keys that should be inserted into the A list of verbatim OpenSSH public keys that should be added to the
user's authorized_keys file. You can combine the <literal>keys</literal> and user's authorized keys. The keys are added to a file that the SSH
daemon reads in addition to the the user's authorized_keys file.
You can combine the <literal>keys</literal> and
<literal>keyFiles</literal> options. <literal>keyFiles</literal> options.
''; '';
}; };
keyFiles = mkOption { keyFiles = mkOption {
#type = types.listOf types.string;
default = []; default = [];
description = '' description = ''
A list of files each containing one OpenSSH public keys that should be A list of files each containing one OpenSSH public key that should be
inserted into the user's authorized_keys file. You can combine added to the user's authorized keys. The contents of the files are
the <literal>keyFiles</literal> and read at build time and added to a file that the SSH daemon reads in
<literal>keys</literal> options. addition to the the user's authorized_keys file. You can combine the
<literal>keyFiles</literal> and <literal>keys</literal> options.
''; '';
}; };
}; };
}; };
mkAuthkeyScript = authKeysFiles = with {
let mkAuthKeyFile = u: {
marker1 = "### NixOS auto-added key. Do not edit!"; target = "ssh/authorized_keys.d/${u.name}";
marker2 = "### NixOS will regenerate this file. Do not edit!"; mode = "0444";
users = map (userName: getAttr userName config.users.extraUsers) (attrNames config.users.extraUsers); source = pkgs.writeText "${u.name}-authorized_keys" ''
usersWithKeys = flip filter users (u: ${concatStringsSep "\n" u.openssh.authorizedKeys.keys}
length u.openssh.authorizedKeys.keys != 0 || length u.openssh.authorizedKeys.keyFiles != 0 ${concatMapStrings (f: builtins.readFile f + "\n") u.openssh.authorizedKeys.keyFiles}
); '';
userLoop = flip concatMapStrings usersWithKeys (u: };
let usersWithKeys = attrValues (flip filterAttrs config.users.extraUsers (n: u:
authKeys = concatStringsSep "," u.openssh.authorizedKeys.keys; length u.openssh.authorizedKeys.keys != 0 || length u.openssh.authorizedKeys.keyFiles != 0
authKeyFiles = concatStrings (map (x: " ${x}") u.openssh.authorizedKeys.keyFiles); ));
preserveExisting = if u.openssh.authorizedKeys.preserveExistingKeys then "true" else "false"; }; map mkAuthKeyFile usersWithKeys;
in ''
mkAuthKeysFile "${u.name}" "${authKeys}" "${authKeyFiles}" "${preserveExisting}"
''
);
in ''
mkAuthKeysFile() {
local userName="$1"
local authKeys="$2"
local authKeyFiles="$3"
local preserveExisting="$4"
eval homeDir=~$userName
if ! [ -d "$homeDir" ]; then
echo "User $userName does not exist"
return
fi
if ! [ -d "$homeDir/.ssh" ]; then
mkdir -v -m 700 "$homeDir/.ssh"
chown "$userName":users "$homeDir/.ssh"
fi
local authKeysFile="$homeDir/.ssh/authorized_keys"
touch "$authKeysFile"
if [ "$preserveExisting" == false ]; then
rm -f "$authKeysFile"
echo "${marker2}" > "$authKeysFile"
else
sed -i '/${marker1}/ d' "$authKeysFile"
fi
IFS=,
for f in $authKeys; do
echo "$f ${marker1}" >> "$authKeysFile"
done
unset IFS
for f in $authKeyFiles; do
if [ -f "$f" ]; then
echo "$(cat "$f") ${marker1}" >> "$authKeysFile"
fi
done
chown "$userName" "$authKeysFile"
}
${userLoop}
'';
in in
@ -305,7 +247,7 @@ in
home = "/var/empty"; home = "/var/empty";
}; };
environment.etc = [ environment.etc = authKeysFiles ++ [
{ source = "${pkgs.openssh}/etc/ssh/moduli"; { source = "${pkgs.openssh}/etc/ssh/moduli";
target = "ssh/moduli"; target = "ssh/moduli";
} }
@ -326,12 +268,10 @@ in
LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive"; LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive";
}; };
path = [ pkgs.openssh pkgs.gnused ]; path = [ pkgs.openssh ];
preStart = preStart =
'' ''
${mkAuthkeyScript}
mkdir -m 0755 -p /etc/ssh mkdir -m 0755 -p /etc/ssh
if ! test -f ${cfg.hostKeyPath}; then if ! test -f ${cfg.hostKeyPath}; then
@ -379,6 +319,8 @@ in
GatewayPorts ${cfg.gatewayPorts} GatewayPorts ${cfg.gatewayPorts}
PasswordAuthentication ${if cfg.passwordAuthentication then "yes" else "no"} PasswordAuthentication ${if cfg.passwordAuthentication then "yes" else "no"}
ChallengeResponseAuthentication ${if cfg.challengeResponseAuthentication then "yes" else "no"} ChallengeResponseAuthentication ${if cfg.challengeResponseAuthentication then "yes" else "no"}
AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2 /etc/ssh/authorized_keys.d/%u
''; '';
assertions = [{ assertion = if cfg.forwardX11 then cfgc.setXAuthLocation else true; assertions = [{ assertion = if cfg.forwardX11 then cfgc.setXAuthLocation else true;