From 855aedd0db6680ab6cd0c9fe907f69ecaa44bc67 Mon Sep 17 00:00:00 2001 From: Vladimir Drozdov Date: Wed, 16 Sep 2026 11:14:16 +0200 Subject: [PATCH] vm: Add vm example support --- default.nix | 14 ++++++++ vm/README.md | 45 ++++++++++++++++++++++++ vm/vm.nix | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 vm/README.md create mode 100644 vm/vm.nix diff --git a/default.nix b/default.nix index 3fec19a..581043d 100644 --- a/default.nix +++ b/default.nix @@ -125,6 +125,20 @@ let }; in rec { + # Throwaway QEMU VM to test Bureautix, see `vm/README.md`. + # Run with: `nix-build -A vm` then `./result/bin/run-*-vm`. + vmTerminal = securix.lib.mkTerminal { + name = "vm-test"; + edition = defaultEdition; + userSpecificModule = { }; + vpnProfiles = { }; + modules = [ + ./vm/vm.nix + ]; + }; + + vm = vmTerminal.system.config.system.build.vm; + # Generic installer for any laptops. # There's a netboot installer, see `netboot/README.md` for documentation. # There's an USB generic installer that will install a default system. diff --git a/vm/README.md b/vm/README.md new file mode 100644 index 0000000..2ca14ff --- /dev/null +++ b/vm/README.md @@ -0,0 +1,45 @@ + + +# VM test example + +This directory contains a minimal example to test Bureautix inside a throwaway QEMU VM. + +It reuses `./common` (office tools, KDE, PAM U2F config, …) but disables +everything that requires physical hardware **only inside `system.build.vm`**: + +- `disko` / LUKS / FIDO2 (`securix.filesystems.enable = false`) +- Secure Boot via Lanzaboote (replaced by `systemd-boot`) +- PAM U2F (password login stays available) +- `pcscd` / TPM / Yubikey agent + +## Run it + +```sh +nix-build -A vm +./result/bin/run-bureautix-vm-test-vm +``` + +Logins: + +- `alice` / `test` (autologged on the KDE session) +- `root` / `nixos` (see `common/superadmins.nix`) + +## Passing a Yubikey + +Find your key with `lsusb`, then uncomment the `usb-host` lines in `vm.nix`: + +```nix +"-usb" +"-device" +"usb-host,vendorid=0x1050,productid=0x0407" +``` + +## Files + +- `vm.nix`: the NixOS module used for the VM. Import it through `mkTerminal` + (see `vmTerminal` in the top-level `default.nix`), all VM-only overrides + live under `virtualisation.vmVariant`. diff --git a/vm/vm.nix b/vm/vm.nix new file mode 100644 index 0000000..2751f66 --- /dev/null +++ b/vm/vm.nix @@ -0,0 +1,96 @@ +# SPDX-FileCopyrightText: 2025 Ryan Lahfa +# +# SPDX-License-Identifier: MIT + +# Test-only NixOS module to run Bureautix inside a QEMU VM. +# +# Why this module exists: +# - Physical Bureautix machines assume a real disk (e.g. /dev/nvme0n1), +# LUKS + FIDO2 enrollment, Secure Boot via Lanzaboote and a Yubikey +# for PAM U2F. None of this exists inside a throwaway QEMU VM. +# - `virtualisation.vmVariant` is only merged into +# `config.system.build.vm`, so every override below applies to the VM +# run (`nix-build -A vm`) and never to your real installed systems. +{ lib, pkgs, ... }: +{ + # Identity of the VM used as a test. + # This reuses the `alice` test account (password is `test`, see + # `inventory/users/alice.nix`). + # NOTE: `mainDisk` is still required at eval time because the + # `office_v1`/`securix_v1` filesystem modules read it eagerly, even + # when disabled via `securix.filesystems.enable = false` in vmVariant. + securix.self.mainDisk = "/dev/vda"; + securix.self.machine = { + hardwareSKU = "x280"; + serialNumber = "VM-TEST-01"; + }; + + imports = [ + # Keep the example small and self-contained: reuse the standard office + # configuration but the test user is defined inline so `nix-build -A vm` + # works without touching the real inventory. + ../common + ]; + + securix.self.user = { + email = "alice@example.com"; + username = "alice"; + # password is `test` + hashedPassword = "$y$j9T$zk4xGLyshz7RzqnMX6M8O0$AybRelILMkQSWcQZV4s.ykRNi/UlgaCUaDwdee0n7N2"; + defaultLoginShell = pkgs.zsh; + }; + + # Everything below only affects `system.build.vm`, not the real toplevel. + virtualisation.vmVariant = { + # Disable everything that requires physical hardware. + # - disko / LUKS / FIDO2: the VM uses a throwaway qcow2 managed by qemu-vm.nix. + # - Lanzaboote / Secure Boot: OVMF in `build.vm` is not enrolled, use systemd-boot. + # - PAM U2F: no Yubikey is passed through by default, keep password login. + securix.filesystems.enable = lib.mkForce false; + disko.enableConfig = lib.mkForce false; + boot.lanzaboote.enable = lib.mkForce false; + # NOTE: securix forces systemd-boot off with `mkForce`, so inside + # `vmVariant` we need an even stronger priority (`mkOverride 10`) + # to re-enable it for the VM. + boot.loader.systemd-boot.enable = lib.mkOverride 10 true; + boot.loader.efi.canTouchEfiVariables = lib.mkOverride 10 false; + securix.pam.u2f.enable = lib.mkForce false; + # `securix.admins` asserts that PAM U2F is enabled (admin accounts are + # passwordless by design). There is no Yubikey in the test VM, so + # disable the IT admin accounts here; `alice` (password `test`) and + # `root` (password `nixos`) stay available. + securix.admins.enable = lib.mkForce false; + + # Do not fail the VM on missing smartcard hardware. + services.pcscd.enable = lib.mkForce false; + services.yubikey-agent.enable = lib.mkForce false; + + # Convenient test-only settings. + users.users.alice.extraGroups = [ "wheel" ]; + security.sudo.wheelNeedsPassword = false; + + # Autologin on the graphical session so `run-*-vm` lands directly + # on the KDE desktop. Console login still works with `alice` / `test` + # and `root` / `nixos`. + services.displayManager.autoLogin.enable = true; + services.displayManager.autoLogin.user = "alice"; + + # Guest integration + resources. + services.qemuGuest.enable = true; + services.spice-vdagentd.enable = true; + + virtualisation = { + memorySize = 4096; + cores = 4; + diskSize = 20480; + graphics = true; + qemu.options = [ + # Example: pass a physical Yubikey to the VM to test PAM U2F / FIDO2. + # Find vendor/product with `lsusb`, then uncomment: + # "-usb" + # "-device" + # "usb-host,vendorid=0x1050,productid=0x0407" + ]; + }; + }; +}