Esta pagina se ve mejor con JavaScript habilitado

Gestión de VMs Bhyve en FreeBSD con Iohyve

 ·  🎃 kr0m

Iohyve es un gestor de máquinas virtuales Bhyve que hace uso de funcionalidades ZFS para ofrecer una experiencia de uso mas sencilla e intuitiva, entre sus características destacan la capacidad de realizar snapshots, gestión de ISOs, servidor VNC integrado, clonado y backup de VMs. Se podría decir que es el equivalente a Iocage pero para VMs Bhyve, por otro lado si preferimos una interfaz unificada siempre podremos utilizar CBSD .

Este manual se compone de diferentes partes:


Instalación

Instalamos todo lo necesario:

pkg install iohyve grub2-bhyve bhyve-firmware

Si tenemos mas de un zpool debemos indicarle a Iohyve cual de ellos utilizar:

zpool list

NAME    SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT  
zroot   109G  78.5G  30.5G        -         -    44%    71%  1.00x  ONLINE  -
iohyve setup pool=zroot

La red Iohyve funciona mediante bridging, debemos indicarle la interfaz de red que queremos meter dentro del bridge, de este modo cuando creemos una VM se attacheará la interfaz tap de dicha VM al bridge existente:

iohyve setup net=em0

Permitimos que Iohyve cargue los módulos del kernel que necesite:

iohyve setup kmod=1

Para hacerlo permanente en el arranque del servidor podemos utilizar los parámetros RC siguientes:

sysrc iohyve_enable="yes"
sysrc iohyve_flags=“kmod=1 net=em0”

Reiniciamos para asegurarnos de que todo se carga de forma automática:

reboot


Descarga de imágenes ISO

Para realizar la instalación del SO necesitamos la imagen ISO de instalación, la bajamos mediante el comando fetchiso:

La renombramos para que sea mas fácil de escribir:

iohyve renameiso kali-linux-2020.3-installer-amd64.iso kali2020.3.iso

Listamos las ISOs disponibles:

iohyve isolist

Listing ISO's...  
kali2020.3.iso

Creación de VMs

Creamos la VM con un disco de 15G:

iohyve create kali 15G

NOTA: La reserva de espacio del disco virtual NO es dinámica lo que implica que debemos tener disponible el espacio indicado en el momento de crear la VM.


Instalación por puerto serie:

Asignamos los parámetros de la VM:

iohyve set kali ram=2048M loader=grub-bhyve os=debian

El parámetro os no indica el SO a instalar si no solo algunos ajustes que grub-bhyve tendrá en cuenta para arrancar la VM, por ejemplo debian es cualquier Linux sin LVM.

Las posibles opciones son: openbsd57, openbsd58, openbsd59, openbsd60, openbsd61, netbsd, debian (non-LVM), d8lvm(LVM installs), centos6, centos7(non-XFS), ubuntu (LVM installs,non-LVM use debian), arch y custom.

La opción custom significa que se leerán los ficheros /iohyve/VM_NAME/device.map y /iohyve/VM_NAME/grub.cfg en el arranque.

NOTA: Si vamos a instalar un sistema FreeBSD no es necesario especificar los parámetros loader/os.

Antes de instalar el SO, dejamos una consola preparada a la espera:

iohyve console kali

En un segundo terminal iniciamos la instalación:

iohyve install kali kali2020.3.iso

Veremos que en el primer terminal aparece el asistente de instalación del SO, seleccionamos la segunda opción:

GNU GRUB version 2.00

+--------------------------------------------------------------------------+
|Graphical install                                                         |
|Install                                                                   |
|Advanced options ...                                                      |
|Accessible dark contrast installer menu ...                               |
|Install with speech synthesis                                             |
|                                                                          |
|                                                                          |
|                                                                          |
|                                                                          |
|                                                                          |
|                                                                          |
|                                                                          |
+--------------------------------------------------------------------------+

 Use the ^ and v keys to select which entry is highlighted.
 Press enter to boot the selected OS, `e' to edit the commands
 before booting or `c' for a command-line.

Al terminar la instalación tendremos la VM apagada, la arrancamos y accedemos a la consola:

iohyve console kali
iohyve start kali

kali login: kr0m  
Password:  
  
Linux kali 5.7.0-kali1-amd64 #1 SMP Debian 5.7.6-1kali2 (2020-07-01) x86_64  
The programs included with the Kali GNU/Linux system are free software;  
the exact distribution terms for each program are described in the  
individual files in /usr/share/doc/*/copyright.  
  
Kali GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent  
permitted by applicable law.  
Last login: Sun Nov 8 10:59:10 CET 2020 on ttyS0  
  
kr0m@kali:~$

Para salir de la consola escribimos Alt+4.: ~.


Instalación por VNC

Por defecto Iohyve utiliza la consola serie para acceder al SO, en la mayoría de casos será mas que suficiente ya que si necesitamos arrancar alguna aplicación gráfica mediante ssh-Xforward podemos hacerlo sin tener que arrancar las X.

Otro modo de conseguir acceso a las X es instalando un servidor VNC en la propia VM, de este modo ya no dependeríamos del VNC de Iohyve.

Pero si necesitamos acceso gráfico en la instalación del SO como ocurre con Windows, tendremos que habilitar el acceso por VNC mediante el loader uefi, para que este esté disponible debemos instalar el paquete bhyve-firmware como se ha hecho al principio del manual e importar el fichero de firmware con el comando cpfw.

iohyve cpfw /usr/local/share/uefi-firmware/BHYVE_UEFI.fd
iohyve fwlist

Listing Firmware...  
BHYVE_UEFI.fd

Ahora debemos decidir si queremos sacrificar una dirección ip de la red para el acceso VNC o si bindeamos el servicio a la loopback y accedemos vía túnel Ssh, mediante loopback el acceso será mas seguro ya que solo estará expuesto cuando montemos el túnel y no desperdiciaremos direcciones ips pero tendremos que configurar un puerto VNC distinto por cada VM.


VNC-Loopback

Creamos la VM:

iohyve create kaliVNC 15G

Seteamos los parámetros necesarios:

iohyve set kaliVNC ram=2048M loader=uefi vnc=YES fw=BHYVE_UEFI.fd

Iniciamos la instalación:

iohyve install kaliVNC kali2020.3.iso

Vemos que hay un servicio en la loopback en el puerto 5900:

sockstat -sv|grep LISTEN|grep bhyve

root bhyve 9029 7 tcp4 127.0.0.1:5900 *:* LISTEN

Montamos el túnel Ssh para acceder desde fuera al VNC:

ssh -L 5900:127.0.0.1:5900 -A -g kr0m@HOST_PADRE

Arrancamos nuestro cliente VNC atacando nuestro pc el cual nos llevará vía túnel al VNC de la VM:

vinagre 127.0.0.1:5900

Si creamos una segunda VM tendremos que elegir un puerto VNC distinto:

iohyve create kaliVNC2 15G
iohyve set kaliVNC2 ram=2048M loader=uefi vnc=YES vnc_port=5901 fw=BHYVE_UEFI.fd
iohyve install kaliVNC2 kali2020.3.iso

Vemos que hay dos servicios bindeados a la loopback pero en distintos puertos:

sockstat -sv|grep LISTEN|grep bhyve

root bhyve 4166 7 tcp4 127.0.0.1:5901 *:* LISTEN  
root bhyve 9029 7 tcp4 127.0.0.1:5900 *:* LISTEN

Montamos el túnel Ssh para dar acceso al VNC de la VM:

ssh -L 5901:127.0.0.1:5901 -A -g kr0m@HOST_PADRE

Accedemos al instalador vía VNC:

vinagre 127.0.0.1:5901



VNC-Ip

Si optamos por asignar una dirección ip la VM tendrá una dirección ip para el acceso VNC y la de la VM propiamente dicha.
Tendremos que configurar la ip-vnc como alias en el padre e indicarla en la configuración de la VM.

Vamos a dejarlo configurado en el rc.conf y manualmente, de este modo en caso de reinicio no se perderá configuración alguna:

sysrc ifconfig_nfe0_alias0=“inet IP_VM netmask NETMASK”
ifconfig INTERFAZ IP_VM netmask NETMASK alias

Creamos la VM:

iohyve create kaliVNC3 15G

Seteamos los parámetros necesarios:

iohyve set kaliVNC3 ram=2048M loader=uefi vnc=YES vnc_ip=192.168.69.254 fw=BHYVE_UEFI.fd

Iniciamos la instalación:

iohyve install kaliVNC3 kali2020.3.iso

Podemos ver como hay un VNC bindeado a la dirección ip indicada:

sockstat -sv|grep LISTEN|grep bhyve

root bhyve 14438 7 tcp4 192.168.69.254:5900 *:* LISTEN  
root bhyve 4166 7 tcp4 127.0.0.1:5901 *:* LISTEN  
root bhyve 9029 7 tcp4 127.0.0.1:5900 *:* LISTEN

Conectamos directamente al VNC de la VM sin necesidad de ningún túnel:

vinagre 192.168.69.254:5900

Realmente para un administrador de sistemas Unix el acceso VNC no tiene sentido ya que normalmente se accede las VMs vía Ssh, si necesitásemos alguna aplicación gráfica sería suficiente arrancándola mediante ssh-Xforward y si se necesitásemos un acceso de urgencia accederíamos vía puerto serie con el comando console de Iohyve.


Bug Xorg

Si se han instalado las X estas están bugeadas( 1 , 2 ), el bug en cuestión presenta la siguiente salida al intentar arrancar las X:

Para solventarlo hay que entrar por Ssh y desinstalar el paquete xserver-xorg-video-vesa, el problema es que al arrancar el entorno gráfico se queda colgado por el bug y cuando presionamos Ctrl+Alt+F1 estamos enviando las pulsaciones a nuestro FreeBSD, para poder hacerlo dentro del cliente VNC previamente tendremos que deshabilitar las teclas en nuestro SO.

setxkbmap -option srvrkeys:none

Ahora ya podemos hacer login desde la tty no gráfica y arrancar el servicio Ssh para desinstalar el paquete conflictivo:

service ssh start

Accedemos por Ssh a la VM:

Desinstalamos el paquete y apagamos la VM:

apt remove xserver-xorg-video-vesa
halt

Rehabilitamos Ctrl+Alt+FX en nuestro SO:

setxkbmap -option

Arrancamos la VM:

iohyve start kaliVNC

Como podemos ver kali ya arranca las X con normalidad, si hacemos login veremos que el entorno gráfico funciona sin problemas:



Aplicaciones gráficas sin X por Ssh

Una manera de ejecutar aplicaciones gráficas pero sin necesidad de arrancar las X es mediante el ssh-xforward, para ello configuramos el acceso ssh y averiguamos la dirección ip de la VM:

iohyve console kali

Starting console on kali...  
~~. to escape console [uses cu(1) for console]  
Connected  
  
kali login: kr0m  
Password:  
  
Linux kali 5.7.0-kali1-amd64 #1 SMP Debian 5.7.6-1kali2 (2020-07-01) x86_64  
The programs included with the Kali GNU/Linux system are free software;  
the exact distribution terms for each program are described in the  
individual files in /usr/share/doc/*/copyright.  
  
Kali GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent  
permitted by applicable law.  
Last login: Sun Nov 8 11:50:53 CET 2020 on ttyS0
Habilitamos el servico Ssh:
kr0m@kali:~$ sudo su
root@kali:/home/kr0m# systemctl enable ssh.service
root@kali:/home/kr0m# systemctl start ssh.service

Consultamos la dirección ip de la VM:

root@kali:/home/kr0m# ifconfig

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500  
 inet 192.168.69.205 netmask 255.255.255.0 broadcast 192.168.69.255

Permitimos mostrar aplicaciones gráficas que provengan de la ip indicada en nuestro pc mediante xhost:

xhost +inet:192.168.69.205

Ejecutamos burpsuite a modo de prueba:

ssh -vYC kr0m@192.168.69.205 burpsuite



Listar VMs

iohyve list
Guest     VMM?  Running  rcboot?  Description  
kali      NO    NO       NO       Sun Nov  8 20:28:35 CET 2020  
kaliVNC3  NO    NO       NO       Mon Nov  9 12:19:21 CET 2020

Información VMs

Podemos consultar información de las VMs del siguiente modo:

iohyve info -sv
Guest           Size  CPU  RAM    Pool   OS       Loader      Tap   Con    VMM?  Running  rcboot?  
kali            -     1    2048M  zroot  debian   grub-bhyve  tap0  nmdm0  NO    NO       NO  
kali/disk0      15G   -    -      zroot  -        -           -     -      -     -        -  
kaliVNC3        -     1    2048M  zroot  default  uefi        tap1  nmdm1  NO    NO       NO  
kaliVNC3/disk0  15G   -    -      zroot  -        -           -     -      -     -        -
iohyve getall kali
Getting kali iohyve properties...  
bargs            -A_-H_-P  
bhyve_path       /usr/sbin/bhyve  
boot             0  
con              nmdm0  
cpu              1  
description      Sun Nov  8 20:28:35 CET 2020  
install          no  
loader           grub-bhyve  
name             kali  
os               debian  
persist          1  
ram              2048M  
size             15G  
tap              tap0  
template         NO  
utc              YES  
vnc              NO  
vnc_h            600  
vnc_ip           127.0.0.1  
vnc_tablet       NO  
vnc_w            800  
vnc_wait         NO  

Parámetros

Podemos asignar valores a los parámetros de la VM, algunos ejemplos pueden ser estos:

iohyve set kali ram=512M
iohyve set kali cpu=1
iohyve set kali description=“This is my Kali box”

Incluso podemos hacer passthrugh de dispositivos:

iohyve set kali pcidev:1=passthru,2/0/0

Para obtener valores de los parámetros:

iohyve get kali ram
iohyve getall kali


Snapshots

Creamos un snapshot:

iohyve snap kali@beforeupdate

Taking snapshot kali@beforeupdate

Listamos los snapshots disponibles:

iohyve snaplist

kali@beforeupdate

Revertimos a un snapshot:

iohyve stop kali
iohyve roll kali@beforeupdate

Rolling back to kali@beforeupdate

Eliminar snapshots:

iohyve rmsnap kali@beforeupdate


Clonar VMs

Mediante el clonado estamos realizando una copia de la VM no un clon a nivel ZFS, esto puede suponer un consumo del espacio considerable ya que además del espacio que ocuparán las dos VMS Iohyve necesita espacio adicional mientras realiza el clonado.

iohyve clone kali dolly
iohyve list

Guest  VMM?  Running  rcboot?  Description  
dolly  NO    NO       NO       Tue_Nov__8_21:04:05_CET_2020  
kali   NO    NO       NO       Sun Nov  8 20:28:35 CET 2020

Templates

Si no queremos que nadie arranque una VM por accidente o haga alguna modificación en esta VM arrancándola, reinstalándola, renombrándola o borrándola tendremos que setearle el parámetro template a YES.

Pongamos el siguiente ejemplo en el que kali está parada:

iohyve list

Guest  VMM?  Running  rcboot?  Description  
kali   NO    NO       NO       Sun Nov  8 20:28:35 CET 2020

Le asignamos el parámetro template=YES:

iohyve set kali template=YES

Intentamos arrancar la VM

iohyve start kali

kali is a template. Cannot start

Intentamos eliminarla:

iohyve delete kali

kali is a template. Cannot delete

Forzar parada

En algunos casos extremos el comando stop no logrará parar la VM, podemos forzar la parada pero este comando debe utilizarse como último recurso:

iohyve forcekill kali


Backup mediante exportaciones

Mediante el comando export podremos generar un tarball con todos los datos de la VM, incluída su configuración Iohyve, este tarball será almacenado en el path: /iohyve/VM_NAME/VM_NAME.tar.gz el único inconveniente es que requiere que apaguemos la VM. Pero siempre podemos clonar la VM, hacer el export del clon, copiar el backup y eliminar el clon.

iohyve clone kali backup
iohyve list

Guest  VMM?  Running  rcboot?  Description  
backup NO    NO       NO       Tue_Nov__8_21:14:05_CET_2020  
kali   NO    NO       NO       Sun Nov  8 20:28:35 CET 2020
iohyve export backup
Exporting backup. Note this may take some time depending on the size.  
Creating temp directory...  
Exporting properties...  
Exporting disks...  
15360+0 records in  
15360+0 records out  
16106127360 bytes transferred in 170.564576 secs (94428326 bytes/sec)  
Compressing to archive...  
Removing temp directory...

Comprobamos el tamaño de la exportación:

du -h /iohyve/backup/backup.tar.gz

3.2G /iohyve/backup/backup.tar.gz

Movemos el tarball a algún lugar seguro, sería aconsejable moverlo a un servidor remoto en otra localización física, como prueba de concepto lo moveré a /root:

mv /iohyve/backup/backup.tar.gz /root/

Eliminamos la VM clonada:

iohyve delete backup

[WARNING] Are you sure you want to permanently delete backup and all child datasets?  
Location: zroot/iohyve/backup [Y/N]? Y  
Deleting backup at zroot/iohyve/backup...

Eliminamos la VM original:

iohyve stop kali
iohyve delete kali

[WARNING] Are you sure you want to permanently delete kali and all child datasets?  
Location: zroot/iohyve/kali [Y/N]? Y  
Deleting kali at zroot/iohyve/kali...

Para restaurarlo tan solo debemos descomprimirlo, crear una VM con los parámetros del fichero de configuración y volcar el contenido de la imagen de disco:

cd /root/
tar xvzf backup.tar.gz

x ./  
x ./disk0.img  
x ./properties.ucl
cat ./properties.ucl  
bargs=-A_-H_-P  
bhyve_path=/usr/sbin/bhyve  
boot=0  
con=nmdm0  
cpu=1  
description=Sun_Nov__8_20:08:03_CET_2020  
install=no  
loader=grub-bhyve  
name=backup  
os=debian  
persist=1  
ram=2048M  
size=15G  
tap=tap0  
template=NO  
utc=YES  
vnc=NO  
vnc_h=600  
vnc_ip=127.0.0.1  
vnc_tablet=NO  
vnc_w=800  
vnc_wait=NO

Creamos la VM con el tamaño de disco indicado en el fichero ucl:

iohyve create kali 15G

Asignamos los parámetros de la VM tal como aparecen en el fichero ucl:

iohyve set kali ram=2048M loader=grub-bhyve os=debian

Comprobamos que se haya creado correctamente:

iohyve list

Guest  VMM?  Running  rcboot?  Description  
kali   NO    NO       NO       Sun Nov  8 20:28:35 CET 2020

Volcamos el contenido de la imagen de disco:

dd if=/root/disk0.img of=/dev/zvol/zroot/iohyve/kali/disk0

31457280+0 records in  
31457280+0 records out  
16106127360 bytes transferred in 397.031970 secs (40566324 bytes/sec)

Arrancamos la VM y accedemos a ella:

iohyve start kali
iohyve console kali


Diferencia entre VMM y Running

Cuando arrancamos una VM esta pasa por el bootloader donde todavía no se ha cargado el kernel, esta fase es VMM, si se empieza a cargar el kernel ya aparece como Running.

Si paramos una VM pero VMM no se para pueden quedar recursos ocupados por esta VM, en tal caso debemos ejecutar el comando destroy:

iohyve destroy kali


Troubleshooting

Alguna vez la consola muestra carácteres incorrectos, reseteándola se solventa el problema:

iohyve conreset kali
iohyve console kali

Si estamos probando Iohyve en un equipo de escritorio es muy probable que tengamos el proceso gvfs arrancado, esto puede causar problemas cuando eliminemos VMs ya que el proceso de Trash de gvfs puede estar accediendo al filesystem, en tal caso el error mostrado al intentar eliminar la VM es el siguiente:

iohyve delete kaliVNC

[WARNING] Are you sure you want to permanently delete kaliVNC and all child datasets?  
Location: zroot/iohyve/kaliVNC [Y/N]? Y  
Deleting kaliVNC at zroot/iohyve/kaliVNC...  
cannot unmount '/iohyve/kaliVNC': Device busy

Localizamos el proceso que mantiene ocupado el dispositivo:

lsof +f -- /iohyve/kaliVNC

COMMAND   PID USER   FD   TYPE                DEVICE SIZE/OFF NODE NAME  
gvfsd-tra 68671 kr0m   29r  VDIR 2635944363,1737022982      512   34 /iohyve/kaliVNC

Matamos el proceso:

kill -9 68671

Ahora ya podemos eliminar la VM sin problemas:

iohyve delete kaliVNC

Si el error que nos muestra es el siguiente:

iohyve delete kali

[WARNING] Are you sure you want to permanently delete kali and all child datasets?  
Location: zroot/iohyve/kali [Y/N]? Y  
Deleting kali at zroot/iohyve/kali...  
cannot destroy 'zroot/iohyve/kali/disk0': dataset is busy

Tendremos que reiniciar el servicio, el inconveniente de esto es que parará todas las VMs:

service iohyve stop
iohyve delete kaliVNC
service iohyve start

Si tenemos algún problema de red podemos identificar rápidamente las interfaces tap de las VMs con el siguiente comando:

iohyve taplist

Listing all network taps:  
zroot/iohyve/kali......tap0

Podemos comprobar manualmente como en el bridge están las dos interfaces de red, la del host padre y la tap de la VM:

ifconfig

em0: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> metric 0 mtu 1500  
 options=812099<RXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,WOL_MAGIC,VLAN_HWFILTER>  
 ether 34:97:f6:36:bf:45  
 inet 192.168.69.4 netmask 0xffffff00 broadcast 192.168.69.255  
 media: Ethernet autoselect (1000baseT <full-duplex>)  
 status: active  
 nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>  
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384  
 options=680003<RXCSUM,TXCSUM,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6>  
 inet6 ::1 prefixlen 128  
 inet6 fe80::1%lo0 prefixlen 64 scopeid 0x2  
 inet 127.0.0.1 netmask 0xff000000  
 groups: lo  
 nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>  
bridge0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500  
 description: iohyve-bridge-em0  
 ether 02:89:af:f3:c6:00  
 id 00:00:00:00:00:00 priority 32768 hellotime 2 fwddelay 15  
 maxage 20 holdcnt 6 proto stp-rstp maxaddr 2000 timeout 1200  
 root id 00:00:00:00:00:00 priority 32768 ifcost 0 port 0  
 member: tap0 flags=143<LEARNING,DISCOVER,AUTOEDGE,AUTOPTP>  
        ifmaxaddr 0 port 5 priority 128 path cost 2000000  
 member: em0 flags=143<LEARNING,DISCOVER,AUTOEDGE,AUTOPTP>  
         ifmaxaddr 0 port 1 priority 128 path cost 20000  
 groups: bridge  
 nd6 options=9<PERFORMNUD,IFDISABLED>  
tap0: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> metric 0 mtu 1500  
 description: iohyve-kali--  
 options=80000<LINKSTATE>  
 ether 58:9c:fc:10:ff:fd  
 groups: tap  
 media: Ethernet autoselect  
 status: active  
 nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>  
 Opened by PID 30627

Debo advertiros de que la gestión de discos parece funcionar bien en la mayoría de los casos probados pero eliminar el disco0 de una VM es problemático, parece que hay algún que otro bug, además luego resulta imposible arrancar la VM con el disco1.

Si te ha gustado el artículo puedes invitarme a un RedBull aquí