1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 cfg = config.boot.initrd.network.ssh;
8
9in
10
11{
12
13 options = {
14
15 boot.initrd.network.ssh.enable = mkOption {
16 type = types.bool;
17 default = false;
18 description = ''
19 Start SSH service during initrd boot. It can be used to debug failing
20 boot on a remote server, enter pasphrase for an encrypted partition etc.
21 Service is killed when stage-1 boot is finished.
22 '';
23 };
24
25 boot.initrd.network.ssh.port = mkOption {
26 type = types.int;
27 default = 22;
28 description = ''
29 Port on which SSH initrd service should listen.
30 '';
31 };
32
33 boot.initrd.network.ssh.shell = mkOption {
34 type = types.str;
35 default = "/bin/ash";
36 description = ''
37 Login shell of the remote user. Can be used to limit actions user can do.
38 '';
39 };
40
41 boot.initrd.network.ssh.hostRSAKey = mkOption {
42 type = types.nullOr types.path;
43 default = null;
44 description = ''
45 RSA SSH private key file in the Dropbear format.
46
47 WARNING: Unless your bootloader supports initrd secrets, this key is
48 contained insecurely in the global Nix store. Do NOT use your regular
49 SSH host private keys for this purpose or you'll expose them to
50 regular users!
51 '';
52 };
53
54 boot.initrd.network.ssh.hostDSSKey = mkOption {
55 type = types.nullOr types.path;
56 default = null;
57 description = ''
58 DSS SSH private key file in the Dropbear format.
59
60 WARNING: Unless your bootloader supports initrd secrets, this key is
61 contained insecurely in the global Nix store. Do NOT use your regular
62 SSH host private keys for this purpose or you'll expose them to
63 regular users!
64 '';
65 };
66
67 boot.initrd.network.ssh.hostECDSAKey = mkOption {
68 type = types.nullOr types.path;
69 default = null;
70 description = ''
71 ECDSA SSH private key file in the Dropbear format.
72
73 WARNING: Unless your bootloader supports initrd secrets, this key is
74 contained insecurely in the global Nix store. Do NOT use your regular
75 SSH host private keys for this purpose or you'll expose them to
76 regular users!
77 '';
78 };
79
80 boot.initrd.network.ssh.authorizedKeys = mkOption {
81 type = types.listOf types.str;
82 default = config.users.extraUsers.root.openssh.authorizedKeys.keys;
83 description = ''
84 Authorized keys for the root user on initrd.
85 '';
86 };
87
88 };
89
90 config = mkIf (config.boot.initrd.network.enable && cfg.enable) {
91 assertions = [
92 { assertion = cfg.hostRSAKey != null || cfg.hostDSSKey != null || cfg.hostECDSAKey != null;
93 message = "You should specify at least one host key for initrd SSH";
94 }
95 { assertion = cfg.authorizedKeys != [];
96 message = "You should specify at least one authorized key for initrd SSH";
97 }
98 ];
99
100 boot.initrd.extraUtilsCommands = ''
101 copy_bin_and_libs ${pkgs.dropbear}/bin/dropbear
102 cp -pv ${pkgs.glibc.out}/lib/libnss_files.so.* $out/lib
103 '';
104
105 boot.initrd.extraUtilsCommandsTest = ''
106 $out/bin/dropbear -V
107 '';
108
109 boot.initrd.network.postCommands = ''
110 echo '${cfg.shell}' > /etc/shells
111 echo 'root:x:0:0:root:/root:${cfg.shell}' > /etc/passwd
112 echo 'passwd: files' > /etc/nsswitch.conf
113
114 mkdir -p /var/log
115 touch /var/log/lastlog
116
117 mkdir -p /etc/dropbear
118
119 mkdir -p /root/.ssh
120 ${concatStrings (map (key: ''
121 echo ${escapeShellArg key} >> /root/.ssh/authorized_keys
122 '') cfg.authorizedKeys)}
123
124 dropbear -s -j -k -E -m -p ${toString cfg.port}
125 '';
126
127 boot.initrd.secrets =
128 (optionalAttrs (cfg.hostRSAKey != null) { "/etc/dropbear/dropbear_rsa_host_key" = cfg.hostRSAKey; }) //
129 (optionalAttrs (cfg.hostDSSKey != null) { "/etc/dropbear/dropbear_dss_host_key" = cfg.hostDSSKey; }) //
130 (optionalAttrs (cfg.hostECDSAKey != null) { "/etc/dropbear/dropbear_ecdsa_host_key" = cfg.hostECDSAKey; });
131
132 };
133
134}