mirror of
https://github.com/NixOS/nixpkgs.git
synced 2024-11-22 23:13:19 +00:00
systemd-initrd: sshd
This commit is contained in:
parent
748f1329fc
commit
0698a1cf04
@ -5,6 +5,10 @@ with lib;
|
||||
let
|
||||
|
||||
cfg = config.boot.initrd.network.ssh;
|
||||
shell = if cfg.shell == null then "/bin/ash" else cfg.shell;
|
||||
inherit (config.programs.ssh) package;
|
||||
|
||||
enabled = let initrd = config.boot.initrd; in (initrd.network.enable || initrd.systemd.network.enable) && cfg.enable;
|
||||
|
||||
in
|
||||
|
||||
@ -33,8 +37,9 @@ in
|
||||
};
|
||||
|
||||
shell = mkOption {
|
||||
type = types.str;
|
||||
default = "/bin/ash";
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
defaultText = ''"/bin/ash"'';
|
||||
description = lib.mdDoc ''
|
||||
Login shell of the remote user. Can be used to limit actions user can do.
|
||||
'';
|
||||
@ -119,9 +124,11 @@ in
|
||||
sshdCfg = config.services.openssh;
|
||||
|
||||
sshdConfig = ''
|
||||
UsePAM no
|
||||
Port ${toString cfg.port}
|
||||
|
||||
PasswordAuthentication no
|
||||
AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys2 /etc/ssh/authorized_keys.d/%u
|
||||
ChallengeResponseAuthentication no
|
||||
|
||||
${flip concatMapStrings cfg.hostKeys (path: ''
|
||||
@ -142,7 +149,7 @@ in
|
||||
|
||||
${cfg.extraConfig}
|
||||
'';
|
||||
in mkIf (config.boot.initrd.network.enable && cfg.enable) {
|
||||
in mkIf enabled {
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.authorizedKeys != [];
|
||||
@ -157,14 +164,19 @@ in
|
||||
for instructions.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
assertion = config.boot.initrd.systemd.enable -> cfg.shell == null;
|
||||
message = "systemd stage 1 does not support boot.initrd.network.ssh.shell";
|
||||
}
|
||||
];
|
||||
|
||||
boot.initrd.extraUtilsCommands = ''
|
||||
copy_bin_and_libs ${pkgs.openssh}/bin/sshd
|
||||
boot.initrd.extraUtilsCommands = mkIf (!config.boot.initrd.systemd.enable) ''
|
||||
copy_bin_and_libs ${package}/bin/sshd
|
||||
cp -pv ${pkgs.glibc.out}/lib/libnss_files.so.* $out/lib
|
||||
'';
|
||||
|
||||
boot.initrd.extraUtilsCommandsTest = ''
|
||||
boot.initrd.extraUtilsCommandsTest = mkIf (!config.boot.initrd.systemd.enable) ''
|
||||
# sshd requires a host key to check config, so we pass in the test's
|
||||
tmpkey="$(mktemp initrd-ssh-testkey.XXXXXXXXXX)"
|
||||
cp "${../../../tests/initrd-network-ssh/ssh_host_ed25519_key}" "$tmpkey"
|
||||
@ -176,9 +188,9 @@ in
|
||||
rm "$tmpkey"
|
||||
'';
|
||||
|
||||
boot.initrd.network.postCommands = ''
|
||||
echo '${cfg.shell}' > /etc/shells
|
||||
echo 'root:x:0:0:root:/root:${cfg.shell}' > /etc/passwd
|
||||
boot.initrd.network.postCommands = mkIf (!config.boot.initrd.systemd.enable) ''
|
||||
echo '${shell}' > /etc/shells
|
||||
echo 'root:x:0:0:root:/root:${shell}' > /etc/passwd
|
||||
echo 'sshd:x:1:1:sshd:/var/empty:/bin/nologin' >> /etc/passwd
|
||||
echo 'passwd: files' > /etc/nsswitch.conf
|
||||
|
||||
@ -204,7 +216,7 @@ in
|
||||
/bin/sshd -e
|
||||
'';
|
||||
|
||||
boot.initrd.postMountCommands = ''
|
||||
boot.initrd.postMountCommands = mkIf (!config.boot.initrd.systemd.enable) ''
|
||||
# Stop sshd cleanly before stage 2.
|
||||
#
|
||||
# If you want to keep it around to debug post-mount SSH issues,
|
||||
@ -217,6 +229,38 @@ in
|
||||
|
||||
boot.initrd.secrets = listToAttrs
|
||||
(map (path: nameValuePair (initrdKeyPath path) path) cfg.hostKeys);
|
||||
|
||||
# Systemd initrd stuff
|
||||
boot.initrd.systemd = mkIf config.boot.initrd.systemd.enable {
|
||||
users.sshd = { uid = 1; group = "sshd"; };
|
||||
groups.sshd = { gid = 1; };
|
||||
|
||||
contents."/etc/ssh/authorized_keys.d/root".text =
|
||||
concatStringsSep "\n" config.boot.initrd.network.ssh.authorizedKeys;
|
||||
contents."/etc/ssh/sshd_config".text = sshdConfig;
|
||||
storePaths = ["${package}/bin/sshd"];
|
||||
|
||||
services.sshd = {
|
||||
description = "SSH Daemon";
|
||||
wantedBy = ["initrd.target"];
|
||||
after = ["network.target" "initrd-nixos-copy-secrets.service"];
|
||||
|
||||
# Keys from Nix store are world-readable, which sshd doesn't
|
||||
# like. If this were a real nix store and not the initrd, we
|
||||
# neither would nor could do this
|
||||
preStart = flip concatMapStrings cfg.hostKeys (path: ''
|
||||
/bin/chmod 0600 "${initrdKeyPath path}"
|
||||
'');
|
||||
unitConfig.DefaultDependencies = false;
|
||||
serviceConfig = {
|
||||
ExecStart = "${package}/bin/sshd -D -f /etc/ssh/sshd_config";
|
||||
Type = "simple";
|
||||
KillMode = "process";
|
||||
Restart = "on-failure";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -678,6 +678,7 @@ in {
|
||||
systemd-initrd-swraid = handleTest ./systemd-initrd-swraid.nix {};
|
||||
systemd-initrd-vconsole = handleTest ./systemd-initrd-vconsole.nix {};
|
||||
systemd-initrd-networkd = handleTest ./systemd-initrd-networkd.nix {};
|
||||
systemd-initrd-networkd-ssh = handleTest ./systemd-initrd-networkd-ssh.nix {};
|
||||
systemd-journal = handleTest ./systemd-journal.nix {};
|
||||
systemd-machinectl = handleTest ./systemd-machinectl.nix {};
|
||||
systemd-networkd = handleTest ./systemd-networkd.nix {};
|
||||
|
82
nixos/tests/systemd-initrd-networkd-ssh.nix
Normal file
82
nixos/tests/systemd-initrd-networkd-ssh.nix
Normal file
@ -0,0 +1,82 @@
|
||||
import ./make-test-python.nix ({ lib, ... }: {
|
||||
name = "systemd-initrd-network-ssh";
|
||||
meta.maintainers = [ lib.maintainers.elvishjerricco ];
|
||||
|
||||
nodes = with lib; {
|
||||
server = { config, pkgs, ... }: {
|
||||
environment.systemPackages = [pkgs.cryptsetup];
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.timeout = 0;
|
||||
virtualisation = {
|
||||
emptyDiskImages = [ 4096 ];
|
||||
useBootLoader = true;
|
||||
useEFIBoot = true;
|
||||
};
|
||||
|
||||
specialisation.encrypted-root.configuration = {
|
||||
virtualisation.bootDevice = "/dev/mapper/root";
|
||||
boot.initrd.luks.devices = lib.mkVMOverride {
|
||||
root.device = "/dev/vdc";
|
||||
};
|
||||
boot.initrd.systemd.enable = true;
|
||||
boot.initrd.network = {
|
||||
enable = true;
|
||||
ssh = {
|
||||
enable = true;
|
||||
authorizedKeys = [ (readFile ./initrd-network-ssh/id_ed25519.pub) ];
|
||||
port = 22;
|
||||
# Terrible hack so it works with useBootLoader
|
||||
hostKeys = [ { outPath = "${./initrd-network-ssh/ssh_host_ed25519_key}"; } ];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
client = { config, ... }: {
|
||||
environment.etc = {
|
||||
knownHosts = {
|
||||
text = concatStrings [
|
||||
"server,"
|
||||
"${
|
||||
toString (head (splitString " " (toString
|
||||
(elemAt (splitString "\n" config.networking.extraHosts) 2))))
|
||||
} "
|
||||
"${readFile ./initrd-network-ssh/ssh_host_ed25519_key.pub}"
|
||||
];
|
||||
};
|
||||
sshKey = {
|
||||
source = ./initrd-network-ssh/id_ed25519;
|
||||
mode = "0600";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
|
||||
def ssh_is_up(_) -> bool:
|
||||
status, _ = client.execute("nc -z server 22")
|
||||
return status == 0
|
||||
|
||||
server.wait_for_unit("multi-user.target")
|
||||
server.succeed(
|
||||
"echo somepass | cryptsetup luksFormat --type=luks2 /dev/vdc",
|
||||
"bootctl set-default nixos-generation-1-specialisation-encrypted-root.conf",
|
||||
"sync",
|
||||
)
|
||||
server.shutdown()
|
||||
server.start()
|
||||
|
||||
client.wait_for_unit("network.target")
|
||||
with client.nested("waiting for SSH server to come up"):
|
||||
retry(ssh_is_up)
|
||||
|
||||
client.succeed(
|
||||
"echo somepass | ssh -i /etc/sshKey -o UserKnownHostsFile=/etc/knownHosts server 'systemd-tty-ask-password-agent' & exit"
|
||||
)
|
||||
|
||||
server.wait_for_unit("multi-user.target")
|
||||
server.succeed("mount | grep '/dev/mapper/root on /'")
|
||||
'';
|
||||
})
|
Loading…
Reference in New Issue
Block a user