CIS KVM / libvirt Benchmark

Security configuration recommendations for KVM/libvirt virtualization hypervisor

v1.0.0 01-2025

Overview

▶

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.

16Recommendations
7Sections
2Profile Levels
SectionAreaFocus
1Host Access ControlQEMU process isolation and libvirt socket authorization
2Mandatory Access ControlsSELinux sVirt and AppArmor profile enforcement
3Network SecurityVirtual network isolation and VM interface filtering
4Storage SecurityVolume encryption and disk image file permissions
5Remote Access & MigrationTLS for live migration and console connections
6Resource ManagementCPU/memory limits and memory overcommit controls
7Audit & BackupAudit logging and VM backup/snapshot procedures

Profile Definitions

▶
ProfileDescriptionIntended Use
L1Level 1 — StandardEssential security for all KVM/libvirt deployments; minimal performance impact.
L2Level 2 — HardenedAdvanced hardening for PCI-DSS, HIPAA, or high-security environments.

1 — Host Access Control

▶

1.1 Process & Socket Security

▶
1.1.1 Ensure QEMU runs as a non-root user (Automated)
L1 Auto
Description

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.

Rationale

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.

Audit
# 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}'
Remediation
# Run QEMU as non-root:
# /etc/libvirt/qemu.conf:
user = "libvirt-qemu"
group = "kvm"

sudo systemctl restart libvirtd
1.1.2 Ensure libvirt socket access uses polkit authorization (Automated)
L1 Auto
Description

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.

Rationale

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.

Audit
# 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
Remediation
# 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-user

2 — Mandatory Access Controls

▶

2.1 SELinux / AppArmor

▶
2.1.1 Ensure SELinux with sVirt is enforcing (Automated)
L1 Auto
Description

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.

Rationale

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.

Audit
# Check SELinux/sVirt status:
getenforce
sestatus | grep -E 'mode|policy'

# Check VM SELinux labels:
ps -eZ | grep qemu | awk '{print $1}'
Remediation
# 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
2.1.2 Ensure AppArmor profiles are enforced for libvirt (Automated)
L1 Auto
Description

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.

Rationale

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.

Audit
# 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
Remediation
# 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

▶
3.1.1 Ensure virtual networks are properly isolated (Automated)
L1 Auto
Description

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.

Rationale

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.

Audit
# Check network isolation - list virtual networks:
virsh net-list --all
virsh net-dumpxml default | grep -E 'forward|bridge|ip'
Remediation
# 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 default
3.1.2 Ensure network filters are applied to VM interfaces (Automated)
L1 Auto
Description

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

Rationale

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.

Audit
# Check nwfilter rules:
virsh nwfilter-list
virsh nwfilter-dumpxml clean-traffic
Remediation
# 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

▶
4.1.1 Ensure storage volumes use encryption (Manual)
L2 Manual
Description

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.

Rationale

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.

Audit
# Check storage pool encryption:
virsh pool-list --all --details
virsh vol-list --pool default --details

# Check LUKS volumes:
lsblk -f | grep LUKS
Remediation
# 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
4.1.2 Ensure disk image file permissions are restrictive (Automated)
L1 Auto
Description

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.

Rationale

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.

Audit
# 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
Remediation
# 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

▶
5.1.1 Ensure TLS is configured for live migration (Automated)
L1 Auto
Description

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.

Rationale

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.

Audit
# 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
Remediation
# 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=*"]
5.1.2 Ensure VNC/Spice consoles use TLS (Automated)
L1 Auto
Description

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.

Rationale

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.

Audit
# Check VNC/Spice TLS:
grep -E 'vnc_tls|spice_tls|vnc_listen' /etc/libvirt/qemu.conf
Remediation
# 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

▶
6.1.1 Ensure CPU and memory limits are configured per VM (Automated)
L1 Auto
Description

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.

Rationale

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.

Audit
# 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
Remediation
# 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
6.1.2 Ensure memory overcommit is controlled (Automated)
L1 Auto
Description

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.

Rationale

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.

Audit
# 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
Remediation
# 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

▶
7.1.1 Ensure libvirt audit logging is enabled (Automated)
L1 Auto
Description

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.

Rationale

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.

Audit
# 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
Remediation
# 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
7.1.2 Ensure VM backup procedures are in place (Manual)
L1 Manual
Description

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.

Rationale

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.

Audit
# Check VM snapshots and backups:
virsh snapshot-list vm-name 2>/dev/null

# Check for backup scripts:
crontab -l | grep -i 'virsh\|backup\|libvirt'
Remediation
# 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