Image building take 2

We want verity protected partitions as well as encrypted state/data along with verified boot.
This PR integrates Peter Marshall's awesome little Nixlet project as a starting point, especially the nice testing scaffolding will be super helpful! 

https://github.com/petm5/nixlet/
This commit is contained in:
Daniel Lundin 2024-11-11 23:02:38 +01:00
parent da5bdb3d47
commit c59ea29957
Signed by: dln
SSH key fingerprint: SHA256:dQy1Xj3UiqJYpKR5ggQ2bxgz4jCH8IF+k3AB8o0kmdI
39 changed files with 1311 additions and 3272 deletions

View file

@ -0,0 +1,15 @@
{ 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

@ -0,0 +1,26 @@
{ ... }:
{
nixpkgs.overlays = [
(final: prev: {
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; };
# # 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;
# };
})
];
}

6
modules/default.nix Normal file
View file

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

View file

@ -1,44 +0,0 @@
{ config, ... }: {
zramSwap = {
enable = true;
algorithm = "zstd";
memoryPercent = 20;
};
fileSystems = {
"/" = {
fsType = "tmpfs";
options = [
"size=20%"
];
};
"/var" =
let
partConf = config.image.repart.partitions."var".repartConfig;
in
{
device = "/dev/disk/by-partuuid/${partConf.UUID}";
fsType = partConf.Format;
};
"/boot" =
let
partConf = config.image.repart.partitions."esp".repartConfig;
in
{
device = "/dev/disk/by-partuuid/${partConf.UUID}";
fsType = partConf.Format;
};
"/nix/store" =
let
partConf = config.image.repart.partitions."store".repartConfig;
in
{
device = "/dev/disk/by-partlabel/${partConf.Label}";
fsType = partConf.Format;
};
};
}

View file

@ -1,71 +0,0 @@
{
pkgs,
config,
lib,
...
}:
{
boot = {
enableContainers = false;
initrd.systemd.enable = true;
initrd.compressor = "zstd";
# FIXME: Add debug/devel option to switch default kernel params
kernelParams = [
# "quiet"
"console=tty1"
"console=ttyS0,38400"
"systemd.log_level=info"
"systemd.log_target=console"
];
loader.efi.canTouchEfiVariables = true;
loader.grub.enable = false;
loader.systemd-boot.enable = true;
uki.name = "patos";
};
system.image.version = "0.0.1"; # FIXME: Use epoch version.
system.nixos = {
codeName = "Finn";
distroId = "patos";
distroName = "PatOS";
release = "2024-09";
};
system.switch.enable = false;
# Make the current system version visible in the prompt.
programs.bash.promptInit = ''
export PS1="\u@\h (version ${config.system.image.version}) \w $ "
'';
# Not compatible with system.etc.overlay.enable yet.
# users.mutableUsers = false;
services.getty.autologinUser = "root";
# Temporary files
boot.tmp.cleanOnBoot = true;
boot.tmp.useTmpfs = true;
systemd.services.nix-daemon = {
environment.TMPDIR = "/var/tmp";
};
services.journald.extraConfig = ''
SystemMaxUse=10M
'';
services.fstrim.enable = true;
# Debugging
environment.systemPackages = with pkgs; [
(runCommand "systemd-sysupdate" { } ''
mkdir -p $out/bin
ln -s ${config.systemd.package}/lib/systemd/systemd-sysupdate $out/bin
'')
];
system.stateVersion = "24.11";
}

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

@ -0,0 +1,167 @@
{
config,
lib,
pkgs,
...
}:
let
inherit (pkgs.stdenv.hostPlatform) efiArch;
initialPartitions = {
"10-root" = {
storePaths = [ config.system.build.toplevel ];
repartConfig = {
Type = "root";
Minimize = "best";
Format = "erofs";
MakeDirectories = "/home /root /etc /dev /sys /bin /var /proc /run /usr /srv /tmp /mnt /lib /efi";
Verity = "data";
VerityMatchKey = "root";
SplitName = "root";
};
};
"20-root-verity" = {
repartConfig = {
Type = "root-verity";
Minimize = "best";
Verity = "hash";
VerityMatchKey = "root";
SplitName = "verity";
};
};
};
# TODO: We don't need a combined image here - add dry-run flag to repart invocation
verityRepart = import (pkgs.path + "/nixos/lib/eval-config.nix") {
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"
];
};
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"
);
rootAttrs = builtins.elemAt verityImgAttrs 0;
verityAttrs = builtins.elemAt verityImgAttrs 1;
rootUuid = rootAttrs.uuid;
verityUuid = verityAttrs.uuid;
verityRootHash = rootAttrs.roothash;
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}";
"/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);
};
};
repartConfig = {
Type = "esp";
Format = "vfat";
SizeMinBytes = "96M";
SizeMaxBytes = "96M";
SplitName = "-";
};
};
"20-root-verity-a" = {
repartConfig = {
Type = "root-verity";
Label = "verity-${config.system.image.version}";
CopyBlocks = "${verityPart}";
SplitName = "-";
SizeMinBytes = "64M";
SizeMaxBytes = "64M";
UUID = "${verityUuid}";
ReadOnly = 1;
};
};
# TODO: Add signature partition for systemd-nspawn
"22-root-a" = {
repartConfig = {
Type = "root";
Label = "root-${config.system.image.version}";
CopyBlocks = "${rootPart}";
SplitName = "-";
UUID = "${rootUuid}";
ReadOnly = 1;
};
};
};
finalRepart = import (pkgs.path + "/nixos/lib/eval-config.nix") {
inherit lib pkgs;
system = null;
modules = [
(
{ 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;
};
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";
};
};
}

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

@ -0,0 +1,40 @@
{ 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 = [ ];
};
};
config = lib.mkIf config.system.image.sshKeys.enable {
assertions = [
{
assertion = config.services.openssh.enable;
message = "OpenSSH must be enabled to preseed authorized keys";
}
];
systemd.services."default-ssh-keys" = {
script = ''
mkdir -p /home/admin/.ssh/
cat /efi/default-ssh-authorized-keys.txt >> /home/admin/.ssh/authorized_keys
'';
wantedBy = [
"sshd.service"
"sshd.socket"
];
unitConfig = {
ConditionPathExists = [
"/home/admin"
"!/home/admin/.ssh/authorized_keys"
"/efi/default-ssh-authorized-keys.txt"
];
};
};
};
}

View file

@ -0,0 +1,86 @@
{ config, lib, ... }: {
options.system.image.updates = {
enable = lib.mkEnableOption "system updates via systemd-sysupdate" // {
default = config.system.image.updates.url != null;
};
url = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
};
};
config = lib.mkIf config.system.image.updates.enable {
assertions = [
{ assertion = config.system.image.updates.url != null; }
];
systemd.sysupdate.enable = true;
systemd.sysupdate.reboot.enable = lib.mkDefault true;
systemd.sysupdate.transfers = {
"10-uki" = {
Transfer = {
Verify = "no";
};
Source = {
Type = "url-file";
Path = "${config.system.image.updates.url}";
MatchPattern = "${config.boot.uki.name}_@v.efi";
};
Target = {
Type = "regular-file";
Path = "/EFI/Linux";
PathRelativeTo = "esp";
MatchPattern = "${config.boot.uki.name}_@v+@l-@d.efi ${config.boot.uki.name}_@v+@l.efi ${config.boot.uki.name}_@v.efi";
Mode = "0444";
TriesLeft = 3;
TriesDone = 0;
InstancesMax = 2;
};
};
"20-root-verity" = {
Transfer = {
Verify = "no";
};
Source = {
Type = "url-file";
Path = "${config.system.image.updates.url}";
MatchPattern = "${config.system.image.id}_@v_@u.verity";
};
Target = {
Type = "partition";
Path = "auto";
MatchPattern = "verity-@v";
MatchPartitionType = "root-verity";
ReadOnly = 1;
};
};
"22-root" = {
Transfer = {
Verify = "no";
};
Source = {
Type = "url-file";
Path = "${config.system.image.updates.url}";
MatchPattern = "${config.system.image.id}_@v_@u.root";
};
Target = {
Type = "partition";
Path = "auto";
MatchPattern = "root-@v";
MatchPartitionType = "root";
ReadOnly = 1;
};
};
};
systemd.additionalUpstreamSystemUnits = [
"systemd-bless-boot.service"
"boot-complete.target"
];
};
}

View file

@ -0,0 +1,39 @@
{ config, lib, ... }:
{
options.boot.initrd.systemd.root = lib.mkOption {
type = lib.types.enum [
"fstab"
"gpt-auto"
""
];
};
config.boot.initrd = {
kernelModules = [
"dm_mod"
"dm_verity"
];
systemd = {
# Required to activate systemd-fstab-generator
root = "";
additionalUpstreamUnits = [
"veritysetup-pre.target"
"veritysetup.target"
"remote-veritysetup.target"
];
storePaths = [
"${config.boot.initrd.systemd.package}/lib/systemd/systemd-veritysetup"
"${config.boot.initrd.systemd.package}/lib/systemd/system-generators/systemd-veritysetup-generator"
];
};
};
}

View file

@ -1,24 +0,0 @@
{
config,
lib,
pkgs,
...
}:
{
boot.kernelPackages =
let
version = "6.11.2";
in
pkgs.linuxPackagesFor (
pkgs.linuxManualConfig {
version = "${version}-patos1";
modDirVersion = version;
src = pkgs.fetchurl {
url = "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-${version}.tar.xz";
sha256 = "ec9ef7a0b9cebb55940e1ef87a1f9e1004b10456a119dc386bb3e565b0d39c42";
};
configfile = ./generic.config;
allowImportFromDerivation = true;
}
);
}

File diff suppressed because it is too large Load diff

View file

@ -1,18 +0,0 @@
{ modulesPath, ... }:
{
imports = [
"${modulesPath}/profiles/minimal.nix"
];
nix.enable = false;
system.disableInstallerTools = true;
system.etc.overlay.enable = true;
systemd.sysusers.enable = true;
programs.less.lessopen = null;
programs.command-not-found.enable = false;
environment.defaultPackages = [ ];
security.sudo.enable = false;
}

View file

@ -1,17 +0,0 @@
{ config, ... }:
{
networking = {
useNetworkd = true;
hostName = "";
# Easy debugging.
firewall.enable = false;
};
services.resolved = {
fallbackDns = [ ]; # Disable fallback DNS. DNS will fail if resolvers are unconfigured
};
# Faster boot.
systemd.network.wait-online.enable = false;
}

View file

@ -1,103 +0,0 @@
{
config,
pkgs,
lib,
modulesPath,
...
}:
{
imports = [
"${modulesPath}/image/repart.nix"
];
image.repart =
let
efiArch = pkgs.stdenv.hostPlatform.efiArch;
in
{
name = config.boot.uki.name;
split = true;
mkfsOptions = {
erofs = [
# "-zzstd,6" # Zstd compression
# "-zlz4hc,12"
"-T0" # Fixed timestamp for all files
"-C262144" # 256 KiB cluster size
# "-C65536" # 64 KiB cluster size
# "-C1048576" # 1 MiB cluster size
"-Efragments,dedupe,ztailpacking" # Extra features
];
};
partitions = {
"esp" = {
contents = {
"/EFI/BOOT/BOOT${lib.toUpper efiArch}.EFI".source = "${pkgs.systemd}/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}";
# systemd-boot configuration
"/loader/loader.conf".source = (
pkgs.writeText "$out" ''
timeout 0
''
# FIXME: should not be 0 in prod
);
};
repartConfig = {
Type = "esp";
UUID = "c12a7328-f81f-11d2-ba4b-00a0c93ec93b"; # Well known
Format = "vfat";
SizeMinBytes = "256M";
SplitName = "-";
};
};
"store" = {
storePaths = [ config.system.build.toplevel ];
stripNixStorePrefix = true;
repartConfig = {
Type = "linux-generic";
Label = "${config.boot.uki.name}_${config.system.image.version}";
Format = "erofs";
Minimize = "best";
ReadOnly = "yes";
SizeMinBytes = "1G";
SizeMaxBytes = "1G";
SplitName = "store";
};
};
# Placeholder for the second installed Nix store.
"store-empty" = {
repartConfig = {
Type = "linux-generic";
Label = "_empty";
Minimize = "off";
SizeMinBytes = "1G";
SizeMaxBytes = "1G";
SplitName = "-";
};
};
# Persistent storage
"var" = {
repartConfig = {
Type = "var";
UUID = "4d21b016-b534-45c2-a9fb-5c16e091fd2d"; # Well known
Format = "xfs";
Label = "nixos-persistent";
Minimize = "off";
# Has to be large enough to hold update files.
SizeMinBytes = "2G";
SizeMaxBytes = "2G";
SplitName = "-";
# Wiping this gives us a clean state.
FactoryReset = "yes";
};
};
};
};
}

View file

@ -1,34 +0,0 @@
{
pkgs,
utils,
...
}:
{
environment.etc."sysupdate.patagia-agent.d".source =
let
format = pkgs.formats.ini { listToValue = toString; };
in
utils.systemdUtils.lib.definitions "sysupdate.patagia-agent.d" format {
"10-image.conf" = {
Source = {
MatchPattern = "patagia-agent_@v.raw";
Path = "https://images.dl.patagia.dev/patagia-agent/";
Type = "url-file";
};
Target = {
InstancesMax = 2;
Path = "/var/lib/extensions";
CurrentSymlink = "/etc/systemd/extensions/patagia-agent.raw";
Type = "regular-file";
MatchPattern = "patagia-agent_@v.raw";
};
Transfer = {
Verify = "no"; # FIXME: verify
};
};
};
}

86
modules/profiles/base.nix Normal file
View file

@ -0,0 +1,86 @@
{
config,
lib,
pkgs,
modulesPath,
...
}:
{
imports = [
(modulesPath + "/profiles/image-based-appliance.nix")
(modulesPath + "/profiles/perlless.nix")
(modulesPath + "/profiles/qemu-guest.nix")
];
# system.forbiddenDependenciesRegexes = lib.mkForce [ ];
nixpkgs.flake.setNixPath = false;
nixpkgs.flake.setFlakeRegistry = false;
networking.hostName = "patos";
boot.kernelModules = [
"zram"
"usb_storage"
"uas"
"sd_mod"
"r8169"
"ehci-hcd"
"ehci-pci"
"xhci-hcd"
"xhci-pci"
"xhci-pci-renesas"
"nvme"
"virtio_net"
];
system.etc.overlay.mutable = lib.mkDefault false;
users.mutableUsers = lib.mkDefault false;
systemd.watchdog = lib.mkDefault {
runtimeTime = "10s";
rebootTime = "30s";
};
zramSwap.enable = true;
services.openssh.settings.PasswordAuthentication = lib.mkDefault false;
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;
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";
}

View file

@ -0,0 +1,56 @@
{ 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;
networking.nftables.enable = lib.mkDefault true;
networking.useNetworkd = true;
systemd.network.wait-online.enable = true;
# Explicitly load networking modules
boot.kernelModules = [
"ip_tables"
"x_tables"
"nf_tables"
"nft_ct"
"nft_log"
"nf_log_syslog"
"nft_fib"
"nft_fib_inet"
"nft_compat"
"nft_nat"
"nft_chain_nat"
"nft_masq"
"nfnetlink"
"xt_conntrack"
"nf_conntrack"
"nf_log_syslog"
"nf_nat"
"af_packet"
"bridge"
"veth"
"tcp_bbr"
"sch_fq_codel"
"ipt_rpfilter"
"ip6t_rpfilter"
"sch_fq"
"tun"
"tap"
"xt_MASQUERADE"
"xt_mark"
"xt_comment"
"xt_multiport"
"xt_addrtype"
];
}

View file

@ -0,0 +1,43 @@
{
modulesPath,
...
}:
{
imports = [
(modulesPath + "/profiles/minimal.nix")
./network.nix
];
boot.kernel.sysctl = {
"net.ipv4.ip_unprivileged_port_start" = 0;
};
users.users."admin" = {
isNormalUser = true;
linger = true;
extraGroups = [ "wheel" ];
};
environment.etc = {
subuid = {
text = "admin:100000:65536";
mode = "0644";
};
subgid = {
text = "admin:100000:65536";
mode = "0644";
};
};
services.openssh.enable = true;
system.image.sshKeys.enable = true;
system.image.sshKeys.keys = [
"sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIIHMAEZx02kbHrEygyPQYStiXlrIe6EIqBCv7anIkL0pAAAABHNzaDo= dln1"
"sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIJNOBFoU7Cdsgi4KpYRcv7EhR/8kD4DYjEZnwk6urRx7AAAABHNzaDo= dln2"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKDx+7ZEJi7lUCAtoHRRIduJzH3hrpx4YS1f0ZxrJ+uW dln3"
];
virtualisation.podman.enable = true;
}

View file

@ -1,23 +0,0 @@
{ config, pkgs, ... }:
{
system.activationScripts.sysext = ''
mkdir -p /var/lib/confexts
mkdir -p /var/lib/extensions
mkdir -p /etc/systemd/extensions
'';
systemd.additionalUpstreamSystemUnits = [
"systemd-confext.service"
"systemd-sysext.service"
];
systemd.services."systemd-confext" = {
enable = true;
wantedBy = [ "multi-user.target" ];
};
systemd.services."systemd-sysext.service" = {
enable = true;
wantedBy = [ "multi-user.target" ];
};
}

View file

@ -1,5 +0,0 @@
{ lib, options, ... }: {
# This fields is immutable by default, but can be overridden.
options.system.nixos.codeName = lib.mkOption { readOnly = false; };
options.system.nixos.release = lib.mkOption { readOnly = false; };
}

View file

@ -1,90 +0,0 @@
{ config, pkgs, ... }:
let
gpgPubKeyStaging = ''
-----BEGIN PGP PUBLIC KEY BLOCK-----
mDMEZvb3mhYJKwYBBAHaRw8BAQdAvyH7AMLukMEF/1as7auAh757//LlO/kBG8pm
zhOlTj20LFBhdGFnaWEgU3RhZ2luZyA8bm9yZXBseStzdGFnaW5nQHBhdGFnaWEu
aW8+iJQEExYKADwWIQTjWE8tGxWc+3+vxyy1R4V5MjgMzAUCZvb3mgIbAwUJBaOa
gAQLCQgHBBUKCQgFFgIDAQACHgUCF4AACgkQtUeFeTI4DMwDWAEAlMAhSZh086Ux
OfLBR1QYgHtXmk6tObJurWkZq6cGICwA/2fBOtZcLfAPRWYPLHAtsqtFrO6CIyQG
H6n4Iv3D5ZsCuDgEZvb3mhIKKwYBBAGXVQEFAQEHQPKKcltfHlELIHf0AYcd0nOe
GaWcAnoW4o3zLZUVNnlpAwEIB4h+BBgWCgAmFiEE41hPLRsVnPt/r8cstUeFeTI4
DMwFAmb295oCGwwFCQWjmoAACgkQtUeFeTI4DMzuegEA62XIq4Ir+4DWdTql58bA
+0Vr89dMQsAxwVzGGzl8D8wBAMuPY6/2SwbA7KwWuz8L/cTPQVLBt+TSdYeuCBps
e5UE
=m2st
-----END PGP PUBLIC KEY BLOCK-----
'';
gpgKeyring = pkgs.runCommand "gpg-keyring" { buildInputs = [ pkgs.gnupg ]; } ''
mkdir -p $out
export GNUPGHOME=$out
gpg --no-default-keyring --keyring=$out/import-pubring.gpg --fingerprint
gpg --no-default-keyring --keyring=$out/import-pubring.gpg --import <<< '${gpgPubKeyStaging}'
rm $out/S.scdaemon $out/S.gpg-agent $out/S.gpg-agent.*
'';
in
{
environment.etc."systemd/import-pubring.gpg".source = "${gpgKeyring}/import-pubring.gpg";
systemd.sysupdate = {
enable = true;
transfers = {
"10-uki" = {
Source = {
MatchPattern = [
"${config.boot.uki.name}_@v.efi.xz"
];
Path = "https://images.dl.patagia.dev/patos/";
Type = "url-file";
};
Target = {
InstancesMax = 2;
MatchPattern = [
"${config.boot.uki.name}_@v.efi"
];
Mode = "0444";
Path = "/EFI/Linux";
PathRelativeTo = "boot";
Type = "regular-file";
};
Transfer = {
ProtectVersion = "%A";
Verify = "no";
};
};
"20-store" = {
Source = {
MatchPattern = [
"${config.boot.uki.name}_@v.img.xz"
];
Path = "https://images.dl.patagia.dev/patos/";
Type = "url-file";
};
Target = {
InstancesMax = 2;
# This doesn't work, because / is a tmpfs and the heuristic is not that smart.
#
# Path = "auto";
Path = "/dev/sda";
MatchPattern = "${config.boot.uki.name}_@v";
Type = "partition";
ReadOnly = "yes";
};
Transfer = {
Verify = "no";
};
};
};
};
}

View file

@ -1,29 +0,0 @@
{
config,
pkgs,
lib,
...
}:
let
script = pkgs.writeShellScriptBin "patos-upgrade.sh" ''
systemd-sysupdate --verify=no
systemd-sysupdate --verify=no update --reboot
'';
patos-install = pkgs.writeShellApplication {
name = "patos-install";
text = ''
set -xeuo pipefail
curl -s https://images.dl.patagia.dev/patos/patos_0.0.1.raw.zst |
zstdcat |
dd of=/dev/sdb status=progress bs=4M
'';
};
in
{
environment.systemPackages = [
# pkgs.ncdu
patos-install
script
];
}