Compare commits

..

1 commit

Author SHA1 Message Date
a8982182b3
WIP: next step on image build 2024-11-14 17:08:39 +01:00
16 changed files with 348 additions and 181 deletions

View file

@ -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;
}

View file

@ -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;
# };
})];
})
];
}

View file

@ -1,8 +1,6 @@
{
imports = [
./config/minimal-modules.nix
./config/minimal-system.nix
];
}

128
modules/image/disk/:w Normal file
View file

@ -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" ];
}

View file

@ -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";
};
};

View file

@ -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"
];

View file

@ -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"
];
};
};

View file

@ -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 = "";

View file

@ -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;
}

View file

@ -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;

View file

@ -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
'';
}

View file

@ -1,5 +1,5 @@
{ super, ... }:
{ prev, ... }:
super.composefs.overrideAttrs (final: prev: {
prev.composefs.overrideAttrs (final: prev: {
doCheck = false;
})

View file

@ -1,6 +1,6 @@
{ super, ... }:
{ prev, ... }:
super.openssh.overrideAttrs (final: prev: {
prev.openssh.overrideAttrs (final: prev: {
doCheck = false;
doInstallCheck = false;
dontCheck = true;

View file

@ -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"

View file

@ -1,6 +1,6 @@
{ super, ... }:
{ prev, ... }:
super.systemd.override {
prev.systemd.override {
withAcl = false;
withAnalyze = false;
withApparmor = false;

View file

@ -1,6 +1,6 @@
{ super, ... }:
{ prev, ... }:
super.systemd.override {
prev.systemd.override {
withAcl = false;
withApparmor = false;
withDocumentation = false;