diff --git a/modules/config/minimal-modules.nix b/modules/config/minimal-modules.nix index b3a03f6..45bdb1f 100644 --- a/modules/config/minimal-modules.nix +++ b/modules/config/minimal-modules.nix @@ -1,19 +1,15 @@ -{ config, lib, ... }: { - - options.boot.kernel.minimalModules = lib.mkEnableOption "minimal kernel modules"; - - config = lib.mkIf config.boot.kernel.minimalModules { - - # Don't include kernel or its modules in rootfs - boot.kernel.enable = false; - boot.modprobeConfig.enable = false; - boot.bootspec.enable = false; - system.build = { inherit (config.boot.kernelPackages) kernel; }; - system.modulesTree = [ config.boot.kernelPackages.kernel ] ++ config.boot.extraModulePackages; - - # Modules must be loaded by initrd - boot.initrd.kernelModules = config.boot.kernelModules; - +{ config, ... }: +{ + boot = { + bootspec.enable = false; + initrd.kernelModules = config.boot.kernelModules; + kernel.enable = false; # No kernel or modules in the rootfs + modprobeConfig.enable = false; }; + system.build = { + inherit (config.boot.kernelPackages) kernel; + }; + + system.modulesTree = [ config.boot.kernelPackages.kernel ] ++ config.boot.extraModulePackages; } diff --git a/modules/config/minimal-system.nix b/modules/config/minimal-system.nix index 9f01a9e..e77476b 100644 --- a/modules/config/minimal-system.nix +++ b/modules/config/minimal-system.nix @@ -1,17 +1,26 @@ -{ config, lib, pkgs, ... }: { +{ ... }: +{ - nixpkgs.overlays = [(self: super: { + nixpkgs.overlays = [ + (final: prev: { - systemdUkify = self.callPackage ../../pkgs/systemd-ukify.nix { inherit super; }; + composefs = final.callPackage ../../pkgs/composefs.nix { inherit prev; }; + qemu_tiny = final.callPackage ../../pkgs/qemu.nix { inherit prev; }; + systemdUkify = final.callPackage ../../pkgs/systemd-ukify.nix { inherit prev; }; - qemu_tiny = self.callPackage ../../pkgs/qemu.nix { inherit super; }; - - composefs = self.callPackage ../../pkgs/composefs.nix { inherit super; }; - - # dbus = super.dbus.override { + # # FIXME: Revisit + refine these below in a future image minimization effort + # + # util-linux = prev.util-linux.override { + # ncursesSupport = false; + # nlsSupport = false; + # }; + # + # dbus = prev.dbus.override { # enableSystemd = false; + # x11Support = false; # }; - })]; + }) + ]; } diff --git a/modules/default.nix b/modules/default.nix index 5f09be2..0a1a5e0 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -1,8 +1,6 @@ { - imports = [ ./config/minimal-modules.nix ./config/minimal-system.nix ]; - } diff --git a/modules/image/disk/:w b/modules/image/disk/:w new file mode 100644 index 0000000..2862e18 --- /dev/null +++ b/modules/image/disk/:w @@ -0,0 +1,128 @@ +{ + config, + lib, + pkgs, + ... +}: +{ + + imports = [ + ./updater.nix + ./ssh.nix + ./builder.nix + ./veritysetup.nix + ]; + + system.build.updatePackage = pkgs.runCommand "update-package" { } '' + mkdir "$out" + cd "$out" + cp "${config.system.build.image}"/* . + ${pkgs.coreutils}/bin/sha256sum * > SHA256SUMS + ''; + + boot.initrd.systemd.enable = true; + + boot.initrd.systemd.repart.enable = true; + systemd.repart.partitions = { + "10-esp" = { + Type = "esp"; + Format = "vfat"; + SizeMinBytes = "96M"; + SizeMaxBytes = "96M"; + }; + "20-root-verity-a" = { + Type = "root-verity"; + SizeMinBytes = "64M"; + SizeMaxBytes = "64M"; + }; + "22-root-a" = { + Type = "root"; + SizeMinBytes = "512M"; + SizeMaxBytes = "512M"; + }; + "30-root-verity-b" = { + Type = "root-verity"; + SizeMinBytes = "64M"; + SizeMaxBytes = "64M"; + Label = "_empty"; + ReadOnly = 1; + }; + "32-root-b" = { + Type = "root"; + SizeMinBytes = "512M"; + SizeMaxBytes = "512M"; + Label = "_empty"; + ReadOnly = 1; + }; + "40-home" = { + Type = "home"; + Format = "btrfs"; + SizeMinBytes = "512M"; + Encrypt = "tpm2"; + }; + }; + + boot.initrd.compressor = "zstd"; + boot.initrd.compressorArgs = [ "-8" ]; + + boot.loader.grub.enable = false; + + boot.initrd.luks.forceLuksSupportInInitrd = true; + boot.initrd.kernelModules = [ + "dm_mod" + "dm_crypt" + ] ++ config.boot.initrd.luks.cryptoModules; + + boot.initrd.supportedFilesystems = { + btrfs = true; + erofs = true; + }; + + system.etc.overlay.mutable = false; + users.mutableUsers = false; + + boot.initrd.systemd.services.systemd-repart.after = lib.mkForce [ "sysroot.mount" ]; + boot.initrd.systemd.services.systemd-repart.requires = [ "sysroot.mount" ]; + + boot.kernelParams = [ + "rootfstype=erofs" + "rootflags=ro" + "roothash=${config.system.build.verityRootHash}" + ]; + + fileSystems."/var" = { + fsType = "tmpfs"; + options = [ "mode=0755" ]; + }; + + # Required to mount the efi partition + boot.kernelModules = [ + "vfat" + "nls_cp437" + "nls_iso8859-1" + ]; + + # Store SSH host keys on /home since /etc is read-only + services.openssh.hostKeys = [ + { + path = "/home/.ssh/ssh_host_ed25519_key"; + type = "ed25519"; + } + ]; + + environment.etc."machine-id" = { + text = ""; + mode = "0755"; + }; + + boot.initrd.systemd.services.systemd-repart.serviceConfig.Environment = [ + "SYSTEMD_REPART_MKFS_OPTIONS_BTRFS=--nodiscard" + ]; + + # Refuse to boot on mount failure + systemd.targets."sysinit".requires = [ "local-fs.target" ]; + + # Make sure home gets mounted + systemd.targets."local-fs".requires = [ "home.mount" ]; + +} diff --git a/modules/image/disk/builder.nix b/modules/image/disk/builder.nix index 4824e50..280b30e 100644 --- a/modules/image/disk/builder.nix +++ b/modules/image/disk/builder.nix @@ -1,5 +1,10 @@ -{ config, lib, pkgs, ... }: let - +{ + config, + lib, + pkgs, + ... +}: +let inherit (pkgs.stdenv.hostPlatform) efiArch; initialPartitions = { @@ -15,6 +20,7 @@ SplitName = "root"; }; }; + "20-root-verity" = { repartConfig = { Type = "root-verity"; @@ -31,26 +37,30 @@ inherit lib pkgs; system = null; modules = [ - ({ modulesPath, ... }: { - imports = [ - (modulesPath + "/image/repart.nix") - ]; - image.repart = { - name = "verity"; - split = true; - mkfsOptions = lib.mkIf config.image.compress { - erofs = [ "-zlz4hc,level=12" "-Efragments,dedupe,ztailpacking" ]; + ( + { modulesPath, ... }: + { + imports = [ (modulesPath + "/image/repart.nix") ]; + image.repart = { + name = "verity"; + split = true; + mkfsOptions.erofs = [ + "-zlz4hc,level=12" + "-Efragments,dedupe,ztailpacking" + ]; + partitions = initialPartitions; }; - partitions = initialPartitions; - }; - }) + } + ) ]; }; rootPart = "${verityRepart.config.system.build.image}/${verityRepart.config.image.repart.imageFileBasename}.root.raw"; verityPart = "${verityRepart.config.system.build.image}/${verityRepart.config.image.repart.imageFileBasename}.verity.raw"; - verityImgAttrs = builtins.fromJSON (builtins.readFile "${verityRepart.config.system.build.image}/repart-output.json"); + verityImgAttrs = builtins.fromJSON ( + builtins.readFile "${verityRepart.config.system.build.image}/repart-output.json" + ); rootAttrs = builtins.elemAt verityImgAttrs 0; verityAttrs = builtins.elemAt verityImgAttrs 1; @@ -61,10 +71,8 @@ finalPartitions = { "10-esp" = { contents = { - "/EFI/BOOT/BOOT${lib.toUpper efiArch}.EFI".source = - "${pkgs.systemdUkify}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi"; - "/EFI/Linux/${config.system.boot.loader.ukiFile}".source = - "${config.system.build.uki}/${config.system.boot.loader.ukiFile}"; + "/EFI/BOOT/BOOT${lib.toUpper efiArch}.EFI".source = "${pkgs.systemdUkify}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi"; + "/EFI/Linux/${config.system.boot.loader.ukiFile}".source = "${config.system.build.uki}/${config.system.boot.loader.ukiFile}"; "/default-ssh-authorized-keys.txt" = lib.mkIf config.system.image.sshKeys.enable { source = pkgs.writeText "ssh-keys" (lib.concatStringsSep "\n" config.system.image.sshKeys.keys); }; @@ -106,48 +114,47 @@ inherit lib pkgs; system = null; modules = [ - ({ modulesPath, ... }: { - imports = [ - (modulesPath + "/image/repart.nix") - ]; - image.repart = { - name = "${config.system.image.id}"; - partitions = finalPartitions; - }; - }) + ( + { modulesPath, ... }: + { + imports = [ (modulesPath + "/image/repart.nix") ]; + image.repart = { + name = "${config.system.image.id}"; + partitions = finalPartitions; + }; + } + ) ]; }; -in { - - options.image.compress = lib.mkEnableOption "image compression" // { - default = true; - }; +in +{ config.system.build = { - inherit verityRootHash; - image = (pkgs.linkFarm "image-release" [ - { - name = "${config.system.image.id}_${config.system.image.version}.efi"; - path = "${config.system.build.uki}/${config.system.boot.loader.ukiFile}"; - } - { - name = "${config.system.image.id}_${config.system.image.version}_${verityUuid}.verity"; - path = "${verityRepart.config.system.build.image}/${verityRepart.config.image.repart.imageFileBasename}.verity.raw"; - } - { - name = "${config.system.image.id}_${config.system.image.version}_${rootUuid}.root"; - path = "${verityRepart.config.system.build.image}/${verityRepart.config.image.repart.imageFileBasename}.root.raw"; - } - { - name = "${config.system.image.id}_${config.system.image.version}.img"; - path = "${finalRepart.config.system.build.image}/${finalRepart.config.image.repart.imageFileBasename}.raw"; - } - ]) // { - imageFile = "${config.system.image.id}_${config.system.image.version}.img"; - }; + image = + (pkgs.linkFarm "image-release" [ + { + name = "${config.system.image.id}_${config.system.image.version}.efi"; + path = "${config.system.build.uki}/${config.system.boot.loader.ukiFile}"; + } + { + name = "${config.system.image.id}_${config.system.image.version}_${verityUuid}.verity"; + path = "${verityRepart.config.system.build.image}/${verityRepart.config.image.repart.imageFileBasename}.verity.raw"; + } + { + name = "${config.system.image.id}_${config.system.image.version}_${rootUuid}.root"; + path = "${verityRepart.config.system.build.image}/${verityRepart.config.image.repart.imageFileBasename}.root.raw"; + } + { + name = "${config.system.image.id}_${config.system.image.version}.img"; + path = "${finalRepart.config.system.build.image}/${finalRepart.config.image.repart.imageFileBasename}.raw"; + } + ]) + // { + imageFile = "${config.system.image.id}_${config.system.image.version}.img"; + }; }; diff --git a/modules/image/disk/default.nix b/modules/image/disk/default.nix index b7b3be2..2862e18 100644 --- a/modules/image/disk/default.nix +++ b/modules/image/disk/default.nix @@ -1,4 +1,10 @@ -{ config, lib, pkgs, modulesPath, ... }: { +{ + config, + lib, + pkgs, + ... +}: +{ imports = [ ./updater.nix @@ -7,9 +13,9 @@ ./veritysetup.nix ]; - system.build.updatePackage = pkgs.runCommand "update-package" {} '' - mkdir $out - cd $out + system.build.updatePackage = pkgs.runCommand "update-package" { } '' + mkdir "$out" + cd "$out" cp "${config.system.build.image}"/* . ${pkgs.coreutils}/bin/sha256sum * > SHA256SUMS ''; @@ -57,12 +63,15 @@ }; boot.initrd.compressor = "zstd"; - boot.initrd.compressorArgs = [ "-6" ]; + boot.initrd.compressorArgs = [ "-8" ]; boot.loader.grub.enable = false; boot.initrd.luks.forceLuksSupportInInitrd = true; - boot.initrd.kernelModules = [ "dm_mod" "dm_crypt" ] ++ config.boot.initrd.luks.cryptoModules; + boot.initrd.kernelModules = [ + "dm_mod" + "dm_crypt" + ] ++ config.boot.initrd.luks.cryptoModules; boot.initrd.supportedFilesystems = { btrfs = true; @@ -75,7 +84,11 @@ boot.initrd.systemd.services.systemd-repart.after = lib.mkForce [ "sysroot.mount" ]; boot.initrd.systemd.services.systemd-repart.requires = [ "sysroot.mount" ]; - boot.kernelParams = [ "rootfstype=erofs" "rootflags=ro" "roothash=${config.system.build.verityRootHash}" ]; + boot.kernelParams = [ + "rootfstype=erofs" + "rootflags=ro" + "roothash=${config.system.build.verityRootHash}" + ]; fileSystems."/var" = { fsType = "tmpfs"; @@ -83,19 +96,25 @@ }; # Required to mount the efi partition - boot.kernelModules = [ "vfat" "nls_cp437" "nls_iso8859-1" ]; + boot.kernelModules = [ + "vfat" + "nls_cp437" + "nls_iso8859-1" + ]; # Store SSH host keys on /home since /etc is read-only - services.openssh.hostKeys = [{ - path = "/home/.ssh/ssh_host_ed25519_key"; - type = "ed25519"; - }]; + services.openssh.hostKeys = [ + { + path = "/home/.ssh/ssh_host_ed25519_key"; + type = "ed25519"; + } + ]; environment.etc."machine-id" = { text = ""; mode = "0755"; }; - + boot.initrd.systemd.services.systemd-repart.serviceConfig.Environment = [ "SYSTEMD_REPART_MKFS_OPTIONS_BTRFS=--nodiscard" ]; diff --git a/modules/image/disk/ssh.nix b/modules/image/disk/ssh.nix index b8fb948..3f6b3c4 100644 --- a/modules/image/disk/ssh.nix +++ b/modules/image/disk/ssh.nix @@ -1,17 +1,20 @@ -{ config, lib, ... }: { - +{ config, lib, ... }: +{ options.system.image.sshKeys = { enable = lib.mkEnableOption "provisioning of default SSH keys from ESP"; keys = lib.mkOption { type = lib.types.listOf lib.types.singleLineStr; - default = []; + default = [ ]; }; }; config = lib.mkIf config.system.image.sshKeys.enable { assertions = [ - { assertion = config.services.openssh.enable; message = "OpenSSH must be enabled to preseed authorized keys"; } + { + assertion = config.services.openssh.enable; + message = "OpenSSH must be enabled to preseed authorized keys"; + } ]; systemd.services."default-ssh-keys" = { @@ -19,9 +22,16 @@ mkdir -p /home/admin/.ssh/ cat /efi/default-ssh-authorized-keys.txt >> /home/admin/.ssh/authorized_keys ''; - wantedBy = [ "sshd.service" "sshd.socket" ]; + wantedBy = [ + "sshd.service" + "sshd.socket" + ]; unitConfig = { - ConditionPathExists = [ "/home/admin" "!/home/admin/.ssh/authorized_keys" "/efi/default-ssh-authorized-keys.txt" ]; + ConditionPathExists = [ + "/home/admin" + "!/home/admin/.ssh/authorized_keys" + "/efi/default-ssh-authorized-keys.txt" + ]; }; }; diff --git a/modules/image/disk/veritysetup.nix b/modules/image/disk/veritysetup.nix index 9ac29b4..1505b45 100644 --- a/modules/image/disk/veritysetup.nix +++ b/modules/image/disk/veritysetup.nix @@ -1,7 +1,12 @@ -{ config, lib, ... }: { +{ config, lib, ... }: +{ options.boot.initrd.systemd.root = lib.mkOption { - type = lib.types.enum [ "fstab" "gpt-auto" "" ]; + type = lib.types.enum [ + "fstab" + "gpt-auto" + "" + ]; }; config.boot.initrd = { @@ -11,7 +16,7 @@ "dm_verity" ]; - systemd = { + systemd = { # Required to activate systemd-fstab-generator root = ""; diff --git a/modules/profiles/base.nix b/modules/profiles/base.nix index 5561bde..5cb46f5 100644 --- a/modules/profiles/base.nix +++ b/modules/profiles/base.nix @@ -1,6 +1,11 @@ -{ config, lib, pkgs, modulesPath, ... }: { - - # Start out with a minimal system +{ + config, + lib, + pkgs, + modulesPath, + ... +}: +{ imports = [ (modulesPath + "/profiles/image-based-appliance.nix") (modulesPath + "/profiles/perlless.nix") @@ -32,22 +37,6 @@ system.etc.overlay.mutable = lib.mkDefault false; users.mutableUsers = lib.mkDefault false; - users.allowNoPasswordLogin = true; - - programs.nano.enable = false; - - boot.tmp.useTmpfs = true; - - # Replace sudo with doas - security.sudo.enable = lib.mkDefault false; - security.doas.enable = lib.mkDefault true; - - environment.systemPackages = with pkgs; [ - (lib.mkIf config.security.doas.enable doas-sudo-shim) - iotop - ]; - - services.openssh.settings.PasswordAuthentication = lib.mkDefault false; systemd.watchdog = lib.mkDefault { runtimeTime = "10s"; @@ -56,27 +45,42 @@ zramSwap.enable = true; - i18n.supportedLocales = [ - "en_US.UTF-8/UTF-8" - ]; + services.openssh.settings.PasswordAuthentication = lib.mkDefault false; - boot.consoleLogLevel = lib.mkDefault 1; + users.allowNoPasswordLogin = true; + security.sudo.enable = lib.mkDefault false; + security.polkit = { + enable = true; + extraConfig ='' + polkit.addRule(function(action, subject) { + if (subject.isInGroup("wheel")) { + return polkit.Result.YES; + } + }); + ''; + }; + + i18n.supportedLocales = [ "en_US.UTF-8/UTF-8" ]; + + systemd.enableEmergencyMode = false; + console.enable = false; systemd.services."getty@tty1".enable = lib.mkDefault false; systemd.services."autovt@".enable = lib.mkDefault false; - systemd.enableEmergencyMode = false; - - boot.kernelParams = [ "panic=1" "boot.panic_on_fail" "nomodeset" ]; + boot.tmp.useTmpfs = true; + boot.consoleLogLevel = lib.mkDefault 1; + boot.kernelParams = [ + "panic=1" + "boot.panic_on_fail" + "nomodeset" + ]; + # This is vi country + programs.nano.enable = false; programs.vim.enable = true; programs.vim.defaultEditor = lib.mkDefault true; + # Logging services.journald.storage = "volatile"; - - console.enable = false; - - networking.useNetworkd = true; - systemd.network.wait-online.enable = lib.mkDefault false; - } diff --git a/modules/profiles/network.nix b/modules/profiles/network.nix index 36d6763..d090994 100644 --- a/modules/profiles/network.nix +++ b/modules/profiles/network.nix @@ -1,15 +1,19 @@ -{ lib, ... }: { - +{ lib, ... }: +{ # Use TCP BBR boot.kernel.sysctl = { "net.core.default_qdisc" = "fq"; "net.ipv4.tcp_congestion_control" = "bbr"; }; - # Use nftables + services.resolved.extraConfig = '' + DNSStubListener=no + ''; + + networking.firewall.enable = false; + networking.nftables.enable = lib.mkDefault true; - # Use systemd-networkd networking.useNetworkd = true; systemd.network.wait-online.enable = true; diff --git a/modules/profiles/server.nix b/modules/profiles/server.nix index 1fd9775..7a828f3 100644 --- a/modules/profiles/server.nix +++ b/modules/profiles/server.nix @@ -1,14 +1,17 @@ -{ config, lib, pkgs, modulesPath, ... }: { +{ + modulesPath, + ... +}: +{ imports = [ (modulesPath + "/profiles/minimal.nix") ./network.nix ]; - boot.kernel.minimalModules = true; - - # system.etc.overlay.mutable = true; - # users.mutableUsers = true; + boot.kernel.sysctl = { + "net.ipv4.ip_unprivileged_port_start" = 0; + }; users.users."admin" = { isNormalUser = true; @@ -16,23 +19,18 @@ extraGroups = [ "wheel" ]; }; - # perlless activation doesn't seem to support subuid / subgid yet - environment.etc."subuid" = { - text = '' - admin:100000:65536 - ''; - mode = "0644"; - }; + environment.etc = { + subuid = { + text = "admin:100000:65536"; + mode = "0644"; + }; - environment.etc."subgid" = { - text = '' - admin:100000:65536 - ''; - mode = "0644"; + subgid = { + text = "admin:100000:65536"; + mode = "0644"; + }; }; - security.doas.wheelNeedsPassword = false; - services.openssh.enable = true; system.image.sshKeys.enable = true; system.image.sshKeys.keys = [ @@ -42,15 +40,4 @@ ]; virtualisation.podman.enable = true; - - boot.kernel.sysctl = { - "net.ipv4.ip_unprivileged_port_start" = 0; - }; - - networking.firewall.enable = false; - - services.resolved.extraConfig = '' - DNSStubListener=no - ''; - } diff --git a/pkgs/composefs.nix b/pkgs/composefs.nix index f499a40..91e8443 100644 --- a/pkgs/composefs.nix +++ b/pkgs/composefs.nix @@ -1,5 +1,5 @@ -{ super, ... }: +{ prev, ... }: -super.composefs.overrideAttrs (final: prev: { +prev.composefs.overrideAttrs (final: prev: { doCheck = false; }) diff --git a/pkgs/openssh.nix b/pkgs/openssh.nix index afa3da1..91de381 100644 --- a/pkgs/openssh.nix +++ b/pkgs/openssh.nix @@ -1,6 +1,6 @@ -{ super, ... }: +{ prev, ... }: -super.openssh.overrideAttrs (final: prev: { +prev.openssh.overrideAttrs (final: prev: { doCheck = false; doInstallCheck = false; dontCheck = true; diff --git a/pkgs/qemu.nix b/pkgs/qemu.nix index 7f595f7..93e67dd 100644 --- a/pkgs/qemu.nix +++ b/pkgs/qemu.nix @@ -1,6 +1,6 @@ -{ super, ... }: +{ prev, pkgs, ... }: -(super.qemu_test.override { +(prev.qemu_test.override { enableDocs = false; capstoneSupport = false; guestAgentSupport = false; @@ -11,8 +11,8 @@ hostCpuTargets = [ "x86_64-softmmu" ]; }).overrideDerivation (old: { postFixup = '' - rm -r $out/share/icons - cp "${pkgs.OVMF.fd + "/FV/OVMF.fd"}" $out/share/qemu/ + rm -r "$out/share/icons" + cp "${pkgs.OVMF.fd + "/FV/OVMF.fd"}" "$out/share/qemu/" ''; configureFlags = old.configureFlags ++ [ "--disable-tcg" diff --git a/pkgs/systemd-ukify.nix b/pkgs/systemd-ukify.nix index 0ca6881..b8e9d55 100644 --- a/pkgs/systemd-ukify.nix +++ b/pkgs/systemd-ukify.nix @@ -1,6 +1,6 @@ -{ super, ... }: +{ prev, ... }: -super.systemd.override { +prev.systemd.override { withAcl = false; withAnalyze = false; withApparmor = false; diff --git a/pkgs/systemd.nix b/pkgs/systemd.nix index 881fc16..2d52e9a 100644 --- a/pkgs/systemd.nix +++ b/pkgs/systemd.nix @@ -1,6 +1,6 @@ -{ super, ... }: +{ prev, ... }: -super.systemd.override { +prev.systemd.override { withAcl = false; withApparmor = false; withDocumentation = false;