This commit is contained in:
parent
da5bdb3d47
commit
a8982182b3
39 changed files with 1262 additions and 3272 deletions
157
flake.lock
157
flake.lock
|
@ -1,169 +1,24 @@
|
|||
{
|
||||
"nodes": {
|
||||
"advisory-db": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1727353582,
|
||||
"narHash": "sha256-2csMEEOZhvowVKZNBHk1kMJqk72ZMrPj9LQYCzP6EKs=",
|
||||
"owner": "rustsec",
|
||||
"repo": "advisory-db",
|
||||
"rev": "cb905e6e405834bdff1eb1e20c9b10edb5403889",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rustsec",
|
||||
"repo": "advisory-db",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"crane": {
|
||||
"locked": {
|
||||
"lastModified": 1727316705,
|
||||
"narHash": "sha256-/mumx8AQ5xFuCJqxCIOFCHTVlxHkMT21idpbgbm/TIE=",
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"rev": "5b03654ce046b5167e7b0bccbd8244cb56c16f0e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1726560853,
|
||||
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_2": {
|
||||
"inputs": {
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1726560853,
|
||||
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1730785428,
|
||||
"narHash": "sha256-Zwl8YgTVJTEum+L+0zVAWvXAGbWAuXHax3KzuejaDyo=",
|
||||
"owner": "nixos",
|
||||
"lastModified": 1731139594,
|
||||
"narHash": "sha256-IigrKK3vYRpUu+HEjPL/phrfh7Ox881er1UEsZvw9Q4=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "4aa36568d413aca0ea84a1684d2d46f55dbabad7",
|
||||
"rev": "76612b17c0ce71689921ca12d9ffdc9c23ce40b2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"patagia-agent": {
|
||||
"inputs": {
|
||||
"advisory-db": "advisory-db",
|
||||
"crane": "crane",
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-overlay": "rust-overlay"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1729636943,
|
||||
"narHash": "sha256-uEvMiMcKyAZ30ZZZuirCu9jM6DwEbNV2olsmSwLkmtg=",
|
||||
"ref": "main",
|
||||
"rev": "9ec0cf1dd5dc1bd64073b58681a8637c21b979c3",
|
||||
"revCount": 10,
|
||||
"type": "git",
|
||||
"url": "ssh://git@patagia.dev/patagia/patagia-agent"
|
||||
},
|
||||
"original": {
|
||||
"ref": "main",
|
||||
"type": "git",
|
||||
"url": "ssh://git@patagia.dev/patagia/patagia-agent"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"patagia-agent": "patagia-agent"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"patagia-agent",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1727490462,
|
||||
"narHash": "sha256-OrrPiNBiikv9BR464XTT75FzOq7tKAvMbMi7YOKVIeg=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "11a13e50debafae4ae802f1d6b8585101516dd93",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_2": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
191
flake.nix
191
flake.nix
|
@ -2,151 +2,70 @@
|
|||
description = "PatOS is a minimal, immutable Linux distribution specialized for the Patagia Platform.";
|
||||
|
||||
inputs = {
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
||||
patagia-agent.url = "git+ssh://git@patagia.dev/patagia/patagia-agent?ref=main";
|
||||
patagia-agent.inputs.nixpkgs.follows = "nixpkgs";
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
};
|
||||
|
||||
outputs =
|
||||
{ self, nixpkgs }:
|
||||
let
|
||||
releaseVersion = "0.0.1";
|
||||
system = "x86_64-linux";
|
||||
updateUrl = "https://images.dl.patagia.dev/patos/";
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
in
|
||||
{
|
||||
self,
|
||||
flake-utils,
|
||||
nixpkgs,
|
||||
patagia-agent,
|
||||
}:
|
||||
flake-utils.lib.eachDefaultSystem (
|
||||
system:
|
||||
let
|
||||
nixosModules.server.imports = [
|
||||
./modules/profiles/server.nix
|
||||
];
|
||||
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [
|
||||
(import ./overlays)
|
||||
];
|
||||
};
|
||||
nixosModules.image.imports = [
|
||||
./modules
|
||||
./modules/profiles/base.nix
|
||||
./modules/image/disk
|
||||
];
|
||||
|
||||
# Prepare an update package for the system.
|
||||
mkUpdate =
|
||||
nixos:
|
||||
let
|
||||
config = nixos.config;
|
||||
in
|
||||
pkgs.runCommand "update-${config.system.image.version}"
|
||||
{
|
||||
nativeBuildInputs = with pkgs; [
|
||||
erofs-utils
|
||||
zstd
|
||||
];
|
||||
}
|
||||
''
|
||||
mkdir -p $out
|
||||
cp ${config.system.build.image}/${config.boot.uki.name}_${config.system.image.version}.store.raw $out/
|
||||
|
||||
zstd -9 ${config.system.build.uki}/${config.system.boot.loader.ukiFile} \
|
||||
-o $out/${config.system.boot.loader.ukiFile}.zst
|
||||
|
||||
zstd -9 ${config.system.build.image}/${config.boot.uki.name}_${config.system.image.version}.store.raw \
|
||||
-o $out/${config.boot.uki.name}_${config.system.image.version}.img.zst
|
||||
'';
|
||||
|
||||
# Prepare a ready-to-boot disk image.
|
||||
mkInstallImage =
|
||||
nixos:
|
||||
let
|
||||
config = nixos.config;
|
||||
in
|
||||
pkgs.runCommand "update-${config.system.image.version}"
|
||||
{
|
||||
nativeBuildInputs = with pkgs; [
|
||||
qemu
|
||||
zstd
|
||||
];
|
||||
}
|
||||
''
|
||||
mkdir -p $out
|
||||
cp ${config.system.build.image}/${config.boot.uki.name}_${config.system.image.version}.raw $out/
|
||||
qemu-img convert -f raw -O qcow2 -C ${config.system.build.image}/${config.boot.uki.name}_${config.system.image.version}.raw $out/disk.qcow2
|
||||
|
||||
zstd -9 ${config.system.build.image}/${config.boot.uki.name}_${config.system.image.version}.store.raw \
|
||||
-o $out/${config.boot.uki.name}_${config.system.image.version}.img.zst
|
||||
|
||||
zstd -9 ${config.system.build.uki}/${config.system.boot.loader.ukiFile} \
|
||||
-o $out/${config.system.boot.loader.ukiFile}.zst
|
||||
'';
|
||||
in
|
||||
{
|
||||
devShells.${system}.default = pkgs.mkShell {
|
||||
packages = with pkgs; [
|
||||
erofs-utils
|
||||
just
|
||||
self.packages.${system}.qemu-efi
|
||||
squashfs-tools-ng
|
||||
];
|
||||
};
|
||||
|
||||
packages = {
|
||||
default = self.packages.${system}.patos_image;
|
||||
patos_image = mkInstallImage self.nixosConfigurations.${system}.patos;
|
||||
patos_update = mkUpdate self.nixosConfigurations.${system}.patos;
|
||||
|
||||
image = system.build;
|
||||
|
||||
# FIXME: only do for x86_64
|
||||
# A helper script to run the disk images above.
|
||||
qemu-efi = pkgs.writeShellApplication {
|
||||
name = "qemu-efi";
|
||||
|
||||
runtimeInputs = [ pkgs.qemu_kvm ];
|
||||
|
||||
text = ''
|
||||
set -ex
|
||||
state="/tmp/qemu-$USER"
|
||||
mkdir -p "$state"
|
||||
chmod 700 "$state"
|
||||
qemu-system-x86_64 \
|
||||
-cpu host \
|
||||
-machine q35,accel=kvm \
|
||||
-m 4G \
|
||||
-smp 8 \
|
||||
-display none \
|
||||
-chardev "stdio,id=char0,mux=on,logfile=$state/serial.log,signal=off" \
|
||||
-serial chardev:char0 \
|
||||
-mon chardev=char0 \
|
||||
-drive "if=pflash,format=raw,unit=0,readonly=on,file=${pkgs.OVMF.firmware}" \
|
||||
-drive "if=pflash,format=raw,unit=1,readonly=on,file=${pkgs.OVMF.variables}" \
|
||||
-netdev id=net00,type=user,hostfwd=tcp::2222-:22 \
|
||||
-device virtio-net-pci,netdev=net00 \
|
||||
"$@"
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
nixosConfigurations = rec {
|
||||
patos = nixpkgs.lib.nixosSystem {
|
||||
specialArgs.pkgs = pkgs;
|
||||
system = system;
|
||||
packages.${system} = {
|
||||
patos =
|
||||
(nixpkgs.lib.nixosSystem {
|
||||
modules = [
|
||||
(
|
||||
{ lib, ... }:
|
||||
{
|
||||
nixpkgs.hostPlatform = system;
|
||||
system.stateVersion = "24.05";
|
||||
}
|
||||
)
|
||||
{
|
||||
_module.args = {
|
||||
inherit patagia-agent;
|
||||
};
|
||||
boot.kernelParams = [
|
||||
"console=ttyS0"
|
||||
"systemd.journald.forward_to_console"
|
||||
];
|
||||
system.image.updates.url = "${updateUrl}";
|
||||
system.image.id = "patos";
|
||||
system.image.version = releaseVersion;
|
||||
}
|
||||
./modules/kernel
|
||||
./modules/filesystems.nix
|
||||
./modules/generic.nix
|
||||
./modules/minimize.nix
|
||||
./modules/network.nix
|
||||
# ./modules/patagia-agent.nix
|
||||
./modules/partitions.nix
|
||||
./modules/system_overrides.nix
|
||||
./modules/sysext.nix
|
||||
./modules/sysupdate.nix
|
||||
./modules/utils.nix
|
||||
self.nixosModules.image
|
||||
self.nixosModules.server
|
||||
];
|
||||
};
|
||||
};
|
||||
}).config.system.build.updatePackage;
|
||||
|
||||
}
|
||||
);
|
||||
qemu-uefi-tpm = pkgs.callPackage ./utils/qemu-uefi-tpm.nix { inherit pkgs; };
|
||||
};
|
||||
|
||||
checks.${system} = {
|
||||
ssh-preseed = import ./tests/ssh-preseed.nix { inherit pkgs self; };
|
||||
podman = import ./tests/podman.nix { inherit pkgs self; };
|
||||
system-update = import ./tests/system-update.nix { inherit pkgs self; };
|
||||
};
|
||||
|
||||
devShells.${system}.default = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
erofs-utils
|
||||
just
|
||||
self.packages.${system}.qemu-uefi-tpm
|
||||
squashfs-tools-ng
|
||||
];
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
|
|
8
justfile
8
justfile
|
@ -13,11 +13,7 @@ build: build-image
|
|||
|
||||
# Build PatOS image
|
||||
build-image:
|
||||
nix build .#patos_image
|
||||
|
||||
# Build PatOS update image
|
||||
build-update:
|
||||
nix build .#patos_update
|
||||
nix build .#patos
|
||||
|
||||
run: build-image
|
||||
qemu-efi -snapshot ./result/disk.qcow2
|
||||
qemu-uefi-tpm ./result/*.img
|
||||
|
|
15
modules/config/minimal-modules.nix
Normal file
15
modules/config/minimal-modules.nix
Normal 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;
|
||||
}
|
26
modules/config/minimal-system.nix
Normal file
26
modules/config/minimal-system.nix
Normal 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
6
modules/default.nix
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
imports = [
|
||||
./config/minimal-modules.nix
|
||||
./config/minimal-system.nix
|
||||
];
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
}
|
|
@ -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
128
modules/image/disk/:w
Normal 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" ];
|
||||
|
||||
}
|
161
modules/image/disk/builder.nix
Normal file
161
modules/image/disk/builder.nix
Normal file
|
@ -0,0 +1,161 @@
|
|||
{
|
||||
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.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
|
||||
{
|
||||
|
||||
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";
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
}
|
128
modules/image/disk/default.nix
Normal file
128
modules/image/disk/default.nix
Normal 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" ];
|
||||
|
||||
}
|
40
modules/image/disk/ssh.nix
Normal file
40
modules/image/disk/ssh.nix
Normal 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"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
}
|
86
modules/image/disk/updater.nix
Normal file
86
modules/image/disk/updater.nix
Normal 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"
|
||||
];
|
||||
|
||||
};
|
||||
|
||||
}
|
39
modules/image/disk/veritysetup.nix
Normal file
39
modules/image/disk/veritysetup.nix
Normal 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"
|
||||
];
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -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
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -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
86
modules/profiles/base.nix
Normal 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";
|
||||
}
|
56
modules/profiles/network.nix
Normal file
56
modules/profiles/network.nix
Normal 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"
|
||||
];
|
||||
|
||||
}
|
43
modules/profiles/server.nix
Normal file
43
modules/profiles/server.nix
Normal 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;
|
||||
}
|
|
@ -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" ];
|
||||
};
|
||||
}
|
|
@ -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; };
|
||||
}
|
|
@ -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";
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
}
|
|
@ -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
|
||||
];
|
||||
}
|
5
pkgs/composefs.nix
Normal file
5
pkgs/composefs.nix
Normal file
|
@ -0,0 +1,5 @@
|
|||
{ prev, ... }:
|
||||
|
||||
prev.composefs.overrideAttrs (final: prev: {
|
||||
doCheck = false;
|
||||
})
|
12
pkgs/linux-firmware.nix
Normal file
12
pkgs/linux-firmware.nix
Normal file
|
@ -0,0 +1,12 @@
|
|||
{ stdenv, lib
|
||||
, linux-firmware
|
||||
, fwDirs
|
||||
}: stdenv.mkDerivation {
|
||||
pname = "linux-firmware-minimal";
|
||||
version = linux-firmware.version;
|
||||
buildCommand = lib.concatStringsSep "\n" (
|
||||
[''mkdir -p "$out/lib/firmware"'']
|
||||
++ (map (name: ''
|
||||
cp -r "${linux-firmware}/lib/firmware/${name}" "$out/lib/firmware/${name}"
|
||||
'') fwDirs));
|
||||
}
|
7
pkgs/openssh.nix
Normal file
7
pkgs/openssh.nix
Normal file
|
@ -0,0 +1,7 @@
|
|||
{ prev, ... }:
|
||||
|
||||
prev.openssh.overrideAttrs (final: prev: {
|
||||
doCheck = false;
|
||||
doInstallCheck = false;
|
||||
dontCheck = true;
|
||||
})
|
30
pkgs/qemu.nix
Normal file
30
pkgs/qemu.nix
Normal file
|
@ -0,0 +1,30 @@
|
|||
{ prev, pkgs, ... }:
|
||||
|
||||
(prev.qemu_test.override {
|
||||
enableDocs = false;
|
||||
capstoneSupport = false;
|
||||
guestAgentSupport = false;
|
||||
tpmSupport = false;
|
||||
libiscsiSupport = false;
|
||||
usbredirSupport = false;
|
||||
canokeySupport = false;
|
||||
hostCpuTargets = [ "x86_64-softmmu" ];
|
||||
}).overrideDerivation (old: {
|
||||
postFixup = ''
|
||||
rm -r "$out/share/icons"
|
||||
cp "${pkgs.OVMF.fd + "/FV/OVMF.fd"}" "$out/share/qemu/"
|
||||
'';
|
||||
configureFlags = old.configureFlags ++ [
|
||||
"--disable-tcg"
|
||||
"--disable-tcg-interpreter"
|
||||
"--disable-docs"
|
||||
"--disable-install-blobs"
|
||||
"--disable-slirp"
|
||||
"--disable-virtfs"
|
||||
"--disable-virtfs-proxy-helper"
|
||||
"--disable-vhost-user-blk-server"
|
||||
"--without-default-features"
|
||||
"--enable-kvm"
|
||||
"--disable-tools"
|
||||
];
|
||||
})
|
48
pkgs/systemd-ukify.nix
Normal file
48
pkgs/systemd-ukify.nix
Normal file
|
@ -0,0 +1,48 @@
|
|||
{ prev, ... }:
|
||||
|
||||
prev.systemd.override {
|
||||
withAcl = false;
|
||||
withAnalyze = false;
|
||||
withApparmor = false;
|
||||
withAudit = false;
|
||||
withEfi = true;
|
||||
withCompression = false;
|
||||
withCoredump = false;
|
||||
withCryptsetup = false;
|
||||
withRepart = false;
|
||||
withDocumentation = false;
|
||||
withFido2 = false;
|
||||
withFirstboot = false;
|
||||
withHomed = false;
|
||||
withHostnamed = false;
|
||||
withHwdb = false;
|
||||
withImportd = false;
|
||||
withIptables = false;
|
||||
withKmod = false;
|
||||
withLibBPF = false;
|
||||
withLibidn2 = false;
|
||||
withLocaled = false;
|
||||
withLogind = false;
|
||||
withMachined = false;
|
||||
withNetworkd = false;
|
||||
withNss = false;
|
||||
withOomd = false;
|
||||
withPam = false;
|
||||
withPasswordQuality = false;
|
||||
withPCRE2 = false;
|
||||
withPolkit = false;
|
||||
withPortabled = false;
|
||||
withQrencode = false;
|
||||
withRemote = false;
|
||||
withResolved = false;
|
||||
withShellCompletions = false;
|
||||
withSysusers = false;
|
||||
withSysupdate = false;
|
||||
withTimedated = false;
|
||||
withTimesyncd = false;
|
||||
withTpm2Tss = false;
|
||||
withUkify = true;
|
||||
withUserDb = false;
|
||||
withUtmp = false;
|
||||
withVmspawn = false;
|
||||
}
|
10
pkgs/systemd.nix
Normal file
10
pkgs/systemd.nix
Normal file
|
@ -0,0 +1,10 @@
|
|||
{ prev, ... }:
|
||||
|
||||
prev.systemd.override {
|
||||
withAcl = false;
|
||||
withApparmor = false;
|
||||
withDocumentation = false;
|
||||
withRemote = false;
|
||||
withShellCompletions = false;
|
||||
withVmspawn = false;
|
||||
}
|
111
tests/common.nix
Normal file
111
tests/common.nix
Normal file
|
@ -0,0 +1,111 @@
|
|||
{ self, lib, pkgs, ... }:
|
||||
|
||||
with import (pkgs.path + "/nixos/lib/testing-python.nix") { inherit pkgs; inherit (pkgs.hostPlatform) system; };
|
||||
|
||||
let
|
||||
|
||||
nixos-lib = import (pkgs.path + "/nixos/lib") {};
|
||||
qemu-common = import (pkgs.path + "/nixos/lib/qemu-common.nix") { inherit lib pkgs; };
|
||||
|
||||
in rec {
|
||||
|
||||
makeSystem = extraConfig:
|
||||
(import (pkgs.path + "/nixos/lib/eval-config.nix")) {
|
||||
inherit pkgs lib;
|
||||
system = null;
|
||||
modules = [
|
||||
{
|
||||
nixpkgs.hostPlatform = pkgs.hostPlatform;
|
||||
}
|
||||
{
|
||||
users.allowNoPasswordLogin = true;
|
||||
system.stateVersion = lib.versions.majorMinor lib.version;
|
||||
system.image.id = lib.mkDefault "test";
|
||||
system.image.version = lib.mkDefault "1";
|
||||
networking.hosts."10.0.2.1" = [ "server.test" ];
|
||||
}
|
||||
{
|
||||
boot.kernelParams = [ "console=ttyS0,115200n8" "systemd.journald.forward_to_console=1" ];
|
||||
image.compress = false;
|
||||
boot.initrd.compressor = lib.mkForce "zstd";
|
||||
boot.initrd.compressorArgs = lib.mkForce [ "-8" ];
|
||||
}
|
||||
(pkgs.path + "/nixos/modules/testing/test-instrumentation.nix")
|
||||
self.nixosModules.server
|
||||
self.nixosModules.image
|
||||
extraConfig
|
||||
];
|
||||
};
|
||||
|
||||
makeImage = extraConfig: let
|
||||
system = makeSystem extraConfig;
|
||||
in "${system.config.system.build.image}/${system.config.system.build.image.imageFile}";
|
||||
|
||||
makeUpdatePackage = extraConfig: let
|
||||
system = makeSystem extraConfig;
|
||||
in "${system.config.system.build.updatePackage}";
|
||||
|
||||
makeImageTest = { name, image, script, httpRoot ? null }: let
|
||||
qemu = qemu-common.qemuBinary pkgs.qemu_test;
|
||||
flags = [
|
||||
"-m" "512M"
|
||||
"-drive" "if=pflash,format=raw,unit=0,readonly=on,file=${pkgs.OVMF.firmware}"
|
||||
"-drive" "if=pflash,format=raw,unit=1,readonly=on,file=${pkgs.OVMF.variables}"
|
||||
"-drive" "if=virtio,file=${mutableImage}"
|
||||
"-chardev" "socket,id=chrtpm,path=${tpmFolder}/swtpm-sock"
|
||||
"-tpmdev" "emulator,id=tpm0,chardev=chrtpm"
|
||||
"-device" "tpm-tis,tpmdev=tpm0"
|
||||
"-netdev" ("'user,id=net0" + (lib.optionalString (httpRoot != null) ",guestfwd=tcp:10.0.2.1:80-cmd:${pkgs.micro-httpd}/bin/micro_httpd ${httpRoot}") + "'")
|
||||
"-device" "virtio-net-pci,netdev=net0"
|
||||
];
|
||||
flagsStr = lib.concatStringsSep " " flags;
|
||||
startCommand = "${qemu} ${flagsStr}";
|
||||
mutableImage = "/tmp/linked-image.qcow2";
|
||||
tpmFolder = "/tmp/emulated_tpm";
|
||||
indentLines = str: lib.concatLines (map (s: " " + s) (lib.splitString "\n" str));
|
||||
in makeTest {
|
||||
inherit name;
|
||||
nodes = { };
|
||||
testScript = ''
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
subprocess.check_call(
|
||||
[
|
||||
"qemu-img",
|
||||
"create",
|
||||
"-f",
|
||||
"qcow2",
|
||||
"-F",
|
||||
"raw",
|
||||
"-b",
|
||||
"${image}",
|
||||
"${mutableImage}",
|
||||
]
|
||||
)
|
||||
subprocess.check_call(["qemu-img", "resize", "${mutableImage}", "4G"])
|
||||
|
||||
os.mkdir("${tpmFolder}")
|
||||
os.mkdir("${tpmFolder}/swtpm")
|
||||
|
||||
def start_tpm():
|
||||
subprocess.Popen(
|
||||
[
|
||||
"${pkgs.swtpm}/bin/swtpm",
|
||||
"socket",
|
||||
"--tpmstate", "dir=${tpmFolder}/swtpm",
|
||||
"--ctrl", "type=unixio,path=${tpmFolder}/swtpm-sock",
|
||||
"--tpm2"
|
||||
]
|
||||
)
|
||||
|
||||
machine = create_machine("${startCommand}")
|
||||
|
||||
try:
|
||||
'' + indentLines script + ''
|
||||
finally:
|
||||
machine.shutdown()
|
||||
'';
|
||||
};
|
||||
|
||||
}
|
9
tests/lib.nix
Normal file
9
tests/lib.nix
Normal file
|
@ -0,0 +1,9 @@
|
|||
test:
|
||||
{ pkgs, self }:
|
||||
let nixos-lib = import (pkgs.path + "/nixos/lib") {};
|
||||
in (nixos-lib.runTest {
|
||||
hostPkgs = pkgs;
|
||||
defaults.documentation.enable = false;
|
||||
node.specialArgs = { inherit self; };
|
||||
imports = [ test ];
|
||||
}).config.result
|
22
tests/podman.nix
Normal file
22
tests/podman.nix
Normal file
|
@ -0,0 +1,22 @@
|
|||
{ pkgs, self }: let
|
||||
|
||||
lib = pkgs.lib;
|
||||
test-common = import ./common.nix { inherit self lib pkgs; };
|
||||
|
||||
image = test-common.makeImage { };
|
||||
|
||||
in test-common.makeImageTest {
|
||||
name = "podman";
|
||||
inherit image;
|
||||
script = ''
|
||||
start_tpm()
|
||||
machine.start()
|
||||
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
machine.wait_for_unit("network-online.target")
|
||||
|
||||
machine.succeed("tar cv --files-from /dev/null | su admin -l -c 'podman import - scratchimg'")
|
||||
|
||||
machine.succeed("su admin -l -c 'podman run --rm -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin scratchimg true'")
|
||||
'';
|
||||
}
|
37
tests/ssh-preseed.nix
Normal file
37
tests/ssh-preseed.nix
Normal file
|
@ -0,0 +1,37 @@
|
|||
{ pkgs, self }:
|
||||
let
|
||||
lib = pkgs.lib;
|
||||
test-common = import ./common.nix { inherit self lib pkgs; };
|
||||
sshKeys = import (pkgs.path + "/nixos/tests/ssh-keys.nix") pkgs;
|
||||
|
||||
image = test-common.makeImage {
|
||||
system.image.sshKeys.keys = [ sshKeys.snakeOilPublicKey ];
|
||||
system.extraDependencies = [ sshKeys.snakeOilPrivateKey ];
|
||||
};
|
||||
|
||||
in
|
||||
test-common.makeImageTest {
|
||||
name = "ssh-preseed";
|
||||
inherit image;
|
||||
script = ''
|
||||
start_tpm()
|
||||
machine.start()
|
||||
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
|
||||
machine.succeed("[ -e /efi/default-ssh-authorized-keys.txt ]")
|
||||
machine.succeed("[ -e /home/admin/.ssh/authorized_keys ]")
|
||||
|
||||
machine.wait_for_open_port(22)
|
||||
|
||||
machine.succeed(
|
||||
"cat ${sshKeys.snakeOilPrivateKey} > privkey.snakeoil"
|
||||
)
|
||||
machine.succeed("chmod 600 privkey.snakeoil")
|
||||
|
||||
machine.succeed(
|
||||
"ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil admin@127.0.0.1 true",
|
||||
timeout=30
|
||||
)
|
||||
'';
|
||||
}
|
45
tests/system-update.nix
Normal file
45
tests/system-update.nix
Normal file
|
@ -0,0 +1,45 @@
|
|||
{ pkgs, self }: let
|
||||
|
||||
lib = pkgs.lib;
|
||||
test-common = import ./common.nix { inherit self lib pkgs; };
|
||||
|
||||
initialImage = test-common.makeImage {
|
||||
system.image.version = "1";
|
||||
system.image.updates.url = "http://server.test/";
|
||||
# The default root-b is too small for uncompressed test images
|
||||
systemd.repart.partitions."32-root-b" = {
|
||||
SizeMinBytes = lib.mkForce "1G";
|
||||
SizeMaxBytes = lib.mkForce "1G";
|
||||
};
|
||||
};
|
||||
|
||||
updatePackage = test-common.makeUpdatePackage {
|
||||
system.image.version = "2";
|
||||
system.image.updates.url = "http://server.test/";
|
||||
};
|
||||
|
||||
in test-common.makeImageTest {
|
||||
name = "system-update";
|
||||
image = initialImage;
|
||||
httpRoot = updatePackage;
|
||||
script = ''
|
||||
start_tpm()
|
||||
machine.start()
|
||||
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
machine.wait_for_unit("network-online.target")
|
||||
|
||||
machine.succeed("/run/current-system/sw/lib/systemd/systemd-sysupdate update")
|
||||
|
||||
machine.shutdown()
|
||||
|
||||
start_tpm()
|
||||
machine.start()
|
||||
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
|
||||
machine.succeed('. /etc/os-release; [ "$IMAGE_VERSION" == "2" ]')
|
||||
|
||||
machine.wait_for_unit("systemd-bless-boot.service")
|
||||
'';
|
||||
}
|
49
utils/qemu-uefi-tpm.nix
Normal file
49
utils/qemu-uefi-tpm.nix
Normal file
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
pkgs.writeShellApplication {
|
||||
name = "qemu-uefi-tpm";
|
||||
|
||||
runtimeInputs = with pkgs; [
|
||||
qemu
|
||||
swtpm
|
||||
];
|
||||
|
||||
text =
|
||||
let
|
||||
tpmOVMF = pkgs.OVMF.override { tpmSupport = true; };
|
||||
in
|
||||
''
|
||||
set -ex
|
||||
state="/tmp/patos-qemu-$USER"
|
||||
rm -rf "$state"
|
||||
mkdir -m 700 "$state"
|
||||
qemu-img create -f qcow2 -F raw -b "$(readlink -e "$1")" "$state/disk.qcow2" 10G
|
||||
|
||||
swtpm socket -d --tpmstate dir="$state" \
|
||||
--ctrl type=unixio,path="$state/swtpm-sock" \
|
||||
--tpm2 \
|
||||
--log level=20
|
||||
|
||||
qemu-system-x86_64 \
|
||||
-enable-kvm \
|
||||
-machine q35,accel=kvm \
|
||||
-cpu host \
|
||||
-smp 8 \
|
||||
-m 4G \
|
||||
-display none \
|
||||
-chardev "stdio,id=char0,mux=on,logfile=$state/console.log,signal=off" \
|
||||
-serial chardev:char0 \
|
||||
-mon chardev=char0 \
|
||||
-drive "if=pflash,format=raw,unit=0,readonly=on,file=${tpmOVMF.firmware}" \
|
||||
-drive "if=pflash,format=raw,unit=1,readonly=on,file=${tpmOVMF.variables}" \
|
||||
-chardev socket,id=chrtpm,path="$state/swtpm-sock" \
|
||||
-tpmdev emulator,id=tpm0,chardev=chrtpm \
|
||||
-device tpm-tis,tpmdev=tpm0 \
|
||||
-netdev id=net00,type=user,hostfwd=tcp::2222-:22 \
|
||||
-device virtio-net-pci,netdev=net00 \
|
||||
-drive "format=qcow2,file=$state/disk.qcow2"
|
||||
'';
|
||||
}
|
Loading…
Reference in a new issue