services/openssh: manage host keys
This commit is contained in:
parent
3bfa436c19
commit
e6efc7c131
3 changed files with 116 additions and 3 deletions
|
|
@ -1,7 +1,72 @@
|
|||
{ config, lib, ... }:
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
cfg = config.services.openssh;
|
||||
|
||||
hostKeyOpts = {
|
||||
options = {
|
||||
type = lib.mkOption {
|
||||
type = lib.types.enum [ "dsa" "ecdsa" "ed25519" "rsa" ];
|
||||
description = ''
|
||||
Key type passed to `ssh-keygen -t`.
|
||||
'';
|
||||
};
|
||||
|
||||
path = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
Path to the private key file.
|
||||
'';
|
||||
};
|
||||
|
||||
bits = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
Key size in bits. If `null`, `ssh-keygen` uses the default
|
||||
for the given key type (RSA=3072, ECDSA=256, ED25519=fixed).
|
||||
'';
|
||||
};
|
||||
|
||||
comment = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "";
|
||||
description = ''
|
||||
Comment for the key, passed to `ssh-keygen -C`.
|
||||
|
||||
Defaults to an empty string to match Apple's built-in host key
|
||||
generation and avoid leaking the hostname.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
hostKeysConfig = lib.concatMapStringsSep "\n"
|
||||
(k: "HostKey ${k.path}")
|
||||
cfg.hostKeys;
|
||||
|
||||
keygenScript = lib.concatMapStrings (k:
|
||||
let
|
||||
escapedPath = lib.escapeShellArg k.path;
|
||||
in ''
|
||||
if ! [[ -s ${escapedPath} ]]; then
|
||||
if ! [[ -L ${escapedPath} ]]; then
|
||||
rm -f ${escapedPath}
|
||||
fi
|
||||
|
||||
keygenArgs=(
|
||||
-t ${lib.escapeShellArg k.type}
|
||||
${lib.optionalString (k.bits != null) "-b ${toString k.bits}"}
|
||||
-C ${lib.escapeShellArg k.comment}
|
||||
-f ${escapedPath}
|
||||
-N ""
|
||||
)
|
||||
|
||||
mkdir -p "$(dirname ${escapedPath})"
|
||||
chmod 0755 "$(dirname ${escapedPath})"
|
||||
${lib.getExe' pkgs.openssh "ssh-keygen"} "''${keygenArgs[@]}"
|
||||
fi
|
||||
'') cfg.hostKeys;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
|
|
@ -24,6 +89,22 @@ in
|
|||
See {manpage}`sshd_config(5)` for help.
|
||||
'';
|
||||
};
|
||||
|
||||
hostKeys = lib.mkOption {
|
||||
type = lib.types.listOf (lib.types.submodule hostKeyOpts);
|
||||
default = [
|
||||
{ type = "rsa"; path = "/etc/ssh/ssh_host_rsa_key"; }
|
||||
{ type = "ecdsa"; path = "/etc/ssh/ssh_host_ecdsa_key"; }
|
||||
{ type = "ed25519"; path = "/etc/ssh/ssh_host_ed25519_key"; }
|
||||
];
|
||||
description = ''
|
||||
SSH host key declarations. Each entry specifies a key type and path.
|
||||
`HostKey` directives are written to the sshd configuration for each
|
||||
entry.
|
||||
|
||||
The default matches the keys that macOS automatically generates.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -41,6 +122,12 @@ in
|
|||
fi
|
||||
'');
|
||||
|
||||
environment.etc."ssh/sshd_config.d/099-host-keys.conf" = lib.mkIf (cfg.hostKeys != []) {
|
||||
text = hostKeysConfig;
|
||||
};
|
||||
|
||||
environment.etc."ssh/sshd_config.d/100-nix-darwin.conf".text = cfg.extraConfig;
|
||||
|
||||
system.activationScripts.openssh.text = lib.mkIf (cfg.hostKeys != []) keygenScript;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@ in
|
|||
${cfg.activationScripts.applications.text}
|
||||
${cfg.activationScripts.pam.text}
|
||||
${cfg.activationScripts.patches.text}
|
||||
${cfg.activationScripts.openssh.text}
|
||||
${cfg.activationScripts.etc.text}
|
||||
${cfg.activationScripts.defaults.text}
|
||||
${cfg.activationScripts.userDefaults.text}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,37 @@
|
|||
{ config, pkgs, ... }:
|
||||
{ config, ... }:
|
||||
|
||||
{
|
||||
services.openssh.enable = true;
|
||||
services.openssh.extraConfig = ''
|
||||
StreamLocalBindUnlink yes
|
||||
'';
|
||||
services.openssh.hostKeys = [
|
||||
{ type = "ed25519"; path = "/etc/ssh/custom_host_ed25519_key"; comment = "my-host"; }
|
||||
{ type = "rsa"; path = "/etc/ssh/custom_host_rsa_key"; bits = 4096; }
|
||||
];
|
||||
|
||||
test = ''
|
||||
echo >&2 "checking for StreamLocalBindUnlink in /etc/ssh/ssh_known_hosts"
|
||||
echo >&2 "checking for StreamLocalBindUnlink in /etc/ssh/sshd_config.d/100-nix-darwin.conf"
|
||||
grep 'StreamLocalBindUnlink yes' ${config.out}/etc/ssh/sshd_config.d/100-nix-darwin.conf
|
||||
|
||||
echo >&2 "checking for HostKey directives in /etc/ssh/sshd_config.d/099-host-keys.conf"
|
||||
grep 'HostKey /etc/ssh/custom_host_ed25519_key' ${config.out}/etc/ssh/sshd_config.d/099-host-keys.conf
|
||||
grep 'HostKey /etc/ssh/custom_host_rsa_key' ${config.out}/etc/ssh/sshd_config.d/099-host-keys.conf
|
||||
|
||||
echo >&2 "checking that default keys are absent from config"
|
||||
(! grep 'HostKey /etc/ssh/ssh_host_rsa_key' ${config.out}/etc/ssh/sshd_config.d/099-host-keys.conf)
|
||||
(! grep 'HostKey /etc/ssh/ssh_host_ecdsa_key' ${config.out}/etc/ssh/sshd_config.d/099-host-keys.conf)
|
||||
(! grep 'HostKey /etc/ssh/ssh_host_ed25519_key' ${config.out}/etc/ssh/sshd_config.d/099-host-keys.conf)
|
||||
|
||||
echo >&2 "checking for ssh-keygen commands in activation script"
|
||||
grep 'ssh-keygen.*keygenArgs' ${config.out}/activate
|
||||
|
||||
echo >&2 "checking for keygenArgs in activation script"
|
||||
grep '\-t ed25519' ${config.out}/activate
|
||||
grep '\-C my-host' ${config.out}/activate
|
||||
grep '\-f /etc/ssh/custom_host_ed25519_key' ${config.out}/activate
|
||||
grep '\-t rsa' ${config.out}/activate
|
||||
grep '\-b 4096' ${config.out}/activate
|
||||
grep '\-f /etc/ssh/custom_host_rsa_key' ${config.out}/activate
|
||||
'';
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue