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
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.