at master 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 "VBoxHeadless" 124 "VBoxNetAdpCtl" 125 "VBoxNetDHCP" 126 "VBoxNetNAT" 127 "VBoxVolInfo" 128 ] 129 ++ (lib.optionals (!cfg.headless) [ 130 "VBoxSDL" 131 "VirtualBoxVM" 132 ]); 133 in 134 lib.mkIf cfg.enableHardening ( 135 builtins.listToAttrs ( 136 map (x: { 137 name = x; 138 value = mkSuid x; 139 }) executables 140 ) 141 ); 142 143 users.groups.vboxusers.gid = config.ids.gids.vboxusers; 144 145 services.udev.extraRules = '' 146 SUBSYSTEM=="usb_device", ACTION=="add", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh $major $minor $attr{bDeviceClass}" 147 SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh $major $minor $attr{bDeviceClass}" 148 SUBSYSTEM=="usb_device", ACTION=="remove", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh --remove $major $minor" 149 SUBSYSTEM=="usb", ACTION=="remove", ENV{DEVTYPE}=="usb_device", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh --remove $major $minor" 150 ''; 151 } 152 (lib.mkIf cfg.enableKvm { 153 assertions = [ 154 { 155 assertion = !cfg.addNetworkInterface; 156 message = "VirtualBox KVM only supports standard NAT networking for VMs. Please turn off virtualisation.virtualbox.host.addNetworkInterface."; 157 } 158 ]; 159 }) 160 (lib.mkIf (!cfg.enableKvm) { 161 boot.kernelModules = [ 162 "vboxdrv" 163 "vboxnetadp" 164 "vboxnetflt" 165 ]; 166 boot.extraModulePackages = [ kernelModules ]; 167 168 services.udev.extraRules = '' 169 KERNEL=="vboxdrv", OWNER="root", GROUP="vboxusers", MODE="0660", TAG+="systemd" 170 KERNEL=="vboxdrvu", OWNER="root", GROUP="root", MODE="0666", TAG+="systemd" 171 KERNEL=="vboxnetctl", OWNER="root", GROUP="vboxusers", MODE="0660", TAG+="systemd" 172 ''; 173 174 # Since we lack the right setuid/setcap binaries, set up a host-only network by default. 175 }) 176 (lib.mkIf cfg.addNetworkInterface { 177 systemd.services.vboxnet0 = { 178 description = "VirtualBox vboxnet0 Interface"; 179 requires = [ "dev-vboxnetctl.device" ]; 180 after = [ "dev-vboxnetctl.device" ]; 181 wantedBy = [ 182 "network.target" 183 "sys-subsystem-net-devices-vboxnet0.device" 184 ]; 185 path = [ virtualbox ]; 186 serviceConfig.RemainAfterExit = true; 187 serviceConfig.Type = "oneshot"; 188 serviceConfig.PrivateTmp = true; 189 environment.VBOX_USER_HOME = "/tmp"; 190 script = '' 191 if ! [ -e /sys/class/net/vboxnet0 ]; then 192 VBoxManage hostonlyif create 193 cat /tmp/VBoxSVC.log >&2 194 fi 195 ''; 196 postStop = '' 197 VBoxManage hostonlyif remove vboxnet0 198 ''; 199 }; 200 201 networking.interfaces.vboxnet0.ipv4.addresses = [ 202 { 203 address = "192.168.56.1"; 204 prefixLength = 24; 205 } 206 ]; 207 # Make sure NetworkManager won't assume this interface being up 208 # means we have internet access. 209 networking.networkmanager.unmanaged = [ "vboxnet0" ]; 210 }) 211 (lib.mkIf config.networking.useNetworkd { 212 systemd.network.networks."40-vboxnet0".extraConfig = '' 213 [Link] 214 RequiredForOnline=no 215 ''; 216 }) 217 218 ] 219 ); 220}