CIS KVM / libvirt Benchmark
Security configuration recommendations for KVM/libvirt virtualization hypervisor
v1.0.0 01-2025Overview
▶This benchmark provides prescriptive guidance for establishing a secure configuration posture for KVM with libvirt management. It covers QEMU process isolation, mandatory access controls (SELinux/AppArmor), network segmentation, storage encryption, migration security, resource limits, and audit logging using virsh, qemu.conf, and libvirtd.conf.
| Section | Area | Focus |
|---|---|---|
| 1 | Host Access Control | QEMU process isolation and libvirt socket authorization |
| 2 | Mandatory Access Controls | SELinux sVirt and AppArmor profile enforcement |
| 3 | Network Security | Virtual network isolation and VM interface filtering |
| 4 | Storage Security | Volume encryption and disk image file permissions |
| 5 | Remote Access & Migration | TLS for live migration and console connections |
| 6 | Resource Management | CPU/memory limits and memory overcommit controls |
| 7 | Audit & Backup | Audit logging and VM backup/snapshot procedures |
Profile Definitions
▶| Profile | Description | Intended Use |
|---|---|---|
| L1 | Level 1 — Standard | Essential security for all KVM/libvirt deployments; minimal performance impact. |
| L2 | Level 2 — Hardened | Advanced hardening for PCI-DSS, HIPAA, or high-security environments. |
1 — Host Access Control
▶1.1 Process & Socket Security
▶This recommendation verifies that QEMU runs as a non-root user on the KVM/libvirt virtualization hypervisor. Implementing this control strengthens the overall security configuration and reduces exposure to potential threats.
Failure to implement this control may leave the KVM/libvirt virtualization hypervisor vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
# Check QEMU user/group:
grep -E '^(user|group)' /etc/libvirt/qemu.conf
# Check running QEMU process:
ps aux | grep qemu-system | grep -v grep | awk '{print $1}'# Run QEMU as non-root: # /etc/libvirt/qemu.conf: user = "libvirt-qemu" group = "kvm" sudo systemctl restart libvirtd
This recommendation verifies that libvirt socket access uses polkit authorization on the KVM/libvirt virtualization hypervisor. Implementing this control strengthens the overall security configuration and reduces exposure to potential threats.
Failure to implement this control may leave the KVM/libvirt virtualization hypervisor vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
# Check libvirtd socket permissions: ls -la /var/run/libvirt/libvirt-sock* # Check polkit rules: ls /etc/polkit-1/rules.d/*libvirt* 2>/dev/null ls /etc/polkit-1/localauthority/50-local.d/*libvirt* 2>/dev/null
# Configure polkit for libvirt access:
# /etc/polkit-1/rules.d/50-libvirt.rules:
polkit.addRule(function(action, subject) {
if (action.id == "org.libvirt.unix.manage" &&
subject.isInGroup("libvirt")) {
return polkit.Result.YES;
}
});
# Add authorized users to libvirt group:
sudo usermod -aG libvirt admin-user2 — Mandatory Access Controls
▶2.1 SELinux / AppArmor
▶This recommendation verifies that SELinux with sVirt is enforcing on the KVM/libvirt virtualization hypervisor. Implementing this control strengthens the overall security configuration and reduces exposure to potential threats.
Failure to implement this control may leave the KVM/libvirt virtualization hypervisor vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
# Check SELinux/sVirt status:
getenforce
sestatus | grep -E 'mode|policy'
# Check VM SELinux labels:
ps -eZ | grep qemu | awk '{print $1}'# Enable SELinux with sVirt: sudo setenforce 1 sudo sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config # Verify sVirt labeling in qemu.conf: # /etc/libvirt/qemu.conf: security_driver = "selinux" security_default_confined = 1 security_require_confined = 1
This recommendation ensures that AppArmor profiles are enforced for libvirt on the KVM/libvirt virtualization hypervisor. Enforcing this requirement establishes a minimum security standard and prevents insecure configurations.
Without this enforcement, the KVM/libvirt virtualization hypervisor may accept insecure configurations that weaken overall security posture. Mandating this control ensures consistent protection against common attack vectors.
# Check AppArmor profiles (Debian/Ubuntu): aa-status 2>/dev/null | grep libvirt # Check per-VM profiles: ls /etc/apparmor.d/libvirt/TEMPLATE* 2>/dev/null
# Enable AppArmor for libvirt: # /etc/libvirt/qemu.conf: security_driver = "apparmor" security_default_confined = 1 # Ensure profiles are loaded: sudo aa-enforce /etc/apparmor.d/usr.sbin.libvirtd sudo aa-enforce /etc/apparmor.d/usr.lib.libvirt.virt-aa-helper sudo systemctl restart libvirtd
3 — Network Security
▶3.1 Virtual Network Isolation
▶This recommendation verifies that virtual networks are properly isolated on the KVM/libvirt virtualization hypervisor. Implementing this control strengthens the overall security configuration and reduces exposure to potential threats.
Failure to implement this control may leave the KVM/libvirt virtualization hypervisor vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
# Check network isolation - list virtual networks: virsh net-list --all virsh net-dumpxml default | grep -E 'forward|bridge|ip'
# Create isolated network for VMs:
cat > /tmp/isolated-net.xml <<EOF
<network>
<name>isolated</name>
<bridge name='virbr1'/>
<ip address='10.10.10.1' netmask='255.255.255.0'>
<dhcp>
<range start='10.10.10.100' end='10.10.10.200'/>
</dhcp>
</ip>
</network>
EOF
virsh net-define /tmp/isolated-net.xml
virsh net-start isolated
virsh net-autostart isolated
# Disable default NAT network if not needed:
virsh net-destroy default
virsh net-undefine defaultThis recommendation verifies that network filters are applied to VM interfaces on the KVM/libvirt virtualization hypervisor. Implementing this control strengthens the overall security configuration and reduces exposure to potential threats.
Failure to implement this control may leave the KVM/libvirt virtualization hypervisor vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
# Check nwfilter rules: virsh nwfilter-list virsh nwfilter-dumpxml clean-traffic
# Apply network filtering to VM interfaces: virsh nwfilter-define /etc/libvirt/nwfilter/clean-traffic.xml # Attach filter to VM interface: # In VM XML: # <interface type='network'> # <source network='default'/> # <filterref filter='clean-traffic'> # <parameter name='IP' value='10.10.10.101'/> # </filterref> # </interface> virsh edit vm-name # Add filterref to interface
4 — Storage Security
▶4.1 Disk & Image Security
▶This recommendation verifies that storage volumes use encryption on the KVM/libvirt virtualization hypervisor. Implementing this control strengthens the overall security configuration and reduces exposure to potential threats.
Failure to implement this control may leave the KVM/libvirt virtualization hypervisor vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
# Check storage pool encryption: virsh pool-list --all --details virsh vol-list --pool default --details # Check LUKS volumes: lsblk -f | grep LUKS
# Create LUKS-encrypted storage pool: virsh secret-define --file /tmp/luks-secret.xml virsh secret-set-value --secret UUID --base64 $(echo -n 'passphrase' | base64) # Create encrypted volume: virsh vol-create-as default encrypted-vol 20G \ --format qcow2 --encryption luks # Or use LUKS partition for pool: cryptsetup luksFormat /dev/sdb1 cryptsetup luksOpen /dev/sdb1 vm-storage mkfs.xfs /dev/mapper/vm-storage
This recommendation verifies that disk image file permissions are restrictive on the KVM/libvirt virtualization hypervisor. Implementing this control strengthens the overall security configuration and reduces exposure to potential threats.
Failure to implement this control may leave the KVM/libvirt virtualization hypervisor vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
# Check disk image permissions: ls -la /var/lib/libvirt/images/ # Check for world-readable images: find /var/lib/libvirt/images -perm -o+r -type f
# Secure disk image permissions: sudo chmod 0600 /var/lib/libvirt/images/*.qcow2 sudo chown libvirt-qemu:kvm /var/lib/libvirt/images/*.qcow2 # Set umask in qemu.conf: # /etc/libvirt/qemu.conf: dynamic_ownership = 1
5 — Remote Access & Migration
▶5.1 TLS Configuration
▶This recommendation verifies that TLS is configured for live migration on the KVM/libvirt virtualization hypervisor. Implementing this control strengthens the overall security configuration and reduces exposure to potential threats.
Failure to implement this control may leave the KVM/libvirt virtualization hypervisor vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
# Check live migration TLS: grep -E 'migrate_tls|default_tls' /etc/libvirt/qemu.conf # Check TLS certificates: ls -la /etc/pki/libvirt/private/ /etc/pki/libvirt/ /etc/pki/CA/ 2>/dev/null
# Configure TLS for live migration: # Generate certificates: mkdir -p /etc/pki/CA /etc/pki/libvirt/private certtool --generate-privkey > /etc/pki/CA/cakey.pem certtool --generate-self-signed --load-privkey /etc/pki/CA/cakey.pem \ --template ca.info --outfile /etc/pki/CA/cacert.pem # /etc/libvirt/qemu.conf: migrate_tls_x509_verify = 1 default_tls_x509_cert_dir = "/etc/pki/libvirt" default_tls_x509_verify = 1 # /etc/libvirt/libvirtd.conf: listen_tls = 1 listen_tcp = 0 tls_allowed_dn_list = ["C=US,O=Example,CN=*"]
This recommendation verifies that VNC/Spice consoles use TLS on the KVM/libvirt virtualization hypervisor. Implementing this control strengthens the overall security configuration and reduces exposure to potential threats.
Failure to implement this control may leave the KVM/libvirt virtualization hypervisor vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
# Check VNC/Spice TLS: grep -E 'vnc_tls|spice_tls|vnc_listen' /etc/libvirt/qemu.conf
# Configure VNC with TLS: # /etc/libvirt/qemu.conf: vnc_listen = "127.0.0.1" vnc_tls = 1 vnc_tls_x509_cert_dir = "/etc/pki/libvirt-vnc" vnc_tls_x509_verify = 1 # For Spice: spice_listen = "127.0.0.1" spice_tls = 1 spice_tls_x509_cert_dir = "/etc/pki/libvirt-spice" sudo systemctl restart libvirtd
6 — Resource Management
▶6.1 Limits & Isolation
▶This recommendation verifies that CPU and memory limits are configured per VM on the KVM/libvirt virtualization hypervisor. Implementing this control strengthens the overall security configuration and reduces exposure to potential threats.
Failure to implement this control may leave the KVM/libvirt virtualization hypervisor vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
# Check resource limits in VM definitions: virsh dumpxml vm-name | grep -A5 'memtune\|cputune\|blkiotune' # Check cgroup enforcement: cat /sys/fs/cgroup/machine.slice/machine-qemu*/cpu.max 2>/dev/null
# Set CPU and memory limits: virsh setvcpus vm-name 4 --maximum --config virsh setvcpus vm-name 2 --config virsh setmaxmem vm-name 4G --config virsh setmem vm-name 2G --config # Set CPU pinning and shares: virsh vcpupin vm-name 0 2-3 virsh schedinfo vm-name --set cpu_shares=1024 # Set block I/O limits: virsh blkiotune vm-name --weight 500 virsh blkdeviotune vm-name vda --total-bytes-sec 104857600
This setting ensures that memory overcommit is controlled on the KVM/libvirt virtualization hypervisor. Restricting this capability limits potential abuse and enforces the principle of least privilege across the environment.
Unrestricted access to this capability could allow unauthorized users or processes to perform actions beyond their intended scope. Applying least-privilege principles to the KVM/libvirt virtualization hypervisor is essential for defense in depth.
# Check for memory overcommit:
virsh list --all | tail -n+3 | awk '{print $2}' | while read vm; do
echo "$vm: $(virsh dumpxml $vm 2>/dev/null | grep -oP '<memory[^>]*>\K[0-9]+')"
done
free -m | grep Mem# Configure KSM and memory ballooning safely: # Disable KSM if not needed (prevents side-channel attacks): echo 0 | sudo tee /sys/kernel/mm/ksm/run # Or configure KSM conservatively: echo 1 | sudo tee /sys/kernel/mm/ksm/run echo 1000 | sudo tee /sys/kernel/mm/ksm/sleep_millisecs # Enable memory ballooning per VM: # In VM XML add: # <memballoon model='virtio'> # <stats period='10'/> # </memballoon>
7 — Audit & Backup
▶7.1 Logging & Recovery
▶This recommendation verifies that libvirt audit logging is enabled on the KVM/libvirt virtualization hypervisor. Implementing this control strengthens the overall security configuration and reduces exposure to potential threats.
Failure to implement this control may leave the KVM/libvirt virtualization hypervisor vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
# Check libvirt audit logging: grep -E 'log_level|log_filters|audit_level' /etc/libvirt/libvirtd.conf # Check recent audit entries: ausearch -m VIRT_CONTROL -ts recent 2>/dev/null | tail -20
# Enable libvirt audit logging: # /etc/libvirt/libvirtd.conf: log_level = 3 log_filters = "1:libvirt 1:qemu 1:security" log_outputs = "1:syslog:libvirtd" audit_level = 2 audit_logging = 1 # Configure auditd rules: sudo auditctl -w /etc/libvirt/ -p wa -k libvirt-config sudo auditctl -w /var/lib/libvirt/images/ -p wa -k vm-images sudo systemctl restart libvirtd
This recommendation verifies that VM backup procedures are in place on the KVM/libvirt virtualization hypervisor. Implementing this control strengthens the overall security configuration and reduces exposure to potential threats.
Failure to implement this control may leave the KVM/libvirt virtualization hypervisor vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
# Check VM snapshots and backups: virsh snapshot-list vm-name 2>/dev/null # Check for backup scripts: crontab -l | grep -i 'virsh\|backup\|libvirt'
# Create VM snapshot:
virsh snapshot-create-as vm-name snap1 "Pre-update snapshot"
# Backup VM disk and XML:
virsh dumpxml vm-name > /backup/vm-name.xml
cp /var/lib/libvirt/images/vm-name.qcow2 /backup/
# Automate backups:
# /etc/cron.daily/vm-backup:
#!/bin/bash
BACKDIR=/backup/vms/$(date +%Y%m%d)
mkdir -p $BACKDIR
for vm in $(virsh list --all --name); do
virsh dumpxml $vm > $BACKDIR/${vm}.xml
virsh snapshot-create-as $vm auto-$(date +%s) --disk-only --atomic
done