diff --git a/modules/config/minimal-modules.nix b/modules/config/minimal-modules.nix index 45bdb1f..b3a03f6 100644 --- a/modules/config/minimal-modules.nix +++ b/modules/config/minimal-modules.nix @@ -1,15 +1,19 @@ -{ config, ... }: -{ - boot = { - bootspec.enable = false; - initrd.kernelModules = config.boot.kernelModules; - kernel.enable = false; # No kernel or modules in the rootfs - modprobeConfig.enable = false; +{ 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; + }; - 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 e77476b..9f01a9e 100644 --- a/modules/config/minimal-system.nix +++ b/modules/config/minimal-system.nix @@ -1,26 +1,17 @@ -{ ... }: -{ +{ config, lib, pkgs, ... }: { - nixpkgs.overlays = [ - (final: prev: { + nixpkgs.overlays = [(self: 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; }; + systemdUkify = self.callPackage ../../pkgs/systemd-ukify.nix { inherit super; }; - # # 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 { + qemu_tiny = self.callPackage ../../pkgs/qemu.nix { inherit super; }; + + composefs = self.callPackage ../../pkgs/composefs.nix { inherit super; }; + + # dbus = super.dbus.override { # enableSystemd = false; - # x11Support = false; # }; - }) - ]; + })]; } diff --git a/modules/default.nix b/modules/default.nix index 0a1a5e0..5f09be2 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -1,6 +1,8 @@ { + imports = [ ./config/minimal-modules.nix ./config/minimal-system.nix ]; + } diff --git a/modules/image/disk/:w b/modules/image/disk/:w deleted file mode 100644 index 2862e18..0000000 --- a/modules/image/disk/:w +++ /dev/null @@ -1,128 +0,0 @@ -{ - 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 280b30e..4824e50 100644 --- a/modules/image/disk/builder.nix +++ b/modules/image/disk/builder.nix @@ -1,10 +1,5 @@ -{ - config, - lib, - pkgs, - ... -}: -let +{ config, lib, pkgs, ... }: let + inherit (pkgs.stdenv.hostPlatform) efiArch; initialPartitions = { @@ -20,7 +15,6 @@ let SplitName = "root"; }; }; - "20-root-verity" = { repartConfig = { Type = "root-verity"; @@ -37,30 +31,26 @@ let inherit lib pkgs; system = null; modules = [ - ( - { modulesPath, ... }: - { - imports = [ (modulesPath + "/image/repart.nix") ]; - image.repart = { - name = "verity"; - split = true; - mkfsOptions.erofs = [ - "-zlz4hc,level=12" - "-Efragments,dedupe,ztailpacking" - ]; - partitions = initialPartitions; + ({ 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" ]; }; - } - ) + 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; @@ -71,8 +61,10 @@ let 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); }; @@ -114,47 +106,48 @@ let 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 -{ +in { + + options.image.compress = lib.mkEnableOption "image compression" // { + default = true; + }; 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 2862e18..b7b3be2 100644 --- a/modules/image/disk/default.nix +++ b/modules/image/disk/default.nix @@ -1,10 +1,4 @@ -{ - config, - lib, - pkgs, - ... -}: -{ +{ config, lib, pkgs, modulesPath, ... }: { imports = [ ./updater.nix @@ -13,9 +7,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 ''; @@ -63,15 +57,12 @@ }; boot.initrd.compressor = "zstd"; - boot.initrd.compressorArgs = [ "-8" ]; + boot.initrd.compressorArgs = [ "-6" ]; 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; @@ -84,11 +75,7 @@ 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"; @@ -96,25 +83,19 @@ }; # 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 3f6b3c4..b8fb948 100644 --- a/modules/image/disk/ssh.nix +++ b/modules/image/disk/ssh.nix @@ -1,20 +1,17 @@ -{ 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" = { @@ -22,16 +19,9 @@ 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 1505b45..9ac29b4 100644 --- a/modules/image/disk/veritysetup.nix +++ b/modules/image/disk/veritysetup.nix @@ -1,12 +1,7 @@ -{ 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 = { @@ -16,7 +11,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 5cb46f5..5561bde 100644 --- a/modules/profiles/base.nix +++ b/modules/profiles/base.nix @@ -1,11 +1,6 @@ -{ - config, - lib, - pkgs, - modulesPath, - ... -}: -{ +{ config, lib, pkgs, modulesPath, ... }: { + + # Start out with a minimal system imports = [ (modulesPath + "/profiles/image-based-appliance.nix") (modulesPath + "/profiles/perlless.nix") @@ -37,6 +32,22 @@ 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"; @@ -45,42 +56,27 @@ zramSwap.enable = true; - services.openssh.settings.PasswordAuthentication = lib.mkDefault false; + i18n.supportedLocales = [ + "en_US.UTF-8/UTF-8" + ]; - users.allowNoPasswordLogin = true; - security.sudo.enable = lib.mkDefault false; + boot.consoleLogLevel = lib.mkDefault 1; - 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; - boot.tmp.useTmpfs = true; - boot.consoleLogLevel = lib.mkDefault 1; - boot.kernelParams = [ - "panic=1" - "boot.panic_on_fail" - "nomodeset" - ]; + systemd.enableEmergencyMode = false; + + 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 d090994..36d6763 100644 --- a/modules/profiles/network.nix +++ b/modules/profiles/network.nix @@ -1,19 +1,15 @@ -{ lib, ... }: -{ +{ lib, ... }: { + # Use TCP BBR boot.kernel.sysctl = { "net.core.default_qdisc" = "fq"; "net.ipv4.tcp_congestion_control" = "bbr"; }; - services.resolved.extraConfig = '' - DNSStubListener=no - ''; - - networking.firewall.enable = false; - + # Use nftables 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 7a828f3..1fd9775 100644 --- a/modules/profiles/server.nix +++ b/modules/profiles/server.nix @@ -1,17 +1,14 @@ -{ - modulesPath, - ... -}: -{ +{ config, lib, pkgs, modulesPath, ... }: { imports = [ (modulesPath + "/profiles/minimal.nix") ./network.nix ]; - boot.kernel.sysctl = { - "net.ipv4.ip_unprivileged_port_start" = 0; - }; + boot.kernel.minimalModules = true; + + # system.etc.overlay.mutable = true; + # users.mutableUsers = true; users.users."admin" = { isNormalUser = true; @@ -19,18 +16,23 @@ extraGroups = [ "wheel" ]; }; - environment.etc = { - subuid = { - text = "admin:100000:65536"; - mode = "0644"; - }; - - subgid = { - text = "admin:100000:65536"; - mode = "0644"; - }; + # perlless activation doesn't seem to support subuid / subgid yet + environment.etc."subuid" = { + text = '' + admin:100000:65536 + ''; + mode = "0644"; }; + environment.etc."subgid" = { + text = '' + admin:100000:65536 + ''; + mode = "0644"; + }; + + security.doas.wheelNeedsPassword = false; + services.openssh.enable = true; system.image.sshKeys.enable = true; system.image.sshKeys.keys = [ @@ -40,4 +42,15 @@ ]; 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 91e8443..f499a40 100644 --- a/pkgs/composefs.nix +++ b/pkgs/composefs.nix @@ -1,5 +1,5 @@ -{ prev, ... }: +{ super, ... }: -prev.composefs.overrideAttrs (final: prev: { +super.composefs.overrideAttrs (final: prev: { doCheck = false; }) diff --git a/pkgs/openssh.nix b/pkgs/openssh.nix index 91de381..afa3da1 100644 --- a/pkgs/openssh.nix +++ b/pkgs/openssh.nix @@ -1,6 +1,6 @@ -{ prev, ... }: +{ super, ... }: -prev.openssh.overrideAttrs (final: prev: { +super.openssh.overrideAttrs (final: prev: { doCheck = false; doInstallCheck = false; dontCheck = true; diff --git a/pkgs/qemu.nix b/pkgs/qemu.nix index 93e67dd..7f595f7 100644 --- a/pkgs/qemu.nix +++ b/pkgs/qemu.nix @@ -1,6 +1,6 @@ -{ prev, pkgs, ... }: +{ super, ... }: -(prev.qemu_test.override { +(super.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 b8e9d55..0ca6881 100644 --- a/pkgs/systemd-ukify.nix +++ b/pkgs/systemd-ukify.nix @@ -1,6 +1,6 @@ -{ prev, ... }: +{ super, ... }: -prev.systemd.override { +super.systemd.override { withAcl = false; withAnalyze = false; withApparmor = false; diff --git a/pkgs/systemd.nix b/pkgs/systemd.nix index 2d52e9a..881fc16 100644 --- a/pkgs/systemd.nix +++ b/pkgs/systemd.nix @@ -1,6 +1,6 @@ -{ prev, ... }: +{ super, ... }: -prev.systemd.override { +super.systemd.override { withAcl = false; withApparmor = false; withDocumentation = false;