diff --git a/externals/systemd-boot-secure/default.nix b/externals/systemd-boot-secure/default.nix
deleted file mode 100644
index abdfa29..0000000
--- a/externals/systemd-boot-secure/default.nix
+++ /dev/null
@@ -1,183 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-let
- cfg = config.boot.loader.systemd-boot-secure;
-
- efi = config.boot.loader.efi;
-
- gummibootBuilder = pkgs.substituteAll {
- src = ./systemd-boot-builder.py;
-
- isExecutable = true;
-
- inherit (pkgs.buildPackages) python3 sbsigntool;
-
- binutils = pkgs.buildPackages.binutils-unwrapped;
-
- systemd = config.systemd.package;
-
- nix = config.nix.package.out;
-
- timeout = if config.boot.loader.timeout != null then
- config.boot.loader.timeout
- else
- "";
-
- editor = if cfg.editor then "True" else "False";
-
- configurationLimit =
- if cfg.configurationLimit == null then 0 else cfg.configurationLimit;
-
- inherit (cfg) consoleMode;
-
- inherit (efi) efiSysMountPoint canTouchEfiVariables;
-
- memtest86 = if cfg.memtest86.enable then pkgs.memtest86-efi else "";
-
- inherit (cfg) signed;
-
- signingKey = if cfg.signed then cfg.signing-key else "/no-signing-key";
-
- signingCertificate =
- if cfg.signed then cfg.signing-certificate else "/no-signing-crt";
- };
-in {
-
- options.boot.loader.systemd-boot-secure = {
- enable = mkOption {
- default = false;
-
- type = types.bool;
-
- description =
- "Whether to enable the systemd-boot (formerly gummiboot) EFI boot manager";
- };
-
- signed = mkOption {
- default = false;
- type = types.bool;
- description = ''
- Whether or not the bootloader files, including systemd-boot
- EFI programs should be signed.
- '';
- };
-
- signing-key = mkOption {
- type = types.path;
- example = "/root/secure-boot/db.key";
- description = ''
- The db.key signing key, for signing EFI
- programs. Note: Do not pass a store path. Passing the key like
- signing-key = ./db.key; will copy the
- private key in to the Nix store and make it world-readable.
-
- Instead, pass the path as an absolute path string, like:
- signing-key = "/root/secure-boot/db.key";.
- '';
- };
-
- signing-certificate = mkOption {
- type = types.path;
- example = "/root/secure-boot/db.crt";
- description = ''
- The db.crt signing certificate, for signing
- EFI programs. Note: certificate files are not private.
- '';
- };
-
- editor = mkOption {
- default = true;
-
- type = types.bool;
-
- description = ''
- Whether to allow editing the kernel command-line before
- boot. It is recommended to set this to false, as it allows
- gaining root access by passing init=/bin/sh as a kernel
- parameter. However, it is enabled by default for backwards
- compatibility.
- '';
- };
-
- configurationLimit = mkOption {
- default = null;
- example = 120;
- type = types.nullOr types.int;
- description = ''
- Maximum number of latest generations in the boot menu.
- Useful to prevent boot partition running out of disk space.
-
- null means no limit i.e. all generations
- that were not garbage collected yet.
- '';
- };
-
- consoleMode = mkOption {
- default = "keep";
-
- type = types.enum [ "0" "1" "2" "auto" "max" "keep" ];
-
- description = ''
- The resolution of the console. The following values are valid:
-
-
-
- "0": Standard UEFI 80x25 mode
-
-
- "1": 80x50 mode, not supported by all devices
-
-
- "2": The first non-standard mode provided by the device firmware, if any
-
-
- "auto": Pick a suitable mode automatically using heuristics
-
-
- "max": Pick the highest-numbered available mode
-
-
- "keep": Keep the mode selected by firmware (the default)
-
-
- '';
- };
-
- memtest86 = {
- enable = mkOption {
- default = false;
- type = types.bool;
- description = ''
- Make MemTest86 available from the systemd-boot menu. MemTest86 is a
- program for testing memory. MemTest86 is an unfree program, so
- this requires allowUnfree to be set to
- true.
- '';
- };
- };
- };
-
- config = mkIf cfg.enable {
- assertions = [{
- assertion =
- (config.boot.kernelPackages.kernel.features or { efiBootStub = true; })
- ? efiBootStub;
-
- message = "This kernel does not support the EFI boot stub";
- }];
-
- boot.loader.grub.enable = mkDefault false;
-
- boot.loader.supportsInitrdSecrets = true;
-
- system = {
- build.installBootLoader = gummibootBuilder;
-
- boot.loader.id = "systemd-boot";
-
- requiredKernelConfig = with config.lib.kernelConfig;
- [ (isYes "EFI_STUB") ];
- };
- };
-}
diff --git a/externals/systemd-boot-secure/systemd-boot-builder.py b/externals/systemd-boot-secure/systemd-boot-builder.py
deleted file mode 100644
index f425b4a..0000000
--- a/externals/systemd-boot-secure/systemd-boot-builder.py
+++ /dev/null
@@ -1,351 +0,0 @@
-#! @python3@/bin/python3 -B
-import argparse
-import shutil
-import os
-import sys
-import errno
-import subprocess
-import glob
-import tempfile
-import warnings
-import ctypes
-libc = ctypes.CDLL("libc.so.6")
-import re
-import datetime
-import os.path
-
-def copy_if_not_exists(source, dest):
- if not os.path.exists(dest):
- shutil.copyfile(source, dest)
-
-def system_dir(profile, generation):
- if profile:
- return "/nix/var/nix/profiles/system-profiles/%s-%d-link" % (profile, generation)
- else:
- return "/nix/var/nix/profiles/system-%d-link" % (generation)
-
-SECURE_BOOT_ENTRY = """title NixOS{profile}
-version Generation {generation} {description} (Secure Boot)
-efi {efi}
-"""
-
-BOOT_ENTRY = """title NixOS{profile}
-version Generation {generation} {description}
-linux {kernel}
-initrd {initrd}
-options {kernel_params}
-"""
-
-# The boot loader entry for memtest86.
-#
-# TODO: This is hard-coded to use the 64-bit EFI app, but it could probably
-# be updated to use the 32-bit EFI app on 32-bit systems. The 32-bit EFI
-# app filename is BOOTIA32.efi.
-MEMTEST_BOOT_ENTRY = """title MemTest86
-efi /efi/memtest86/BOOTX64.efi
-"""
-
-def write_loader_conf(profile, generation):
- with open("@efiSysMountPoint@/loader/loader.conf.tmp", 'w') as f:
- if "@timeout@" != "":
- f.write("timeout @timeout@\n")
- if profile:
- f.write("default nixos-%s-generation-%d\n" % (profile, generation))
- else:
- f.write("default nixos-generation-%d\n" % (generation))
- if "@editor@" != "1":
- f.write("editor 0\n");
- f.write("console-mode @consoleMode@\n");
- os.rename("@efiSysMountPoint@/loader/loader.conf.tmp", "@efiSysMountPoint@/loader/loader.conf")
-
-def profile_path(profile, generation, name):
- return os.readlink("%s/%s" % (system_dir(profile, generation), name))
-
-def copy_from_profile(profile, generation, name, dry_run=False):
- store_file_path = profile_path(profile, generation, name)
- suffix = os.path.basename(store_file_path)
- store_dir = os.path.basename(os.path.dirname(store_file_path))
- efi_file_path = "/efi/nixos/%s-%s.efi" % (store_dir, suffix)
- if not dry_run:
- copy_if_not_exists(store_file_path, "@efiSysMountPoint@%s" % (efi_file_path))
- return efi_file_path
-
-def describe_generation(generation_dir):
- try:
- with open("%s/nixos-version" % generation_dir) as f:
- nixos_version = f.read()
- except IOError:
- nixos_version = "Unknown"
-
- kernel_dir = os.path.dirname(os.path.realpath("%s/kernel" % generation_dir))
- module_dir = glob.glob("%s/lib/modules/*" % kernel_dir)[0]
- kernel_version = os.path.basename(module_dir)
-
- build_time = int(os.path.getctime(generation_dir))
- build_date = datetime.datetime.fromtimestamp(build_time).strftime('%F')
-
- description = "NixOS {}, Linux Kernel {}, Built on {}".format(
- nixos_version, kernel_version, build_date
- )
-
- return description
-
-def write_entry(profile, generation, machine_id):
- kernel = copy_from_profile(profile, generation, "kernel")
- initrd = copy_from_profile(profile, generation, "initrd")
- try:
- append_initrd_secrets = profile_path(profile, generation, "append-initrd-secrets")
- subprocess.check_call([append_initrd_secrets, "@efiSysMountPoint@%s" % (initrd)])
- except FileNotFoundError:
- pass
- if profile:
- entry_file = "@efiSysMountPoint@/loader/entries/nixos-%s-generation-%d.conf" % (profile, generation)
- else:
- entry_file = "@efiSysMountPoint@/loader/entries/nixos-generation-%d.conf" % (generation)
- generation_dir = os.readlink(system_dir(profile, generation))
- tmp_path = "%s.tmp" % (entry_file)
- kernel_params = "systemConfig=%s init=%s/init " % (generation_dir, generation_dir)
-
- with open("%s/kernel-params" % (generation_dir)) as params_file:
- kernel_params = kernel_params + params_file.read()
- with open(tmp_path, 'w') as f:
- f.write(BOOT_ENTRY.format(profile=" [" + profile + "]" if profile else "",
- generation=generation,
- kernel=kernel,
- initrd=initrd,
- kernel_params=kernel_params,
- description=describe_generation(generation_dir)))
- if machine_id is not None:
- f.write("machine-id %s\n" % machine_id)
- os.rename(tmp_path, entry_file)
-
-def sb_efi_file_name_relative(profile, generation):
- if profile:
- return "efi/nixos/nixos-%s-generation-%d.efi" % (profile, generation)
- else:
- return "efi/nixos/nixos-generation-%d.efi" % (generation)
-
-def make_signed_efi(profile, generation, efi_file):
- with tempfile.TemporaryDirectory() as tmpdir:
- append_initrd_secrets = profile_path(profile, generation, "append-initrd-secrets")
- if os.path.exists(append_initrd_secrets):
- initrd = f"{tmpdir}/initrd"
- shutil.copyfile(
- profile_path(profile, generation, "initrd"),
- initrd
- )
-
- subprocess.check_call([append_initrd_secrets, "@efiSysMountPoint@%s" % (initrd)])
- else:
- initrd = profile_path(profile, generation, "initrd"),
-
- generation_dir = os.readlink(system_dir(profile, generation))
- tmp_path = "%s/efistub" % (tmpdir)
-
- kernel_params = "systemConfig=%s init=%s/init " % (generation_dir, generation_dir)
- with open("%s/kernel-params" % (generation_dir)) as params_file:
- kernel_params = kernel_params + params_file.read()
- kernel_param_file = "%s/kernel_params" % tmpdir
- with open(kernel_param_file, 'w') as f:
- f.write(kernel_params)
-
- subprocess.check_call([
- "@binutils@/bin/objcopy",
- "--add-section", ".osrel={}/etc/os-release".format(generation_dir), "--change-section-vma", ".osrel=0x20000",
- "--add-section", ".cmdline={}".format(kernel_param_file), "--change-section-vma", ".cmdline=0x30000",
- "--add-section", ".linux={}/kernel".format(generation_dir), "--change-section-vma", ".linux=0x40000",
- "--add-section", ".initrd={}".format(initrd), "--change-section-vma", ".initrd=0x3000000",
- "{}/sw/lib/systemd/boot/efi/linuxx64.efi.stub".format(generation_dir),
- tmp_path
- ])
- sign_path(tmp_path, efi_file)
-
-
-def write_secureboot_entry(profile, generation, machine_id):
- if profile:
- entry_file = "@efiSysMountPoint@/loader/entries/nixos-%s-generation-%d.conf" % (profile, generation)
- else:
- entry_file = "@efiSysMountPoint@/loader/entries/nixos-generation-%d.conf" % (generation)
- efi_file_relative = sb_efi_file_name_relative(profile, generation)
- efi_file = "@efiSysMountPoint@/%s" % (efi_file_relative)
-
- try:
- sbverify(efi_file)
- except:
- make_signed_efi(profile, generation, efi_file)
-
- generation_dir = os.readlink(system_dir(profile, generation))
-
- entry_tmp = entry_file + ".tmp";
- with open(entry_tmp, 'w') as fp:
- fp.write(SECURE_BOOT_ENTRY.format(
- profile=" [" + profile + "]" if profile else "",
- generation=generation,
- efi=efi_file_relative,
- description=describe_generation(generation_dir)
- ))
- if machine_id is not None:
- fp.write("machine-id %s\n" % machine_id)
-
- os.rename(entry_tmp, entry_file)
-
-def sign_path(src, output):
- with tempfile.TemporaryDirectory() as tmpdir:
- print(f"Signing {output}")
- subprocess.check_call([
- "@sbsigntool@/bin/sbsign",
- "--key", "@signingKey@",
- "--cert", "@signingCertificate@",
- "--output", f"{tmpdir}/signed",
- src
- ])
-
- # Very likely to move across filesystems, so use
- # shutil.move over os.rename.
- shutil.move(f"{tmpdir}/signed", f"{output}.tmp")
- try:
- sbverify(f"{output}.tmp")
- os.rename(f"{output}.tmp", output)
- except:
- os.unlink(f"{output}.tmp")
- raise
-
-def sbverify(filename):
- subprocess.check_call([
- "@sbsigntool@/bin/sbverify",
- "--cert", "@signingCertificate@",
- filename,
- ])
-
-
-def mkdir_p(path):
- try:
- os.makedirs(path)
- except OSError as e:
- if e.errno != errno.EEXIST or not os.path.isdir(path):
- raise
-
-def get_generations(profile=None):
- gen_list = subprocess.check_output([
- "@nix@/bin/nix-env",
- "--list-generations",
- "-p",
- "/nix/var/nix/profiles/%s" % ("system-profiles/" + profile if profile else "system"),
- "--option", "build-users-group", ""],
- universal_newlines=True)
- gen_lines = gen_list.split('\n')
- gen_lines.pop()
-
- configurationLimit = @configurationLimit@
- return [ (profile, int(line.split()[0])) for line in gen_lines ][-configurationLimit:]
-
-def remove_old_entries(gens):
- rex_profile = re.compile("^@efiSysMountPoint@/loader/entries/nixos-(.*)-generation-.*\.conf$")
- rex_generation = re.compile("^@efiSysMountPoint@/loader/entries/nixos.*-generation-(.*)\.conf$")
- known_paths = []
- for gen in gens:
- known_paths.append(copy_from_profile(*gen, "kernel", True))
- known_paths.append(copy_from_profile(*gen, "initrd", True))
- known_paths.append("@efiSysMountPoint@/%s" % sb_efi_file_name_relative(*gen))
-
- for path in glob.iglob("@efiSysMountPoint@/loader/entries/nixos*-generation-[1-9]*.conf"):
- try:
- if rex_profile.match(path):
- prof = rex_profile.sub(r"\1", path)
- else:
- prof = "system"
- gen = int(rex_generation.sub(r"\1", path))
- if not (prof, gen) in gens:
- os.unlink(path)
- except ValueError:
- pass
- for path in glob.iglob("@efiSysMountPoint@/efi/nixos/*"):
- if not path in known_paths and not os.path.isdir(path):
- os.unlink(path)
-
-def get_profiles():
- if os.path.isdir("/nix/var/nix/profiles/system-profiles/"):
- return [x
- for x in os.listdir("/nix/var/nix/profiles/system-profiles/")
- if not x.endswith("-link")]
- else:
- return []
-
-def main():
- parser = argparse.ArgumentParser(description='Update NixOS-related systemd-boot files')
- parser.add_argument('default_config', metavar='DEFAULT-CONFIG', help='The default NixOS config to boot')
- args = parser.parse_args()
-
- try:
- with open("/etc/machine-id") as machine_file:
- machine_id = machine_file.readlines()[0]
- except IOError as e:
- if e.errno != errno.ENOENT:
- raise
- # Since systemd version 232 a machine ID is required and it might not
- # be there on newly installed systems, so let's generate one so that
- # bootctl can find it and we can also pass it to write_entry() later.
- cmd = ["@systemd@/bin/systemd-machine-id-setup", "--print"]
- machine_id = subprocess.check_output(cmd).rstrip()
-
- if os.getenv("NIXOS_INSTALL_GRUB") == "1":
- warnings.warn("NIXOS_INSTALL_GRUB env var deprecated, use NIXOS_INSTALL_BOOTLOADER", DeprecationWarning)
- os.environ["NIXOS_INSTALL_BOOTLOADER"] = "1"
-
- if os.getenv("NIXOS_INSTALL_BOOTLOADER") == "1":
- # bootctl uses fopen() with modes "wxe" and fails if the file exists.
- if os.path.exists("@efiSysMountPoint@/loader/loader.conf"):
- os.unlink("@efiSysMountPoint@/loader/loader.conf")
-
- if "@canTouchEfiVariables@" == "1":
- subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "install"])
- else:
- subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "--no-variables", "install"])
-
- mkdir_p("@efiSysMountPoint@/efi/nixos")
- mkdir_p("@efiSysMountPoint@/loader/entries")
-
- if "@signed@" == "1":
- sign_path("@efiSysMountPoint@/EFI/BOOT/BOOTX64.EFI", "@efiSysMountPoint@/EFI/BOOT/BOOTX64.EFI")
- sign_path("@efiSysMountPoint@/EFI/systemd/systemd-bootx64.efi", "@efiSysMountPoint@/EFI/systemd/systemd-bootx64.efi")
-
- gens = get_generations()
- for profile in get_profiles():
- gens += get_generations(profile)
- remove_old_entries(gens)
- for gen in gens:
- if "@signed@"== "1":
- write_secureboot_entry(*gen, machine_id)
- else:
- write_entry(*gen, machine_id)
- if os.readlink(system_dir(*gen)) == args.default_config:
- write_loader_conf(*gen)
-
- memtest_entry_file = "@efiSysMountPoint@/loader/entries/memtest86.conf"
- if os.path.exists(memtest_entry_file):
- os.unlink(memtest_entry_file)
- shutil.rmtree("@efiSysMountPoint@/efi/memtest86", ignore_errors=True)
- if "@memtest86@" != "":
- mkdir_p("@efiSysMountPoint@/efi/memtest86")
- for path in glob.iglob("@memtest86@/*"):
- if os.path.isdir(path):
- shutil.copytree(path, os.path.join("@efiSysMountPoint@/efi/memtest86", os.path.basename(path)))
- else:
- shutil.copy(path, "@efiSysMountPoint@/efi/memtest86/")
-
- memtest_entry_file = "@efiSysMountPoint@/loader/entries/memtest86.conf"
- memtest_entry_file_tmp_path = "%s.tmp" % memtest_entry_file
- with open(memtest_entry_file_tmp_path, 'w') as f:
- f.write(MEMTEST_BOOT_ENTRY)
- os.rename(memtest_entry_file_tmp_path, memtest_entry_file)
-
- # Since fat32 provides little recovery facilities after a crash,
- # it can leave the system in an unbootable state, when a crash/outage
- # happens shortly after an update. To decrease the likelihood of this
- # event sync the efi filesystem after each update.
- rc = libc.syncfs(os.open("@efiSysMountPoint@", os.O_RDONLY))
- if rc != 0:
- print("could not sync @efiSysMountPoint@: {}".format(os.strerror(rc)), file=sys.stderr)
-
-if __name__ == '__main__':
- main()
diff --git a/sets/secureBoot.nix b/sets/secureBoot.nix
index e681b9a..2d46768 100644
--- a/sets/secureBoot.nix
+++ b/sets/secureBoot.nix
@@ -4,6 +4,8 @@
imports = [ inputs.lanzaboote.nixosModules.lanzaboote ];
boot.loader.systemd-boot.enable = false;
+ environment.systemPackages = [ pkgs.sbctl ];
+
boot.lanzaboote = {
enable = true;
pkiBundle = "/etc/secureboot";
diff --git a/system/starlight/boot-config.nix b/system/starlight/boot-config.nix
index 549330f..b966572 100644
--- a/system/starlight/boot-config.nix
+++ b/system/starlight/boot-config.nix
@@ -8,18 +8,11 @@ let
"x-systemd.mount-timeout=5s"
];
in {
- imports = [ ../../externals/systemd-boot-secure ];
boot = {
kernelPackages = pkgs-unstable.linuxPackages_latest;
extraModulePackages = with config.boot.kernelPackages; [ v4l2loopback ];
kernel.sysctl."vm.swappiness" = 5;
tmp.cleanOnBoot = true;
- loader.systemd-boot-secure = {
- enable = true;
- signed = true;
- signing-key = "/root/secure-boot/db.key";
- signing-certificate = "/root/secure-boot/db.crt";
- };
# Encrypted drives
initrd.luks = {
diff --git a/system/starlight/default.nix b/system/starlight/default.nix
index e75ae5f..ab902bf 100644
--- a/system/starlight/default.nix
+++ b/system/starlight/default.nix
@@ -15,6 +15,7 @@
../../sets/krb5.nix
../../sets/music.nix
../../sets/radio.nix
+ ../../sets/secureBoot.nix
../../sets/sshd.nix
../../sets/virtualization.nix
../../sets/workstation.nix