sshd: Support multiple host keys
The option services.openssh.hostKeys now allows specifying multiple host keys. The default value enables both a DSA and ECDSA key. (Clients by default will use the ECDSA key, unless known_hosts already has a DSA key for that host.) To use only an ECDSA key, you can say: services.openssh.hostKeys = [ { path = "/etc/ssh/ssh_host_ecdsa_key"; type = "ecdsa"; bits = 521; } ];
This commit is contained in:
parent
c9b9f7ee1d
commit
9771f0c96c
@ -15,29 +15,6 @@ let
|
|||||||
v == "forced-commands-only" ||
|
v == "forced-commands-only" ||
|
||||||
v == "no";
|
v == "no";
|
||||||
|
|
||||||
hostKeyTypeNames = {
|
|
||||||
dsa1024 = "dsa"; # DSA has a key size limitation due to standards
|
|
||||||
rsa3072 = "rsa";
|
|
||||||
ecdsa521 = "ecdsa";
|
|
||||||
};
|
|
||||||
|
|
||||||
hostKeyTypeBits = {
|
|
||||||
dsa1024 = 1024; # =80 bits of security
|
|
||||||
rsa3072 = 3072; # =128 bits of security
|
|
||||||
ecdsa521 = 521; # =256 bits of security
|
|
||||||
};
|
|
||||||
|
|
||||||
# equivalent to 112 bit of security strength. Anything below this is very unsafe.
|
|
||||||
hostKeyTypeSafeBits = {
|
|
||||||
dsa1024 = 2048;
|
|
||||||
rsa3072 = 2048;
|
|
||||||
ecdsa521 = 255;
|
|
||||||
};
|
|
||||||
|
|
||||||
hktn = attrByPath [cfg.hostKeyType] (throw "unknown host key type `${cfg.hostKeyType}'") hostKeyTypeNames;
|
|
||||||
hktb = attrByPath [cfg.hostKeyType] (throw "unknown host key type `${cfg.hostKeyType}'") hostKeyTypeBits;
|
|
||||||
hktsb = attrByPath [cfg.hostKeyType] (throw "unknown host key type `${cfg.hostKeyType}'") hostKeyTypeSafeBits;
|
|
||||||
|
|
||||||
knownHosts = map (h: getAttr h cfg.knownHosts) (attrNames cfg.knownHosts);
|
knownHosts = map (h: getAttr h cfg.knownHosts) (attrNames cfg.knownHosts);
|
||||||
|
|
||||||
knownHostsFile = pkgs.writeText "ssh_known_hosts" (
|
knownHostsFile = pkgs.writeText "ssh_known_hosts" (
|
||||||
@ -176,22 +153,23 @@ in
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
hostKeyType = mkOption {
|
hostKeys = mkOption {
|
||||||
default = "dsa1024";
|
default =
|
||||||
|
[ { path = "/etc/ssh/ssh_host_dsa_key";
|
||||||
|
type = "dsa";
|
||||||
|
bits = 1024;
|
||||||
|
}
|
||||||
|
{ path = "/etc/ssh/ssh_host_ecdsa_key";
|
||||||
|
type = "ecdsa";
|
||||||
|
bits = 521;
|
||||||
|
}
|
||||||
|
];
|
||||||
description = ''
|
description = ''
|
||||||
Type of host key to generate (dsa1024/rsa3072/ecdsa521), if
|
NixOS can automatically generate SSH host keys. This option
|
||||||
the file specified by <literal>hostKeyPath</literal> does not
|
specifies the path, type and size of each key. See
|
||||||
exist when the service starts.
|
<citerefentry><refentrytitle>ssh-keygen</refentrytitle>
|
||||||
'';
|
<manvolnum>1</manvolnum></citerefentry> for supported types
|
||||||
};
|
and sizes.
|
||||||
|
|
||||||
hostKeyPath = mkOption {
|
|
||||||
default = "/etc/ssh/ssh_host_${hktn}_key";
|
|
||||||
description = ''
|
|
||||||
Path to the server's private key. If there is no key file
|
|
||||||
on this path, it will be generated when the service is
|
|
||||||
started for the first time. Otherwise, the ssh daemon will
|
|
||||||
use the specified key directly in-place.
|
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -252,7 +230,7 @@ in
|
|||||||
|
|
||||||
###### implementation
|
###### implementation
|
||||||
|
|
||||||
config = mkIf config.services.openssh.enable {
|
config = mkIf cfg.enable {
|
||||||
|
|
||||||
users.extraUsers = singleton
|
users.extraUsers = singleton
|
||||||
{ name = "sshd";
|
{ name = "sshd";
|
||||||
@ -286,21 +264,16 @@ in
|
|||||||
''
|
''
|
||||||
mkdir -m 0755 -p /etc/ssh
|
mkdir -m 0755 -p /etc/ssh
|
||||||
|
|
||||||
if ! test -f ${cfg.hostKeyPath}; then
|
${flip concatMapStrings cfg.hostKeys (k: ''
|
||||||
ssh-keygen -t ${hktn} -b ${toString hktb} -f ${cfg.hostKeyPath} -N ""
|
if ! [ -f "${k.path}" ]; then
|
||||||
fi
|
ssh-keygen -t "${k.type}" -b "${toString k.bits}" -f "${k.path}" -N ""
|
||||||
|
fi
|
||||||
result=$(ssh-keygen -lf ${cfg.hostKeyPath}|awk '{ print ($1>=${toString hktsb}?1:0)}')
|
'')}
|
||||||
if [ "$result" -ne "1" ]; then
|
|
||||||
ERROR="SECURITY ALERT: SSH Host Key is too weak. Generate a strong key NOW."
|
|
||||||
echo "$ERROR"
|
|
||||||
echo "$ERROR" > /dev/console
|
|
||||||
fi
|
|
||||||
'';
|
'';
|
||||||
|
|
||||||
serviceConfig =
|
serviceConfig =
|
||||||
{ ExecStart =
|
{ ExecStart =
|
||||||
"${pkgs.openssh}/sbin/sshd -h ${cfg.hostKeyPath} " +
|
"${pkgs.openssh}/sbin/sshd " +
|
||||||
"-f ${pkgs.writeText "sshd_config" cfg.extraConfig}";
|
"-f ${pkgs.writeText "sshd_config" cfg.extraConfig}";
|
||||||
Restart = "always";
|
Restart = "always";
|
||||||
Type = "forking";
|
Type = "forking";
|
||||||
@ -351,6 +324,10 @@ in
|
|||||||
PrintMotd no # handled by pam_motd
|
PrintMotd no # handled by pam_motd
|
||||||
|
|
||||||
AuthorizedKeysFile ${toString cfg.authorizedKeysFiles}
|
AuthorizedKeysFile ${toString cfg.authorizedKeysFiles}
|
||||||
|
|
||||||
|
${flip concatMapStrings cfg.hostKeys (k: ''
|
||||||
|
HostKey ${k.path}
|
||||||
|
'')}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
assertions = [{ assertion = if cfg.forwardX11 then cfgc.setXAuthLocation else true;
|
assertions = [{ assertion = if cfg.forwardX11 then cfgc.setXAuthLocation else true;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user