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