diff options
Diffstat (limited to 'nixos/modules/virtualisation')
-rw-r--r-- | nixos/modules/virtualisation/brightbox-config.nix | 5 | ||||
-rw-r--r-- | nixos/modules/virtualisation/brightbox-image.nix | 166 | ||||
-rw-r--r-- | nixos/modules/virtualisation/containers.nix | 14 | ||||
-rw-r--r-- | nixos/modules/virtualisation/docker.nix | 36 | ||||
-rw-r--r-- | nixos/modules/virtualisation/openvswitch.nix | 6 | ||||
-rw-r--r-- | nixos/modules/virtualisation/virtualbox-guest.nix | 19 | ||||
-rw-r--r-- | nixos/modules/virtualisation/virtualbox-host.nix | 115 | ||||
-rw-r--r-- | nixos/modules/virtualisation/virtualbox-image.nix | 2 | ||||
-rw-r--r-- | nixos/modules/virtualisation/xen-dom0.nix | 10 |
9 files changed, 347 insertions, 26 deletions
diff --git a/nixos/modules/virtualisation/brightbox-config.nix b/nixos/modules/virtualisation/brightbox-config.nix new file mode 100644 index 000000000000..528ffecc0bf2 --- /dev/null +++ b/nixos/modules/virtualisation/brightbox-config.nix @@ -0,0 +1,5 @@ +{ config, pkgs, modulesPath, ... }: + +{ + imports = [ "${modulesPath}/virtualisation/brightbox-image.nix" ]; +} diff --git a/nixos/modules/virtualisation/brightbox-image.nix b/nixos/modules/virtualisation/brightbox-image.nix new file mode 100644 index 000000000000..3a956caca0c3 --- /dev/null +++ b/nixos/modules/virtualisation/brightbox-image.nix @@ -0,0 +1,166 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + diskSize = "20G"; +in +{ + imports = [ ../profiles/headless.nix ../profiles/qemu-guest.nix ]; + + system.build.brightboxImage = + pkgs.vmTools.runInLinuxVM ( + pkgs.runCommand "brightbox-image" + { preVM = + '' + mkdir $out + diskImage=$out/$diskImageBase + truncate $diskImage --size ${diskSize} + mv closure xchg/ + ''; + + postVM = + '' + PATH=$PATH:${pkgs.gnutar}/bin:${pkgs.gzip}/bin + pushd $out + ${pkgs.qemu_kvm}/bin/qemu-img convert -c -O qcow2 $diskImageBase nixos.qcow2 + rm $diskImageBase + popd + ''; + diskImageBase = "nixos-${config.system.nixosVersion}-${pkgs.stdenv.system}.raw"; + buildInputs = [ pkgs.utillinux pkgs.perl ]; + exportReferencesGraph = + [ "closure" config.system.build.toplevel ]; + } + '' + # Create partition table + ${pkgs.parted}/sbin/parted /dev/vda mklabel msdos + ${pkgs.parted}/sbin/parted /dev/vda mkpart primary ext4 1 ${diskSize} + ${pkgs.parted}/sbin/parted /dev/vda print + . /sys/class/block/vda1/uevent + mknod /dev/vda1 b $MAJOR $MINOR + + # Create an empty filesystem and mount it. + ${pkgs.e2fsprogs}/sbin/mkfs.ext4 -L nixos /dev/vda1 + ${pkgs.e2fsprogs}/sbin/tune2fs -c 0 -i 0 /dev/vda1 + + mkdir /mnt + mount /dev/vda1 /mnt + + # The initrd expects these directories to exist. + mkdir /mnt/dev /mnt/proc /mnt/sys + + mount --bind /proc /mnt/proc + mount --bind /dev /mnt/dev + mount --bind /sys /mnt/sys + + # Copy all paths in the closure to the filesystem. + storePaths=$(perl ${pkgs.pathsFromGraph} /tmp/xchg/closure) + + mkdir -p /mnt/nix/store + echo "copying everything (will take a while)..." + cp -prd $storePaths /mnt/nix/store/ + + # Register the paths in the Nix database. + printRegistration=1 perl ${pkgs.pathsFromGraph} /tmp/xchg/closure | \ + chroot /mnt ${config.nix.package}/bin/nix-store --load-db --option build-users-group "" + + # Create the system profile to allow nixos-rebuild to work. + chroot /mnt ${config.nix.package}/bin/nix-env \ + -p /nix/var/nix/profiles/system --set ${config.system.build.toplevel} \ + --option build-users-group "" + + # `nixos-rebuild' requires an /etc/NIXOS. + mkdir -p /mnt/etc + touch /mnt/etc/NIXOS + + # `switch-to-configuration' requires a /bin/sh + mkdir -p /mnt/bin + ln -s ${config.system.build.binsh}/bin/sh /mnt/bin/sh + + # Install a configuration.nix. + mkdir -p /mnt/etc/nixos /mnt/boot/grub + cp ${./brightbox-config.nix} /mnt/etc/nixos/configuration.nix + + # Generate the GRUB menu. + ln -s vda /dev/sda + chroot /mnt ${config.system.build.toplevel}/bin/switch-to-configuration boot + + umount /mnt/proc /mnt/dev /mnt/sys + umount /mnt + '' + ); + + fileSystems."/".label = "nixos"; + + # Generate a GRUB menu. Amazon's pv-grub uses this to boot our kernel/initrd. + boot.loader.grub.device = "/dev/vda"; + boot.loader.grub.timeout = 0; + + # Don't put old configurations in the GRUB menu. The user has no + # way to select them anyway. + boot.loader.grub.configurationLimit = 0; + + # Allow root logins only using the SSH key that the user specified + # at instance creation time. + services.openssh.enable = true; + services.openssh.permitRootLogin = "without-password"; + + # Force getting the hostname from Google Compute. + networking.hostName = mkDefault ""; + + # Always include cryptsetup so that NixOps can use it. + environment.systemPackages = [ pkgs.cryptsetup ]; + + systemd.services."fetch-ec2-data" = + { description = "Fetch EC2 Data"; + + wantedBy = [ "multi-user.target" "sshd.service" ]; + before = [ "sshd.service" ]; + wants = [ "ip-up.target" ]; + after = [ "ip-up.target" ]; + + path = [ pkgs.wget pkgs.iproute ]; + + script = + '' + wget="wget -q --retry-connrefused -O -" + + ${optionalString (config.networking.hostName == "") '' + echo "setting host name..." + ${pkgs.nettools}/bin/hostname $($wget http://169.254.169.254/latest/meta-data/hostname) + ''} + + # Don't download the SSH key if it has already been injected + # into the image (a Nova feature). + if ! [ -e /root/.ssh/authorized_keys ]; then + echo "obtaining SSH key..." + mkdir -m 0700 -p /root/.ssh + $wget http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key > /root/key.pub + if [ $? -eq 0 -a -e /root/key.pub ]; then + if ! grep -q -f /root/key.pub /root/.ssh/authorized_keys; then + cat /root/key.pub >> /root/.ssh/authorized_keys + echo "new key added to authorized_keys" + fi + chmod 600 /root/.ssh/authorized_keys + rm -f /root/key.pub + fi + fi + + # Extract the intended SSH host key for this machine from + # the supplied user data, if available. Otherwise sshd will + # generate one normally. + $wget http://169.254.169.254/2011-01-01/user-data > /root/user-data || true + key="$(sed 's/|/\n/g; s/SSH_HOST_DSA_KEY://; t; d' /root/user-data)" + key_pub="$(sed 's/SSH_HOST_DSA_KEY_PUB://; t; d' /root/user-data)" + if [ -n "$key" -a -n "$key_pub" -a ! -e /etc/ssh/ssh_host_dsa_key ]; then + mkdir -m 0755 -p /etc/ssh + (umask 077; echo "$key" > /etc/ssh/ssh_host_dsa_key) + echo "$key_pub" > /etc/ssh/ssh_host_dsa_key.pub + fi + ''; + + serviceConfig.Type = "oneshot"; + serviceConfig.RemainAfterExit = true; + }; + +} diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix index da39dda85353..59f486ff78b7 100644 --- a/nixos/modules/virtualisation/containers.nix +++ b/nixos/modules/virtualisation/containers.nix @@ -120,6 +120,15 @@ in ''; }; + interfaces = mkOption { + type = types.listOf types.string; + default = []; + example = [ "eth1" "eth2" ]; + description = '' + The list of interfaces to be moved into the container. + ''; + }; + autoStart = mkOption { type = types.bool; default = false; @@ -218,6 +227,10 @@ in extraFlags+=" --network-veth" fi + for iface in $INTERFACES; do + extraFlags+=" --network-interface=$iface" + done + for iface in $MACVLANS; do extraFlags+=" --network-macvlan=$iface" done @@ -331,6 +344,7 @@ in LOCAL_ADDRESS=${cfg.localAddress} ''} ''} + INTERFACES="${toString cfg.interfaces}" ${optionalString cfg.autoStart '' AUTO_START=1 ''} diff --git a/nixos/modules/virtualisation/docker.nix b/nixos/modules/virtualisation/docker.nix index ef9cc2280db7..ba078cc0a11f 100644 --- a/nixos/modules/virtualisation/docker.nix +++ b/nixos/modules/virtualisation/docker.nix @@ -43,6 +43,17 @@ in in future. So set this option explicitly to false if you wish. ''; }; + storageDriver = + mkOption { + type = types.enum ["aufs" "btrfs" "devicemapper" "overlay" "zfs"]; + description = + '' + This option determines which Docker storage driver to use. + It is required but lacks a default value as its most + suitable value will depend the filesystems available on the + host. + ''; + }; extraOptions = mkOption { type = types.separatedString " "; @@ -54,6 +65,21 @@ in ''; }; + postStart = + mkOption { + type = types.string; + default = '' + while ! [ -e /var/run/docker.sock ]; do + sleep 0.1 + done + ''; + description = '' + The postStart phase of the systemd service. You may need to + override this if you are passing in flags to docker which + don't cause the socket file to be created. + ''; + }; + }; @@ -70,7 +96,7 @@ in after = [ "network.target" "docker.socket" ]; requires = [ "docker.socket" ]; serviceConfig = { - ExecStart = "${pkgs.docker}/bin/docker --daemon=true --host=fd:// --group=docker ${cfg.extraOptions}"; + ExecStart = "${pkgs.docker}/bin/docker daemon --host=fd:// --group=docker --storage-driver=${cfg.storageDriver} ${cfg.extraOptions}"; # I'm not sure if that limits aren't too high, but it's what # goes in config bundled with docker itself LimitNOFILE = 1048576; @@ -96,7 +122,7 @@ in wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; serviceConfig = { - ExecStart = "${pkgs.docker}/bin/docker --daemon=true --group=docker ${cfg.extraOptions}"; + ExecStart = "${pkgs.docker}/bin/docker daemon --group=docker --storage-driver=${cfg.storageDriver} ${cfg.extraOptions}"; # I'm not sure if that limits aren't too high, but it's what # goes in config bundled with docker itself LimitNOFILE = 1048576; @@ -106,11 +132,7 @@ in path = [ pkgs.kmod ]; environment.MODULE_DIR = "/run/current-system/kernel-modules/lib/modules"; - postStart = '' - while ! [ -e /var/run/docker.sock ]; do - sleep 0.1 - done - ''; + postStart = cfg.postStart; # Presumably some containers are running we don't want to interrupt restartIfChanged = false; diff --git a/nixos/modules/virtualisation/openvswitch.nix b/nixos/modules/virtualisation/openvswitch.nix index 69ca13a71479..b5155246fdad 100644 --- a/nixos/modules/virtualisation/openvswitch.nix +++ b/nixos/modules/virtualisation/openvswitch.nix @@ -67,7 +67,6 @@ in { description = "Open_vSwitch Database Server"; wantedBy = [ "multi-user.target" ]; after = [ "systemd-udev-settle.service" ]; - wants = [ "vswitchd.service" ]; path = [ cfg.package ]; restartTriggers = [ db cfg.package ]; # Create the config database @@ -108,6 +107,7 @@ in { systemd.services.vswitchd = { description = "Open_vSwitch Daemon"; + wantedBy = [ "multi-user.target" ]; bindsTo = [ "ovsdb.service" ]; after = [ "ovsdb.service" ]; path = [ cfg.package ]; @@ -135,8 +135,8 @@ in { systemd.services.ovs-monitor-ipsec = { description = "Open_vSwitch Ipsec Daemon"; wantedBy = [ "multi-user.target" ]; - requires = [ "racoon.service" ]; - after = [ "vswitchd.service" ]; + requires = [ "ovsdb.service" ]; + before = [ "vswitchd.service" "racoon.service" ]; environment.UNIXCTLPATH = "/tmp/ovsdb.ctl.sock"; serviceConfig = { ExecStart = '' diff --git a/nixos/modules/virtualisation/virtualbox-guest.nix b/nixos/modules/virtualisation/virtualbox-guest.nix index a0e4bd558e05..642ea3154b1b 100644 --- a/nixos/modules/virtualisation/virtualbox-guest.nix +++ b/nixos/modules/virtualisation/virtualbox-guest.nix @@ -6,7 +6,7 @@ with lib; let - cfg = config.services.virtualboxGuest; + cfg = config.virtualisation.virtualbox.guest; kernel = config.boot.kernelPackages; in @@ -15,20 +15,11 @@ in ###### interface - options = { - - services.virtualboxGuest = { - - enable = mkOption { - default = false; - description = "Whether to enable the VirtualBox service and other guest additions."; - }; - - }; - + options.virtualisation.virtualbox.guest.enable = mkOption { + default = false; + description = "Whether to enable the VirtualBox service and other guest additions."; }; - ###### implementation config = mkIf cfg.enable { @@ -54,7 +45,7 @@ in unitConfig.ConditionVirtualization = "oracle"; - serviceConfig.ExecStart = "@${kernel.virtualboxGuestAdditions}/sbin/VBoxService VBoxService --foreground"; + serviceConfig.ExecStart = "@${kernel.virtualboxGuestAdditions}/bin/VBoxService VBoxService --foreground"; }; services.xserver.videoDrivers = mkOverride 50 [ "virtualbox" ]; diff --git a/nixos/modules/virtualisation/virtualbox-host.nix b/nixos/modules/virtualisation/virtualbox-host.nix new file mode 100644 index 000000000000..00486df5c4ba --- /dev/null +++ b/nixos/modules/virtualisation/virtualbox-host.nix @@ -0,0 +1,115 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.virtualisation.virtualbox.host; + virtualbox = config.boot.kernelPackages.virtualbox.override { + inherit (cfg) enableHardening; + }; + +in + +{ + options.virtualisation.virtualbox.host = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable VirtualBox. + + <note><para> + In order to pass USB devices from the host to the guests, the user + needs to be in the <literal>vboxusers</literal> group. + </para></note> + ''; + }; + + addNetworkInterface = mkOption { + type = types.bool; + default = true; + description = '' + Automatically set up a vboxnet0 host-only network interface. + ''; + }; + + enableHardening = mkOption { + type = types.bool; + default = true; + description = '' + Enable hardened VirtualBox, which ensures that only the binaries in the + system path get access to the devices exposed by the kernel modules + instead of all users in the vboxusers group. + + <important><para> + Disabling this can put your system's security at risk, as local users + in the vboxusers group can tamper with the VirtualBox device files. + </para></important> + ''; + }; + }; + + config = mkIf cfg.enable (mkMerge [{ + boot.kernelModules = [ "vboxdrv" "vboxnetadp" "vboxnetflt" ]; + boot.extraModulePackages = [ virtualbox ]; + environment.systemPackages = [ virtualbox ]; + + security.setuidOwners = let + mkSuid = program: { + inherit program; + source = "${virtualbox}/libexec/virtualbox/${program}"; + owner = "root"; + group = "vboxusers"; + setuid = true; + }; + in mkIf cfg.enableHardening (map mkSuid [ + "VBoxHeadless" + "VBoxNetAdpCtl" + "VBoxNetDHCP" + "VBoxNetNAT" + "VBoxSDL" + "VBoxVolInfo" + "VirtualBox" + ]); + + users.extraGroups.vboxusers.gid = config.ids.gids.vboxusers; + + services.udev.extraRules = + '' + KERNEL=="vboxdrv", OWNER="root", GROUP="vboxusers", MODE="0660", TAG+="systemd" + KERNEL=="vboxdrvu", OWNER="root", GROUP="root", MODE="0666", TAG+="systemd" + KERNEL=="vboxnetctl", OWNER="root", GROUP="vboxusers", MODE="0660", TAG+="systemd" + SUBSYSTEM=="usb_device", ACTION=="add", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh $major $minor $attr{bDeviceClass}" + SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh $major $minor $attr{bDeviceClass}" + SUBSYSTEM=="usb_device", ACTION=="remove", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh --remove $major $minor" + SUBSYSTEM=="usb", ACTION=="remove", ENV{DEVTYPE}=="usb_device", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh --remove $major $minor" + ''; + + # Since we lack the right setuid binaries, set up a host-only network by default. + } (mkIf cfg.addNetworkInterface { + systemd.services."vboxnet0" = + { description = "VirtualBox vboxnet0 Interface"; + requires = [ "dev-vboxnetctl.device" ]; + after = [ "dev-vboxnetctl.device" ]; + wantedBy = [ "network.target" "sys-subsystem-net-devices-vboxnet0.device" ]; + path = [ virtualbox ]; + serviceConfig.RemainAfterExit = true; + serviceConfig.Type = "oneshot"; + serviceConfig.PrivateTmp = true; + environment.VBOX_USER_HOME = "/tmp"; + script = + '' + if ! [ -e /sys/class/net/vboxnet0 ]; then + VBoxManage hostonlyif create + cat /tmp/VBoxSVC.log >&2 + fi + ''; + postStop = + '' + VBoxManage hostonlyif remove vboxnet0 + ''; + }; + + networking.interfaces.vboxnet0.ip4 = [ { address = "192.168.56.1"; prefixLength = 24; } ]; + })]); +} diff --git a/nixos/modules/virtualisation/virtualbox-image.nix b/nixos/modules/virtualisation/virtualbox-image.nix index 8232f6e50dfc..c1538feb9df5 100644 --- a/nixos/modules/virtualisation/virtualbox-image.nix +++ b/nixos/modules/virtualisation/virtualbox-image.nix @@ -128,6 +128,6 @@ in { boot.loader.grub.version = 2; boot.loader.grub.device = "/dev/sda"; - services.virtualboxGuest.enable = true; + virtualisation.virtualbox.guest.enable = true; }; } diff --git a/nixos/modules/virtualisation/xen-dom0.nix b/nixos/modules/virtualisation/xen-dom0.nix index c750286a3970..a0b2d5363eb2 100644 --- a/nixos/modules/virtualisation/xen-dom0.nix +++ b/nixos/modules/virtualisation/xen-dom0.nix @@ -121,6 +121,10 @@ in "xenfs" ]; + # The xenfs module is needed in system.activationScripts.xen, but + # the modprobe command there fails silently. Include xenfs in the + # initrd as a work around. + boot.initrd.kernelModules = [ "xenfs" ]; # The radeonfb kernel module causes the screen to go black as soon # as it's loaded, so don't load it. @@ -182,6 +186,9 @@ in { source = "${pkgs.xen}/etc/xen/scripts"; target = "xen/scripts"; } + { source = "${pkgs.xen}/etc/default/xendomains"; + target = "default/xendomains"; + } ]; # Xen provides udev rules. @@ -199,7 +206,8 @@ in rm -f "$XENSTORED_ROOTDIR"/tdb* &>/dev/null mkdir -p /var/run - ${optionalString cfg.trace "mkdir -p /var/log/xen"} + mkdir -p /var/log/xen # Running xl requires /var/log/xen and /var/lib/xen, + mkdir -p /var/lib/xen # so we create them here unconditionally. grep -q control_d /proc/xen/capabilities ''; serviceConfig.ExecStart = '' |