diff options
Diffstat (limited to 'sys/boot')
| -rw-r--r-- | sys/boot/chain.nix | 14 | ||||
| -rw-r--r-- | sys/boot/default.nix | 1 | ||||
| -rw-r--r-- | sys/boot/pxe.nix | 187 | ||||
| -rw-r--r-- | sys/boot/tpm.nix | 4 |
4 files changed, 200 insertions, 6 deletions
diff --git a/sys/boot/chain.nix b/sys/boot/chain.nix index 43edcb4..b6a9ab2 100644 --- a/sys/boot/chain.nix +++ b/sys/boot/chain.nix @@ -9,7 +9,7 @@ with lib; let in { options.local.boot = { loader = mkOption { - type = types.enum ["none" "grub" "systemd-boot"]; + type = types.enum ["none" "out-of-band" "grub" "systemd-boot"]; }; kernel = mkOption { @@ -22,7 +22,11 @@ in { kernelPackages = cfg.kernel; loader = - if cfg.loader == "grub" + if cfg.loader == "none" || cfg.loader == "out-of-band" + then { + grub.enable = false; + } + else if cfg.loader == "grub" then { grub = { enable = true; @@ -30,12 +34,14 @@ in { efiSupport = true; }; } - else { + else if cfg.loader == "systemd-boot" + then { systemd-boot = { enable = true; editor = true; }; - }; + } + else throw "unexpected config.local.boot.loader setting: ${cfg.loader}"; }; }; } diff --git a/sys/boot/default.nix b/sys/boot/default.nix index 4580cba..3cbbb6f 100644 --- a/sys/boot/default.nix +++ b/sys/boot/default.nix @@ -7,6 +7,7 @@ ./fscrypt.nix ./impermanence.nix ./namespaced.nix + ./pxe.nix ./secure-boot.nix ./stack ./tpm.nix diff --git a/sys/boot/pxe.nix b/sys/boot/pxe.nix new file mode 100644 index 0000000..e25ba9d --- /dev/null +++ b/sys/boot/pxe.nix @@ -0,0 +1,187 @@ +{ + config, + lib, + ... +}: +with lib; let + cfg = config.local.boot.pxe; +in { + options.local.boot.pxe = { + enable = mkEnableOption "PXE netboot"; + + setupMode = mkOption { + type = types.bool; + default = false; + }; + + initrdInterface = mkOption { + type = types.str; + }; + + linkLocal6 = mkOption { + type = types.str; + }; + + networkDriver = mkOption { + type = types.str; + }; + + mac = mkOption { + type = types.str; + }; + + panicTimeout = mkOption { + type = types.nullOr types.ints.u16; + default = 30; + }; + }; + + # Based on nixpkgs/nixos/modules/installer/netboot/netboot.nix + config = mkIf cfg.enable { + boot = { + initrd = { + kernelModules = [cfg.networkDriver]; + + network = { + enable = true; + flushBeforeStage2 = true; + ssh = { + enable = true; + ignoreEmptyHostKeys = true; + }; + }; + + preFailCommands = mkIf (!cfg.setupMode) '' + echo "init stage1 failed in unattended mode, rebooting" + reboot -f + ''; + + postResumeCommands = '' + store_img_dir="/nix/.ro-store-img" + store_img="$store_img_dir/nix-store.squashfs" + + mkdir -p "$store_img_dir" + mount -t tmpfs -o mode=0700,nr_inodes=2,huge=within_size,nodev,nosuid tmpfs "$store_img_dir" + + ip link set up ${cfg.initrdInterface} + ip addr add ${cfg.linkLocal6}/64 dev ${cfg.initrdInterface} + + recv_init_timeout=120 + echo -n "Waiting up to ''${recv_init_timeout}s for $store_img" + + t="$recv_init_timeout" + while true; do + echo -n . | nc -u -w1 -s ${cfg.linkLocal6}%${cfg.initrdInterface} fe80::b007:b007%${cfg.initrdInterface} 1792 >/dev/null 2>&1 & + + if [ -e "$store_img.tmp" ]; then + kill -x nc + break + elif [ "$t" -le 0 ]; then + echo "timed out" + fail + fi + + # sleep builtin de ash retorna cuando nc termina (lo cual puede pasar muchas veces debido a IPv6 DAD) + /bin/sleep 1 + echo -n . + t=$((t - 1)) + done + + recv_poll=60 + recv_timeout=1800 + + t=0 + last_mtime="" + poll_time="$recv_poll" + while true; do + if [ -e "$store_img" ]; then + break + elif [ "$t" -ge "$recv_timeout" ]; then + echo "Store image upload timed out" + fail + fi + + sleep 1 + t=$((t + 1)) + poll_time=$((poll_time - 1)) + + if [ "$poll_time" -le 0 ]; then + current_size=$(stat -c '%s' "$store_img.tmp" || echo -) + current_mtime=$(stat -c '%y' "$store_img.tmp" || echo final) + echo "Store upload: $current_mtime: $current_size bytes" + + if [ "$current_mtime" = "$last_mtime" ]; then + echo "Store image upload stalled, image not modified in ''${recv_poll}s" + fail + fi + + last_mtime="$current_mtime" + poll_time="$recv_poll" + fi + done + + sleep 1 + kill -x sshd + + chmod 0500 "$store_img_dir" + chmod 0400 "$store_img" + chattr +i "$store_img" + mount -o remount,ro "$store_img_dir" + + store_size=$(stat -c '%s' "$store_img") + echo "Store image upload complete, final size is $store_size bytes" + + ln -sf "$store_img" /dev/nix-store + ''; + + postMountCommands = '' + mkdir -p "/mnt-root$store_img_dir" + mount --move "$store_img_dir" "/mnt-root$store_img_dir" + ''; + }; + + kernelParams = + optional (cfg.panicTimeout != null) "panic=${toString cfg.panicTimeout}" + ++ optional cfg.setupMode "boot.shell_on_fail"; + }; + + fileSystems = { + "/" = { + fsType = "tmpfs"; + neededForBoot = true; + + options = ["mode=0755"]; + }; + + "/nix/store" = { + fsType = "overlay"; + neededForBoot = true; + + overlay = { + lowerdir = ["/nix/.ro-store"]; + upperdir = "/nix/.rw-store/store"; + workdir = "/nix/.rw-store/work"; + }; + }; + + "/nix/.ro-store" = { + fsType = "squashfs"; + neededForBoot = true; + + device = "/dev/nix-store"; + options = ["loop" "threads=multi"]; + }; + + "/nix/.rw-store" = { + fsType = "tmpfs"; + neededForBoot = true; + + options = ["mode=0755"]; + }; + }; + + local = { + boot.loader = "out-of-band"; + }; + }; +} diff --git a/sys/boot/tpm.nix b/sys/boot/tpm.nix index ecc115b..da6f73a 100644 --- a/sys/boot/tpm.nix +++ b/sys/boot/tpm.nix @@ -93,8 +93,8 @@ in { config = mkIf cfg.enable { assertions = [ { - assertion = config.local.boot.efi.enable; - message = "TPM2 requires EFI"; + assertion = cfg.initrd.enable -> config.local.boot.efi.enable; + message = "TPM2 in initrd requires EFI"; } { assertion = cfg.initrd.enable -> cfg.enable; |
