at 25.11-pre 7.1 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7let 8 cfg = config.virtualisation.virtualbox.host; 9 10 virtualbox = cfg.package.override { 11 inherit (cfg) 12 enableHardening 13 headless 14 enableWebService 15 enableKvm 16 ; 17 extensionPack = if cfg.enableExtensionPack then pkgs.virtualboxExtpack else null; 18 }; 19 20 kernelModules = config.boot.kernelPackages.virtualbox.override { 21 inherit virtualbox; 22 }; 23 24in 25 26{ 27 options.virtualisation.virtualbox.host = { 28 enable = lib.mkEnableOption "VirtualBox" // { 29 description = '' 30 Whether to enable VirtualBox. 31 32 ::: {.note} 33 In order to pass USB devices from the host to the guests, the user 34 needs to be in the `vboxusers` group. 35 ::: 36 ''; 37 }; 38 39 enableExtensionPack = lib.mkEnableOption "VirtualBox extension pack" // { 40 description = '' 41 Whether to install the Oracle Extension Pack for VirtualBox. 42 43 ::: {.important} 44 You must set `nixpkgs.config.allowUnfree = true` in 45 order to use this. This requires you accept the VirtualBox PUEL. 46 ::: 47 ''; 48 }; 49 50 package = lib.mkPackageOption pkgs "virtualbox" { }; 51 52 addNetworkInterface = lib.mkOption { 53 type = lib.types.bool; 54 default = true; 55 description = '' 56 Automatically set up a vboxnet0 host-only network interface. 57 ''; 58 }; 59 60 enableHardening = lib.mkOption { 61 type = lib.types.bool; 62 default = true; 63 description = '' 64 Enable hardened VirtualBox, which ensures that only the binaries in the 65 system path get access to the devices exposed by the kernel modules 66 instead of all users in the vboxusers group. 67 68 ::: {.important} 69 Disabling this can put your system's security at risk, as local users 70 in the vboxusers group can tamper with the VirtualBox device files. 71 ::: 72 ''; 73 }; 74 75 headless = lib.mkOption { 76 type = lib.types.bool; 77 default = false; 78 description = '' 79 Use VirtualBox installation without GUI and Qt dependency. Useful to enable on servers 80 and when virtual machines are controlled only via SSH. 81 ''; 82 }; 83 84 enableWebService = lib.mkOption { 85 type = lib.types.bool; 86 default = false; 87 description = '' 88 Build VirtualBox web service tool (vboxwebsrv) to allow managing VMs via other webpage frontend tools. Useful for headless servers. 89 ''; 90 }; 91 92 enableKvm = lib.mkOption { 93 type = lib.types.bool; 94 default = false; 95 description = '' 96 Enable KVM support for VirtualBox. This increases compatibility with Linux kernel versions, because the VirtualBox kernel modules 97 are not required. 98 99 This option is incompatible with `addNetworkInterface`. 100 101 Note: This is experimental. Please check https://github.com/cyberus-technology/virtualbox-kvm/issues. 102 ''; 103 }; 104 }; 105 106 config = lib.mkIf cfg.enable ( 107 lib.mkMerge [ 108 { 109 warnings = lib.mkIf (pkgs.config.virtualbox.enableExtensionPack or false) [ 110 "'nixpkgs.virtualbox.enableExtensionPack' has no effect, please use 'virtualisation.virtualbox.host.enableExtensionPack'" 111 ]; 112 environment.systemPackages = [ virtualbox ]; 113 114 security.wrappers = 115 let 116 mkSuid = program: { 117 source = "${virtualbox}/libexec/virtualbox/${program}"; 118 owner = "root"; 119 group = "vboxusers"; 120 setuid = true; 121 }; 122 executables = 123 [ 124 "VBoxHeadless" 125 "VBoxNetAdpCtl" 126 "VBoxNetDHCP" 127 "VBoxNetNAT" 128 "VBoxVolInfo" 129 ] 130 ++ (lib.optionals (!cfg.headless) [ 131 "VBoxSDL" 132 "VirtualBoxVM" 133 ]); 134 in 135 lib.mkIf cfg.enableHardening ( 136 builtins.listToAttrs ( 137 map (x: { 138 name = x; 139 value = mkSuid x; 140 }) executables 141 ) 142 ); 143 144 users.groups.vboxusers.gid = config.ids.gids.vboxusers; 145 146 services.udev.extraRules = '' 147 SUBSYSTEM=="usb_device", ACTION=="add", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh $major $minor $attr{bDeviceClass}" 148 SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh $major $minor $attr{bDeviceClass}" 149 SUBSYSTEM=="usb_device", ACTION=="remove", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh --remove $major $minor" 150 SUBSYSTEM=="usb", ACTION=="remove", ENV{DEVTYPE}=="usb_device", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh --remove $major $minor" 151 ''; 152 } 153 (lib.mkIf cfg.enableKvm { 154 assertions = [ 155 { 156 assertion = !cfg.addNetworkInterface; 157 message = "VirtualBox KVM only supports standard NAT networking for VMs. Please turn off virtualisation.virtualbox.host.addNetworkInterface."; 158 } 159 ]; 160 }) 161 (lib.mkIf (!cfg.enableKvm) { 162 boot.kernelModules = [ 163 "vboxdrv" 164 "vboxnetadp" 165 "vboxnetflt" 166 ]; 167 boot.extraModulePackages = [ kernelModules ]; 168 169 services.udev.extraRules = '' 170 KERNEL=="vboxdrv", OWNER="root", GROUP="vboxusers", MODE="0660", TAG+="systemd" 171 KERNEL=="vboxdrvu", OWNER="root", GROUP="root", MODE="0666", TAG+="systemd" 172 KERNEL=="vboxnetctl", OWNER="root", GROUP="vboxusers", MODE="0660", TAG+="systemd" 173 ''; 174 175 # Since we lack the right setuid/setcap binaries, set up a host-only network by default. 176 }) 177 (lib.mkIf cfg.addNetworkInterface { 178 systemd.services.vboxnet0 = { 179 description = "VirtualBox vboxnet0 Interface"; 180 requires = [ "dev-vboxnetctl.device" ]; 181 after = [ "dev-vboxnetctl.device" ]; 182 wantedBy = [ 183 "network.target" 184 "sys-subsystem-net-devices-vboxnet0.device" 185 ]; 186 path = [ virtualbox ]; 187 serviceConfig.RemainAfterExit = true; 188 serviceConfig.Type = "oneshot"; 189 serviceConfig.PrivateTmp = true; 190 environment.VBOX_USER_HOME = "/tmp"; 191 script = '' 192 if ! [ -e /sys/class/net/vboxnet0 ]; then 193 VBoxManage hostonlyif create 194 cat /tmp/VBoxSVC.log >&2 195 fi 196 ''; 197 postStop = '' 198 VBoxManage hostonlyif remove vboxnet0 199 ''; 200 }; 201 202 networking.interfaces.vboxnet0.ipv4.addresses = [ 203 { 204 address = "192.168.56.1"; 205 prefixLength = 24; 206 } 207 ]; 208 # Make sure NetworkManager won't assume this interface being up 209 # means we have internet access. 210 networking.networkmanager.unmanaged = [ "vboxnet0" ]; 211 }) 212 (lib.mkIf config.networking.useNetworkd { 213 systemd.network.networks."40-vboxnet0".extraConfig = '' 214 [Link] 215 RequiredForOnline=no 216 ''; 217 }) 218 219 ] 220 ); 221}