Configure vmm on OpenBSD
OpenBSD can support virtual machines with vmd(8). The guide below is inspired by the virtualization guide from the OpenBSD FAQ.
vmd requires a processor that supports SLAT for AMD or EPT for Intel. Check support with this command:
$ dmesg | egrep '(VMX/EPT|SVM/RVI)'
Once you have confirmed your hardware can handle virtualization, install vmm-firmware:
$ doas fw_update
By default, there are only four tap interfaces. We need to create sufficient devices for all our virtual machines:
# cd /dev # for i in $(jot 50 4 50); do sh MAKEDEV tap$i; done
We'll increase arpq because we may have many virtual machines on the same switch:
# sysctl net.inet.ip.arpq.maxlen=1024 # echo "net.inet.ip.arpq.maxlen=1024" >> /etc/sysctl.conf
We will need to permit IPv4 and IPv6 forwarding for our virtual machines:
# sysctl net.inet.ip.forwarding=1 # echo "net.inet.ip.forwarding=1" >> /etc/sysctl.conf # sysctl net.inet6.ip6.forwarding=1 # echo "net.inet6.ip6.forwarding=1" >> /etc/sysctl.conf
Configuring networking devices
We need a bridge to connect together all the tap? interfaces from our virtual machines. Although we could use bridge?, veb may offer better performance. We will therefore combine veb and vport? together to handle routing of traffic from tap(4) interfaces.
# cat /etc/hostname.veb0 add vport0 link1 # cat /etc/hostname.vport0 inet 192.168.0.1 255.255.255.0 inet6 2001:db8:: 48 up
Replace 192.168.0.1
with the actual IP address you intend to use as the
default gateway. Replace 255.255.255.0
with the correct subnet mask.
Similarly, replace 2001:db8:: with your actual IPv6 subnet, and replace 48
with the correct subnet mask.
For veb0
, we specify link1
in order to allow filtering on this
interface (see veb(4)).
NOTE: You must add up
in /etc/hostname.vport0
.
vport(4) interfaces do not come up
automatically.
Configuring vm.conf
We create vm.conf(5):
# cat /etc/vm.conf socket owner :vmdusers switch "switch0" { group vms locked lladdr interface veb0 } obsd="/home/iso/install75.iso" vm "username" { owner username memory 2048M cdrom $obsd disk /home/username/username.qcow2 format qcow2 interface tap0 { locked lladdr aa:bb:cc:dd:ee:01 switch "switch0" } }
First, we set group vmdusers
as the owner of the /var/run/vmd.sock
. Only users in the vmdusers
group will be able to start or stop virtual machine with vmctl.
Next, we define a virtual switch block for switch0
. The interface will belong to group vms
, which provides us an easy way to filter with pf?. locked lladdr
prevents spoofing of hardware addresses. veb0
will be the network interface used by the switch.
We then define a macro for the OpenBSD ISO.
Next, we define a virtual machine named username
owned by username
with 2GB of memory, the CDROM with the OpenBSD ISO, and we lock the networking interface to tap0
and explicitly define a hardware address. We put this interface on switch0
.
WARNING: Do not use aa:bb:cc:dd:ee:xx. This must be replaced with your own random lladdr address.
WARNING: Do not pick a broadcast MAC address. If the first octet of the address is an odd number (such as f1:xx:xx:xx:xx:xx or f3:xx:xx:xx:xx:xx), it will appear as a broadcast device and may be the cause of routing issues.
Preparing ISO files
Next, we download our OpenBSD ISO.
$ doas useradd -m -g =uid -c "iso" -d /home/iso -s /sbin/nologin iso $ ftp https://cdn.openbsd.org/pub/OpenBSD/7.5/amd64/install75.iso $ ftp https://cdn.openbsd.org/pub/OpenBSD/7.5/amd64/SHA256.sig $ signify -C -p /etc/signify/openbsd-75-base.pub -x SHA256.sig install75.iso Signature Verified install75.iso: OK $ doas mv install75.iso /home/iso/ $ doas mv SHA256.sig /home/iso/ $ doas chown -R iso:iso /home/iso/
If the signature does not verify, delete the ISO and don't proceed.
We will want to enable and start vmd:
$ doas rcctl enable vmd $ doas rcctl start vmd
We need to create a new group vmdusers for each of our users so they can access the serial console:
# groupadd vmdusers # chown root:vmdusers /var/run/vmd.sock
For each virtual machine, we create a user and a disk image using install.pl:
$ ./install.pl $USERNAME
Configuring Packet Filter
Inside pf.conf(5), we add a rule to block all traffic from the vms group (all virtual machines), while allowing ICMP:
block drop on vms all pass on vms proto {icmp icmp6}
After this line, whitelist traffic from each individual machine's IP addresses:
pass on tap1 from {192.168.0.2 2001:db8:1234:5678::/64} to any pass on tap1 from any to {192.168.0.2 2001:db8:1234:5678::/64}
Replace 192.168.0.2
with the actual IPv4 address, and
2001:db8:1234:5678::/64
with the actual IPv6 subnet. You will need two
lines for each virtual machine
Reload the ruleset with pfctl?:
# pfctl -f /etc/pf.conf