Virsh – MacOS Mojave

1. Preparation

Install the necessary packages:

apt install iptables-persistent apparmor-utils ovmf

Open the QEMU configuration file:

vim /etc/libvirt/qemu.conf

And add/edit the following line:

security_driver = "apparmor"

Restart libvirt service

systemctl restart libvirt-bin
systemctl restart libvirtd

Next you need to create an XML file with the description of our virtual machine.

vim macos-mojave.xml

With the following content:

<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
  <name>macos-mojave</name>
  <uuid>2aca0dd6-cec9-4717-9ab2-0b7b13d111c3</uuid>
  <title>MacOS-Mojave</title>
  <memory unit='KiB'>8192000</memory>
  <currentMemory unit='KiB'>8192000</currentMemory>
  <vcpu placement='static'>4</vcpu>
  <os>
    <type arch='x86_64' machine='pc-q35-2.11'>hvm</type>
    <loader readonly='yes' type='pflash'>/var/lib/kvm/vm_images/macos-mojave/OVMF_CODE.fd</loader>
    <nvram>/var/lib/kvm/vm_images/macos-mojave/OVMF_VARS-1024x768.fd</nvram>
  </os>
  <features>
    <acpi/>
    <kvm>
      <hidden state='on'/>
    </kvm>
  </features>
  <clock offset='utc'/>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>restart</on_crash>
  <devices>
    <emulator>/usr/bin/qemu-system-x86_64</emulator>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='writeback'/>
      <source file='/var/lib/kvm/vm_images/macos-mojave/mac_hdd.img'/>
      <target dev='sda' bus='sata'/>
      <boot order='1'/>
      

<address type='drive' controller='0' bus='0' target='0' unit='0'/>
    </disk>
    <controller type='sata' index='0'>
      

<address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/>
    </controller>
    <controller type='pci' index='0' model='pcie-root'/>
    <controller type='pci' index='1' model='dmi-to-pci-bridge'>
      <model name='i82801b11-bridge'/>
      

<address type='pci' domain='0x0000' bus='0x00' slot='0x1e' function='0x0'/>
    </controller>
    <controller type='pci' index='2' model='pci-bridge'>
      <model name='pci-bridge'/>
      <target chassisNr='2'/>
      

<address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
    </controller>
    <controller type='usb' index='0' model='ich9-ehci1'>
      

<address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x7'/>
    </controller>
    <controller type='usb' index='0' model='ich9-uhci1'>
      <master startport='0'/>
      

<address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x0' multifunction='on'/>
    </controller>
    <controller type='usb' index='0' model='ich9-uhci2'>
      <master startport='2'/>
      

<address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x1'/>
    </controller>
    <controller type='usb' index='0' model='ich9-uhci3'>
      <master startport='4'/>
      

<address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x2'/>
    </controller>
    <interface type='bridge'>
      <mac address='52:54:00:AB:DF:0A'/>
      <source bridge='virbr0'/>
      <target dev='tap1'/>
      <model type='e1000-82545em'/>
      

<address type='pci' domain='0x0000' bus='0x02' slot='0x02' function='0x0'/>
    </interface>
    <input type='keyboard' bus='usb'>
      

<address type='usb' bus='0' port='2'/>
    </input>
    <input type='mouse' bus='ps2'/>
    <input type='tablet' bus='usb'>
      

<address type='usb' bus='0' port='3'/>
    </input>
    <input type='keyboard' bus='ps2'/>
    <graphics type='vnc' port='5901' autoport='no' listen='0.0.0.0' keymap='en-us'>
      <listen type='address' address='0.0.0.0'/>
    </graphics>
    <sound model='ich9'>
      

<address type='pci' domain='0x0000' bus='0x02' slot='0x01' function='0x0'/>
    </sound>
    <video>
      <model type='vga'/>
    </video>
    <redirdev bus='usb' type='spicevmc'>
      

<address type='usb' bus='0' port='5'/>
    </redirdev>
    <hub type='usb'>
      

<address type='usb' bus='0' port='1'/>
    </hub>
    <memballoon model='none'/>
  </devices>
  <qemu:commandline>
    <qemu:arg value='-device'/>
    <qemu:arg value='isa-applesmc,osk=ourhardworkbythesewordsguardedpleasedontsteal(c)AppleComputerInc'/>
    <qemu:arg value='-smbios'/>
    <qemu:arg value='type=2'/>
    <qemu:arg value='-cpu'/>
    <qemu:arg value='Penryn,kvm=on,vendor=GenuineIntel,+invtsc,vmware-cpuid-freq=on,+pcid,+ssse3,+sse4.2,+popcnt,+avx,+aes,+xsave,+xsaveopt,check'/>
  </qemu:commandline>
</domain>

We described a virtual machine named “macos-mojave“, which has 4 cores and 8 GB RAM, a network card in NAT mode (tap1 interface), as well as VNC access on port 5901.

Check the paths to the storage of the disk image and OVMF files.

MAC address and UUID must be unique.

UUID generation:

uuidgen

MAC address generation:

printf '52:54:00:AB:%02X:%02X\n' $((RANDOM%256)) $((RANDOM%256))

 

2. Virsh

Connect to libvirtd:

virsh --connect qemu:///system

We check our XML file for validity:

virt-xml-validate macos-mojave.xml

Create a virtual machine based on the XML file:

virsh define macos-mojave.xml

We start the virtual machine:

virsh start macos-mojave

Add a virtual machine to autorun.

We look at the list of VM

virsh list --all
root@KVM:~# virsh list --all
 Id    Name                           State
----------------------------------------------------
 -     macos-mojave                   shut off

We look information on the macos virtual machine:

virsh dominfo macos-mojave
root@KVM:~# virsh dominfo macos-mojave
Id:             -
Name:           macos-mojave
UUID:           2aca0dd6-cec9-4717-9ab2-0b7b13d111c3
OS Type:        hvm
State:          shut off
CPU(s):         4
Max memory:     8192000 KiB
Used memory:    8192000 KiB
Persistent:     yes
Autostart:      disable
Managed save:   no
Security model: none
Security DOI:   0

We are interested in the line: “Autostart: disable

Add to autostart:

virsh autostart macos-mojave
root@KVM:~# virsh autostart macos-mojave
Domain macos-mojave marked as autostarted

Check again:

root@KVM:~# virsh dominfo macos-mojave
Id:             -
Name:           macos-mojave
UUID:           2aca0dd6-cec9-4717-9ab2-0b7b13d111c3
OS Type:        hvm
State:          shut off
CPU(s):         4
Max memory:     8192000 KiB
Used memory:    8192000 KiB
Persistent:     yes
Autostart:      enable
Managed save:   no
Security model: none
Security DOI:   0

 

3. IPTables

When Virsh starts, it wipes its IPTables rules. In order to avoid this, for the beginning you need to save the necessary rules.
The current rules can be viewed with the command:
iptables -S

An example IPTables initial configuration script:

#!/bin/bash
 
iptables -F
iptables -X
 
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP
iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP
iptables -A INPUT -m state --state INVALID -j DROP
iptables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP
iptables -A INPUT -i lo -j ACCEPT
 
########################## ALLOWED PORTS ###########################

iptables -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT

#################### FOR SSH CONNECTIONS TO VM's ###################

iptables -A INPUT -p tcp -m tcp --dport 2222 -j ACCEPT
 
####################### ALLOWED IP ADDRESSES #######################

# FOR VNC ACCESS WITHOUT PASSWORD
iptables -A INPUT -s 1.1.1.1 -j ACCEPT
iptables -A INPUT -s 2.2.2.2 -j ACCEPT

######################## FOR NAT FROM VM's #########################

iptables -A INPUT -i virbr0 -p udp -m udp --dport 53 -j ACCEPT
iptables -A INPUT -i virbr0 -p tcp -m tcp --dport 53 -j ACCEPT
iptables -A INPUT -i virbr0 -p udp -m udp --dport 67 -j ACCEPT
iptables -A INPUT -i virbr0 -p tcp -m tcp --dport 67 -j ACCEPT

################### FOR FORWARDING PORTS TO VM's ###################

iptables -t nat -A PREROUTING -p tcp -d MY_EXTERNAL_IP --dport 2222 -j DNAT --to-destination 192.168.122.100:22

iptables -A FORWARD -i eno1 -d 192.168.122.100 -p tcp --dport 22 -j ACCEPT

######################## FOR NAT FROM VM's #########################

iptables -A FORWARD -d 192.168.122.0/24 -o virbr0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -s 192.168.122.0/24 -i virbr0 -j ACCEPT
iptables -A FORWARD -i virbr0 -o virbr0 -j ACCEPT
iptables -A FORWARD -o virbr0 -j REJECT --reject-with icmp-port-unreachable
iptables -A FORWARD -i virbr0 -j REJECT --reject-with icmp-port-unreachable

iptables -A OUTPUT -o virbr0 -p udp -m udp --dport 68 -j ACCEPT

iptables -P OUTPUT ACCEPT
iptables -P INPUT DROP
iptables -P FORWARD ACCEPT

Do not forget to substitute your external IP address, and replace the external interface “eno1” with your own.

The script allows access to the ports: 22, 80 and 443. As well as full access to the IP addresses “1.1.1.1” and “2.2.2.2“, it also forwards the port “2222” from the host to the port “22” of the virtual machine (IP address virtual machine – 192.168.122.100)

Save the rules:

iptables-save > /etc/iptables/rules.v4

If this folder does not exist, you need to create it:

mkdir /etc/libvirt/hooks

Create a script:

vim /etc/libvirt/hooks/network

With the following content:

#!/bin/bash

# Libvirt hook, see: https://www.libvirt.org/hooks.html
# for iptables reloading after host booted

if [ "$2" = "started" ]; then

/bin/systemctl restart netfilter-persistent

fi;

exit 0;

Add the execute bit:

chmod +x /etc/libvirt/hooks/network

Now, after starting Virsh, IPTables will be restarted, thereby resetting the rules to the saved ones.

Tagged: Tags

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments