diff --git a/.envrc b/.envrc index 71f6f8c..26967a1 100644 --- a/.envrc +++ b/.envrc @@ -1,2 +1,2 @@ -nix_direnv_watch_file devshell/{default,commands,install}.nix +nix_direnv_watch_file devshell/{default,commands,install,vm-tasks}.nix use flake diff --git a/devshell/commands.nix b/devshell/commands.nix index 1284185..914204c 100644 --- a/devshell/commands.nix +++ b/devshell/commands.nix @@ -46,7 +46,13 @@ in name = "qemu-genmac"; category = "utilities"; help = "Generate MAC address suitable for QEMU"; - command = ''printf "52:54:00:ab:%02x:%02x\n" $((RANDOM%256)) $((RANDOM%256))''; + command = ''printf "52:54:00:%02x:%02x:%02x\n" $((RANDOM%256)) $((RANDOM%256)) $((RANDOM%256))''; + } + { + name = "ssh-get-ed25519"; + category = "utilities"; + help = "Print the ed25519 pubkey for a host"; + command = "${pkgs.openssh}/bin/ssh-keyscan -t ed25519 \"$1\" 2> /dev/null | awk '{ print $2 \" \" $3 }'"; } { diff --git a/devshell/default.nix b/devshell/default.nix index eaea123..4d5883c 100644 --- a/devshell/default.nix +++ b/devshell/default.nix @@ -3,7 +3,7 @@ let inherit (lib.my) attrsToNVList; in { - imports = [ ./commands.nix ./install.nix ]; + imports = [ ./commands.nix ./install.nix ./vm-tasks.nix ]; env = attrsToNVList { # starship will show this @@ -13,6 +13,8 @@ in '' experimental-features = nix-command flakes ca-derivations ''); + + INSTALLER_SSH_OPTS = "-i .keys/deploy.key"; }; packages = with pkgs; [ diff --git a/devshell/install.nix b/devshell/install.nix index adbc758..e39538c 100644 --- a/devshell/install.nix +++ b/devshell/install.nix @@ -1,7 +1,7 @@ { lib, pkgs, config, ... }: let - inherit (lib) mapAttrsToList concatMapStringsSep; - inherit (lib.my) mkOpt' attrsToNVList; + inherit (lib) mapAttrsToList; + inherit (lib.my) mkOpt'; parseArgs = opts: '' @@ -45,10 +45,10 @@ let log "[\e[36;1minfo\e[0m]: \e[36m$*\e[0m" } warn() { - log "[\e[33;1minfo\e[0m]: \e[33m$*\e[0m" + log "[\e[33;1mwarn\e[0m]: \e[33m$*\e[0m" } error() { - log "[\e[31;1minfo\e[0m]: \e[31m$*\e[0m" + log "[\e[31;1merror\e[0m]: \e[31m$*\e[0m" } die() { error "$@" diff --git a/devshell/vm-tasks.nix b/devshell/vm-tasks.nix new file mode 100644 index 0000000..9bb9297 --- /dev/null +++ b/devshell/vm-tasks.nix @@ -0,0 +1,128 @@ +{ lib, pkgs, config, ... }: +let + inherit (lib) mapAttrsToList; + inherit (lib.my) mkOpt; + + parseArgs = opts: + '' + POSITIONAL_ARGS=() + + while [ $# -gt 0 ]; do + # shellcheck disable=SC2221,SC2222 + case $1 in + ${opts} + -*|--*) + die "Unknown option $1" + ;; + *) + POSITIONAL_ARGS+=("$1") # save positional arg + shift # past argument + ;; + esac + done + + set -- "''${POSITIONAL_ARGS[@]}" # restore positional parameters + ''; + common = pkgs.writeShellApplication { + name = "vm-tasks-common.sh"; + runtimeInputs = with pkgs; [ + openssh + ]; + text = + '' + : "''${VM_SSH_OPTS:=}" + + IFS=" " read -ra SSH_OPTS <<< "$VM_SSH_OPTS" + SSH_OPTS+=(-N) + + HOST="''${1:-}" + VM="''${2:-}" + if [ -z "$HOST" ] || [ -z "$VM" ]; then + echo "usage: $0 ..." >&2 + exit 1 + fi + + SOCKS_DIR="$(mktemp -d --tmpdir vm-socks.XXXXXX)" + cleanup() { + rm -rf "$SOCKS_DIR" + } + trap cleanup EXIT + + SOCKS=() + closeSocks() { + for p in "''${SOCK_PIDS[@]}"; do + kill "$p" + done + } + openSock() { + local s="$SOCKS_DIR"/"$1".sock + ssh "''${SSH_OPTS[@]}" -L "$s":/run/vms/"$VM"/"$1".sock "$HOST" & + SOCKS+=($!) + echo "$s" + } + ''; + }; + vmTaskOpts = with lib.types; { + options = { + help = mkOpt str null; + script = mkOpt lines ""; + packages = mkOpt (listOf package) [ ]; + }; + }; +in +{ + options.my.vmTasks = with lib.types; + mkOpt (attrsOf (submodule vmTaskOpts)) { }; + + config = { + my.vmTasks = { + vm-tty = { + help = "Access remote VM's TTY"; + packages = with pkgs; [ minicom ]; + script = + '' + sock="$(openSock tty)" + minicom -D unix#"$sock" + closeSocks + ''; + }; + vm-monitor = { + help = "Access remote VM's QEMU monitor"; + packages = with pkgs; [ minicom ]; + script = + '' + sock="$(openSock monitor)" + minicom -D unix#"$sock" + closeSocks + ''; + }; + vm-viewer = { + help = "Access remote VM's display with virt-viewer"; + packages = with pkgs; [ virt-viewer ]; + script = + '' + sock=$(openSock spice) + remote-viewer spice+unix://"$sock" + closeSocks + ''; + }; + }; + + commands = mapAttrsToList (name: cmd: { + inherit name; + inherit (cmd) help; + category = "vm-tasks"; + package = pkgs.writeShellApplication { + inherit name; + runtimeInputs = cmd.packages; + text = + '' + # shellcheck disable=SC1091 + source "${common}/bin/vm-tasks-common.sh" + + ${cmd.script} + ''; + }; + }) config.my.vmTasks; + }; +} diff --git a/flake.nix b/flake.nix index b45f28f..26d744e 100644 --- a/flake.nix +++ b/flake.nix @@ -95,6 +95,7 @@ nixos/installer.nix nixos/boxes/colony.nix + nixos/vms/estuary.nix nixos/containers/vaultwarden.nix # Homes @@ -138,7 +139,7 @@ } // (eachDefaultSystem (system: let - pkgs = pkgs'.unstable.${system}; + pkgs = pkgs'.mine.${system}; lib = pkgs.lib; in # Stuff for each platform diff --git a/nixos/boxes/colony.nix b/nixos/boxes/colony.nix index 3be6339..1502006 100644 --- a/nixos/boxes/colony.nix +++ b/nixos/boxes/colony.nix @@ -6,43 +6,112 @@ configuration = { lib, pkgs, modulesPath, config, systems, ... }: let - inherit (lib) mkIf; + inherit (lib) mkIf mapAttrs; + + wanBDF = + if config.my.build.isDevVM then "00:02.0" else "01:00.0"; in { imports = [ "${modulesPath}/profiles/qemu-guest.nix" ]; + boot.kernelParams = [ "intel_iommu=on" ]; + boot.loader.systemd-boot.configurationLimit = 20; + fileSystems = { + "/boot" = { + device = "/dev/disk/by-label/ESP"; + fsType = "vfat"; + }; + "/nix" = { + device = "/dev/ssds/colony-nix"; + fsType = "ext4"; + }; + "/persist" = { + device = "/dev/ssds/colony-persist"; + fsType = "ext4"; + neededForBoot = true; + }; + }; + services = { + lvm = { + boot.thin.enable = true; + dmeventd.enable = true; + }; + }; + + environment.systemPackages = with pkgs; [ + pciutils + ]; + + networking = { + interfaces = mkIf (!config.my.build.isDevVM) { + enp10s0.useDHCP = true; + }; + }; + + systemd = { + network = { + netdevs."25-base-bridge".netdevConfig = { + Name = "base"; + Kind = "bridge"; + }; + networks."80-base-bridge" = { + matchConfig = { + Name = "base"; + Driver = "bridge"; + }; + DHCP = "ipv4"; + networkConfig = { + IPv6AcceptRA = true; + }; + }; + }; + services."vm@estuary" = rec { + # Bind to the interface, networkd wait-online would deadlock... + requires = [ "sys-subsystem-net-devices-base.device" ]; + bindsTo = requires; + }; + }; + + #environment.etc."udev/udev.conf".text = "udev_log=debug"; + #systemd.services.systemd-networkd.environment.SYSTEMD_LOG_LEVEL = "debug"; + virtualisation = { + cores = 8; + memorySize = 8192; + qemu.options = [ + "-machine q35" + "-accel kvm,kernel-irqchip=split" + "-device intel-iommu,intremap=on,caching-mode=on" + ]; + }; + my = { + #deploy.generate.system.mode = "boot"; secrets = { - key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINkqdN5t3UKwrNOOPKlbnG1WYhnkV5H9luAzMotr8SbT"; + key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKp5WDdDr/1NS3SJIDOKwcCNZDFOxqPAD7cbZWAP7EkX"; files."test.txt" = {}; }; - firewall = { - trustedInterfaces = [ "virtual" ]; - nat = { - externalInterface = "eth0"; - forwardPorts = [ - { - proto = "tcp"; - sourcePort = 2222; - destination = "127.0.0.1:22"; - } - ]; - }; - }; server.enable = true; - containers = { - instances.vaultwarden = { - networking.bridge = "virtual"; - }; + network = { + ipv6 = "2a0e:97c0:4d1:0::2"; + ipv4 = "10.110.0.2"; }; + firewall = { + trustedInterfaces = [ "base" ]; + }; + + #containers = { + # instances.vaultwarden = { + # networking.bridge = "virtual"; + # }; + #}; vms = { - instances.test = { + instances.estuary = { uuid = "59f51efb-7e6d-477b-a263-ed9620dbc87b"; - networks.virtual.mac = "52:54:00:ab:f1:52"; + networks.base.mac = "52:54:00:ab:f1:52"; drives = { - disk = { + installer = { backend = { driver = "file"; filename = "${systems.installer.configuration.config.my.buildAs.iso}/iso/nixos.iso"; @@ -50,62 +119,31 @@ }; format.driver = "raw"; frontend = "ide-cd"; + frontendOpts = { + bootindex = 1; + }; + }; + disk = { + backend = { + driver = "host_device"; + filename = "/dev/ssds/vm-estuary"; + # It appears this needs to be set on the backend _and_ the format + discard = "unmap"; + }; + format = { + driver = "raw"; + discard = "unmap"; + }; + frontend = "virtio-blk"; frontendOpts = { bootindex = 0; }; }; }; + hostDevices."${wanBDF}" = { }; }; }; }; - - fileSystems = { - "/boot" = { - device = "/dev/disk/by-label/ESP"; - fsType = "vfat"; - }; - "/nix" = { - device = "/dev/disk/by-label/nix"; - fsType = "ext4"; - }; - "/persist" = { - device = "/dev/disk/by-label/persist"; - fsType = "ext4"; - neededForBoot = true; - }; - }; - - networking = { - interfaces = mkIf (!config.my.build.isDevVM) { - enp1s0.useDHCP = true; - }; - }; - - systemd.network = { - netdevs."25-virtual-bridge".netdevConfig = { - Name = "virtual"; - Kind = "bridge"; - }; - networks."80-virtual-bridge" = { - matchConfig = { - Name = "virtual"; - Driver = "bridge"; - }; - networkConfig = { - Address = "172.16.137.1/24"; - DHCPServer = true; - # TODO: Configuration for routed IPv6 (and maybe IPv4) - IPMasquerade = "both"; - IPv6SendRA = true; - }; - }; - }; - - #systemd.services.systemd-networkd.environment.SYSTEMD_LOG_LEVEL = "debug"; - virtualisation = { - cores = 8; - memorySize = 8192; - }; }; }; } diff --git a/nixos/installer.nix b/nixos/installer.nix index 1b0ccd2..2068049 100644 --- a/nixos/installer.nix +++ b/nixos/installer.nix @@ -13,14 +13,14 @@ in { imports = [ - # Lots of kernel modules and firmware - "${modulesPath}/profiles/all-hardware.nix" # Useful tools to have "${modulesPath}/profiles/base.nix" ]; config = { my = { + # Lots of kernel modules and firmware + build.allHardware = true; # Whatever installer mechanism is chosen will provide an appropriate `/` tmproot.enable = false; firewall.nat.enable = false; @@ -72,9 +72,6 @@ ''; environment.systemPackages = with pkgs; [ - # We disable networking.useDHCP, so bring these in for the user - # dhcpcd probably has more features, but dhclient actually seems a bit more simple - (pkgs.writeShellScriptBin "dhclient" ''exec ${pkgs.dhcp}/bin/dhclient -v "$@"'') dhcpcd ]; @@ -99,6 +96,7 @@ # download-using-manifests.pl from forking even if there is # plenty of free memory. boot.kernel.sysctl."vm.overcommit_memory" = "1"; + services.lvm.boot.thin.enable = true; }; }; }; diff --git a/nixos/modules/_list.nix b/nixos/modules/_list.nix index 84c5033..5f32c5d 100644 --- a/nixos/modules/_list.nix +++ b/nixos/modules/_list.nix @@ -11,5 +11,6 @@ secrets = ./secrets.nix; containers = ./containers.nix; vms = ./vms.nix; + network = ./network.nix; }; } diff --git a/nixos/modules/build.nix b/nixos/modules/build.nix index b795c88..c4023df 100644 --- a/nixos/modules/build.nix +++ b/nixos/modules/build.nix @@ -80,6 +80,7 @@ in sharedDirectories = dummyOption; cores = dummyOption; memorySize = dummyOption; + qemu.options = dummyOption; }; }; diff --git a/nixos/modules/common.nix b/nixos/modules/common.nix index c84c319..1fd5d0b 100644 --- a/nixos/modules/common.nix +++ b/nixos/modules/common.nix @@ -1,6 +1,6 @@ { lib, pkgs, pkgs', inputs, config, ... }: let - inherit (lib) flatten optional mkIf mkDefault mkMerge; + inherit (lib) mkIf mkDefault mkMerge; inherit (lib.my) mkBoolOpt' dummyOption; in { @@ -95,17 +95,11 @@ in }; }; - networking = { - domain = mkDefault "int.nul.ie"; - useDHCP = false; - enableIPv6 = mkDefault true; - useNetworkd = mkDefault true; - }; - environment.systemPackages = with pkgs; [ bash-completion vim ldns + minicom ]; programs = { @@ -141,14 +135,6 @@ in }) ]; }) - (mkIf config.my.build.isDevVM { - networking.interfaces.eth0.useDHCP = mkDefault true; - virtualisation = { - forwardPorts = flatten [ - (optional config.services.openssh.openFirewall { from = "host"; host.port = 2222; guest.port = 22; }) - ]; - }; - }) ]; meta.buildDocsInSandbox = false; diff --git a/nixos/modules/deploy-rs.nix b/nixos/modules/deploy-rs.nix index 64f4efc..8c227d9 100644 --- a/nixos/modules/deploy-rs.nix +++ b/nixos/modules/deploy-rs.nix @@ -1,11 +1,24 @@ { lib, pkgs, config, systems, ... }: let inherit (builtins) head attrNames; - inherit (lib) mkMerge mkIf mkDefault optionalAttrs mapAttrs'; + inherit (lib) mkMerge mkIf mkDefault optionalAttrs mapAttrs' optionalString; inherit (lib.my) mkOpt' mkBoolOpt'; cfg = config.my.deploy; + # Based on https://github.com/serokell/deploy-rs/blob/master/flake.nix + nixosActivate = mode: base: (pkgs.deploy-rs.lib.activate.custom // { dryActivate = "$PROFILE/bin/switch-to-configuration dry-activate"; }) base.config.system.build.toplevel '' + # work around https://github.com/NixOS/nixpkgs/issues/73404 + cd /tmp + + $PROFILE/bin/switch-to-configuration ${mode} + + # https://github.com/serokell/deploy-rs/issues/31 + ${with base.config.boot.loader; + optionalString ((mode == "switch" || mode == "boot") && systemd-boot.enable) + "sed -i '/^default /d' ${efi.efiSysMountPoint}/loader/loader.conf"} + ''; + ctrProfiles = optionalAttrs cfg.generate.containers.enable (mapAttrs' (n: c: let ctrConfig = systems."${n}".configuration.config; @@ -34,7 +47,10 @@ in inherit (lib.my.deploy-rs) node; generate = { - system.enable = mkBoolOpt' true "Whether to generate a deploy-rs profile for this system's config."; + system = { + enable = mkBoolOpt' true "Whether to generate a deploy-rs profile for this system's config."; + mode = mkOpt' str "switch" "switch-to-configuration mode."; + }; containers.enable = mkBoolOpt' true "Whether to generate deploy-rs profiles for this system's containers."; }; }; @@ -49,7 +65,7 @@ in profilesOrder = [ "system" ] ++ (attrNames ctrProfiles); profiles = { system = mkIf cfg.generate.system.enable { - path = pkgs.deploy-rs.lib.activate.nixos { inherit config; }; + path = nixosActivate cfg.generate.system.mode { inherit config; }; user = "root"; }; diff --git a/nixos/modules/network.nix b/nixos/modules/network.nix new file mode 100644 index 0000000..c705316 --- /dev/null +++ b/nixos/modules/network.nix @@ -0,0 +1,35 @@ +{ lib, config, ... }: +let + inherit (lib) flatten optional mkIf mkDefault mkMerge; + inherit (lib.my) mkOpt' mkBoolOpt'; + + cfg = config.my.network; +in +{ + options = with lib.types; { + my.network = { + ipv4 = mkOpt' str null "Internal network IPv4 address."; + ipv6 = mkOpt' str null "Internal network IPv6 address."; + }; + }; + + config = mkMerge [ + { + networking = { + domain = mkDefault "int.nul.ie"; + useDHCP = false; + enableIPv6 = mkDefault true; + useNetworkd = mkDefault true; + }; + } + + (mkIf config.my.build.isDevVM { + networking.interfaces.eth0.useDHCP = mkDefault true; + virtualisation = { + forwardPorts = flatten [ + (optional config.services.openssh.openFirewall { from = "host"; host.port = 2222; guest.port = 22; }) + ]; + }; + }) + ]; +} diff --git a/nixos/modules/secrets.nix b/nixos/modules/secrets.nix index 428b9c5..a2c2905 100644 --- a/nixos/modules/secrets.nix +++ b/nixos/modules/secrets.nix @@ -22,15 +22,14 @@ in # agenix sets this as a default but adding any custom extras will _replace_ the list (different priority) identityPaths = mkIf config.services.openssh.enable - (map (e: e.path) (lib.filter (e: e.type == "rsa" || e.type == "ed25519") config.services.openssh.hostKeys)); + (map + # Use the persit dir to grab the keys instead, otherwise they might not be ready. We can't really make + # agenix depend on impermanence, since users depends on agenix (to decrypt passwords) and impermanence + # depends on users + (e: let pDir = config.my.tmproot.persistence.dir; in if pDir != null then "${pDir}/${e.path}" else e.path) + (lib.filter (e: e.type == "rsa" || e.type == "ed25519") config.services.openssh.hostKeys)); }; } - (mkIf (config.age.secrets != { }) { - system.activationScripts.agenixMountSecrets.deps = mkIf (config.my.tmproot.persistence.dir != null) [ - # The key used to decrypt is not going to exist! - "persist-files" - ]; - }) (mkIf config.my.build.isDevVM { age.identityPaths = [ cfg.vmKeyPath ]; }) diff --git a/nixos/modules/vms.nix b/nixos/modules/vms.nix index d375b47..02d7a14 100644 --- a/nixos/modules/vms.nix +++ b/nixos/modules/vms.nix @@ -1,6 +1,9 @@ { lib, pkgs, config, ... }: let - inherit (lib) optional optionals optionalString flatten concatStringsSep mapAttrsToList mapAttrs' mkIf mkDefault; + inherit (builtins) filter any attrNames attrValues fetchGit; + inherit (lib) + unique optional optionals optionalString flatten concatStringsSep + concatMapStringsSep mapAttrsToList mapAttrs' mkIf mkDefault; inherit (lib.my) mkOpt' mkBoolOpt'; flattenQEMUOpts = attrs: @@ -38,6 +41,29 @@ let pass ''; + # TODO: Upstream or something... + vfio-pci-bind = pkgs.stdenv.mkDerivation rec { + pname = "vfio-pci-bind"; + version = "b41e4545b21de434fc51a34a9bf1d72e3ac66cc8"; + + src = fetchGit { + url = "https://github.com/andre-richter/vfio-pci-bind"; + rev = version; + }; + + prePatch = '' + substituteInPlace vfio-pci-bind.sh \ + --replace modprobe ${pkgs.kmod}/bin/modprobe + substituteInPlace 25-vfio-pci-bind.rules \ + --replace vfio-pci-bind.sh "$out"/bin/vfio-pci-bind.sh + ''; + installPhase = '' + mkdir -p "$out"/bin/ "$out"/lib/udev/rules.d + cp vfio-pci-bind.sh "$out"/bin/ + cp 25-vfio-pci-bind.rules "$out"/lib/udev/rules.d/ + ''; + }; + cfg = config.my.vms; netOpts = with lib.types; { name, ... }: { @@ -61,6 +87,12 @@ let }; }; + hostDevOpts = with lib.types; { + options = { + bindVFIO = mkBoolOpt' true "Whether to automatically bind the device to vfio-pci."; + }; + }; + vmOpts = with lib.types; { name, ... }: { options = { qemuBin = mkOpt' path "${pkgs.qemu_kvm}/bin/qemu-kvm" "Path to QEMU executable."; @@ -85,9 +117,16 @@ let spice.enable = mkBoolOpt' true "Whether to enable SPICE."; networks = mkOpt' (attrsOf (submodule netOpts)) { } "Networks to attach VM to."; drives = mkOpt' (attrsOf (submodule driveOpts)) { } "Drives to attach to VM."; + hostDevices = mkOpt' (attrsOf (submodule hostDevOpts)) { } "Host PCI devices to pass to the VM."; }; }; + allHostDevs = + flatten + (map + (i: mapAttrsToList (bdf: c: { inherit bdf; inherit (c) bindVFIO; }) i.hostDevices) + (attrValues cfg.instances)); + mkQemuCommand = n: i: let flags = @@ -122,7 +161,8 @@ let "blockdev node-name=${dn}-backend,${c.backend}" "blockdev node-name=${dn}-format,${c.formatBackendProp}=${dn}-backend,${c.format}" ("device ${c.frontend},id=${dn},drive=${dn}-format" + (extraQEMUOpts c.frontendOpts)) - ]) i.drives)); + ]) i.drives)) ++ + (map (bdf: "device vfio-pci,host=${bdf}") (attrNames i.hostDevices)); args = map (v: "-${v}") flags; in concatStringsSep " " ([ i.qemuBin ] ++ args); @@ -134,6 +174,30 @@ in }; config = mkIf (cfg.instances != { }) { + assertions = [ + { + assertion = let bdfs = map (d: d.bdf) allHostDevs; in (unique bdfs) == bdfs; + message = "VMs cannot share host devices!"; + } + ]; + + services.udev = { + packages = + optionals + (any (d: d.bindVFIO) allHostDevs) + [ + vfio-pci-bind + (pkgs.writeTextDir + "etc/udev/rules.d/20-vfio-tags.rules" + (concatMapStringsSep + "\n" + (d: ''ACTION=="add", SUBSYSTEM=="pci", KERNEL=="0000:${d.bdf}", TAG="vfio-pci-bind"'') + (filter (d: d.bindVFIO) allHostDevs))) + ]; + }; + + my.tmproot.persistence.config.directories = [ "/var/lib/vms" ]; + # qemu-bridge-helper will fail otherwise environment.etc."qemu/bridge.conf".text = "allow all"; systemd = { diff --git a/nixos/vms/estuary.nix b/nixos/vms/estuary.nix new file mode 100644 index 0000000..34ea11e --- /dev/null +++ b/nixos/vms/estuary.nix @@ -0,0 +1,101 @@ +{ + nixos.systems.estuary = { + system = "x86_64-linux"; + nixpkgs = "mine"; + home-manager = "unstable"; + + configuration = { lib, pkgs, modulesPath, config, systems, ... }: + let + inherit (lib) mkIf mkMerge; + in + { + imports = [ "${modulesPath}/profiles/qemu-guest.nix" ]; + + config = mkMerge [ + { + boot.kernelParams = [ "console=ttyS0,115200n8" ]; + fileSystems = { + "/boot" = { + device = "/dev/disk/by-label/ESP"; + fsType = "vfat"; + }; + "/nix" = { + device = "/dev/main/nix"; + fsType = "ext4"; + }; + "/persist" = { + device = "/dev/main/persist"; + fsType = "ext4"; + neededForBoot = true; + }; + }; + services = { + lvm = { + dmeventd.enable = true; + }; + }; + + systemd.network = { + links = { + "10-wan" = { + matchConfig.MACAddress = "52:54:00:a1:b2:5f"; + linkConfig.Name = "wan"; + }; + "10-base" = { + matchConfig.MACAddress = "52:54:00:ab:f1:52"; + linkConfig.Name = "base"; + }; + }; + + networks = { + #"80-wan" = { + # matchConfig.Name = "wan"; + # address = [ + # "1.2.3.4/24" + # "2a00::2/64" + # ]; + #}; + "80-wan" = { + matchConfig.Name = "wan"; + DHCP = "ipv4"; + }; + "80-base" = { + matchConfig.Name = "base"; + address = with config.my.network; [ "${ipv4}/24" "${ipv6}/64" ]; + networkConfig = { + DHCPServer = true; + IPv6SendRA = true; + IPMasquerade = "both"; + }; + }; + }; + }; + + my = { + server.enable = true; + + network = { + ipv6 = "2a0e:97c0:4d1:0::1"; + ipv4 = "10.110.0.1"; + }; + firewall = { + trustedInterfaces = [ "base" ]; + nat = { + enable = true; + externalInterface = "wan"; + }; + }; + }; + } + (mkIf config.my.build.isDevVM { + systemd.network = { + netdevs."05-dummy-base".netdevConfig = { + Name = "base"; + Kind = "dummy"; + }; + }; + }) + ]; + }; + }; +} diff --git a/secrets/test.txt.age b/secrets/test.txt.age index f3bd459..588ff65 100644 Binary files a/secrets/test.txt.age and b/secrets/test.txt.age differ diff --git a/secrets/vaultwarden.env.age b/secrets/vaultwarden.env.age index 86cc13f..97aa29d 100644 Binary files a/secrets/vaultwarden.env.age and b/secrets/vaultwarden.env.age differ