Virtualisierung isoliert systembedingt seine VMs wesentlich wirksamer als ein Containerhost seine Gäste. Allerdings bergen Implementierungsschwächen im Hypervisor und Konfigurationsfehler das Restrisiko von folgenreichen Ausbrüchen – hier erklärt am Beispiel von KVM.
Egal, ob eine Virtualisierungsumgebung nur aus wenigen Hosts bestehen wird oder ob eine komplexe Cloudlandschaft zu betonieren ist – eine Mehrheit von Admins, die Linux als Basis ihres Hypervisor einplant, gibt heute KVM den Vorzug. Dass alle üblichen Linux-Distributionen die dafür notwendigen Softwarepakete bereits mitbringen, befördert oft die Entscheidung und vereinfacht das Vorhaben selbst.
Viel zu selten beachten die Architekten solcher Setups die Sicherheit ihres Konstruktes. Zwar zeigt die Verbreitung von Containertechnologien, unter welch geringem Schutzgrad viele Anwender bereit sind zu arbeiten. Daraus und aus dem positiven Umstand, dass Virtualisierung systembedingt seine Gäste viel besser voneinander isoliert als Docker & Co., lässt sich aber nicht ableiten, dass Linux-Hypervisor wie KVM automatisch sicher wären. Der Artikel beschreibt daher Härtungsmaßnahmen und legt den Finger auf häufige Konfigurationsfehler.
Die weitreichendste Gefahr für einen Virtualisierungsserver droht, wenn es einer maliziösen VM gelingt, auszubrechen und Zugriff auf den Host und andere Gäste zu erlangen. Real wird die Gefahr durch Fehler in den Komponenten der Virtualisierung. Das Gegenmittel Nummer 1 besteht im zügigen Einspielen aller Sicherheitspatches. Der Admin kann die Wahrscheinlichkeit, dass ein Gast ausbricht, aber auch anderweitig reduzieren.
Hierzu muss er die wesentlichen Softwarekomponenten seines KVM-Ökosystems und deren Zusammenspiel gut kennen. Die Bezeichnung KVM [1], die für Kernel-based Virtual Machine steht, setzt Linux in den Mittelpunkt des Virtualisierungsgeschehens. Die KVM-Komponente des Linux-Kernel stellt aber nur die Basisfunktionen zum Ausführen virtueller Maschinen bereit. Die Anwendung, die diese Funktionen nutzt, muss sich nicht mit allen Details der Hardware herumschlagen.
KVM und Qemu teilen sich die Aufgaben
Die KVM-Funktionen, die der Kernel bereitstellt, könnte jede Linux-Anwendung benutzen, in der Praxis ist nur eine einzige relevant: Qemu [2]. Der Quick Emulator zieht KVM heran, um ein Gastsystem weitgehend nativ auf der realen Hardware auszuführen [3]. In Eigenleistung dagegen führt Qemu sicherheitskritische Operationen des Gastes aus, vor allem Zugriffe auf die (virtuelle) Hardware. Bei dieser Gelegenheit unterbricht der Rechner die native Ausführung, und KVM übernimmt die Regie. KVM lässt dann meist Qemu den Hardwarezugriff ausführen, kommt also dann ins Spiel, wenn der Gast nicht mehr nur CPU und Hauptspeicher braucht, sondern Festplatten, Netzwerk- oder Grafikkarte.
Aber auch das Gespann aus Qemu und KVM hat nicht das Zeug, um das weite Feld einer modernen Virtualisierung ertragreich zu beackern. Das ändert sich mit einer dritten Kernkomponente: Libvirt [4]. Sie ermöglicht es zum einen, mehrere Qemu-Prozesse und somit mehrere Gäste auf einem Host auszuführen. Zum anderen bietet Libvirt eine Schnittstelle an, um die Gäste beispielsweise zu starten, zu beenden oder Snapshots von VMs anzufertigen.
Die Werkzeuge »virsh« und »virt-manager« nutzen die Libvirt-Schnittstelle, um dem Wartungspersonal die Administration des Ganzen zu ermöglichen. Aber auch Programmierer können sich der Dienste der Libvirt bedienen. Dies ist insbesondere für komplexe Cloudlösungen notwendig, zum Beispiel für Open Stack. Das Zusammenspiel von KVM, Qemu und Libvirt skizziert Abbildung 1.
Keine große Hexerei: System härten in der Praxis
Den Löwenanteil des Codes der Gesamtlösung steuert nicht die KVM-Kernelkomponente bei, sondern Qemu in Form von diversen Plattform-Emulatoren. Es ist daher empfehlenswert, den Qemu-Prozess im Userspace so weit das geht einzuschränken. In der Praxis gelingt das wirksam und sogar recht einfach mittels SE Linux oder App Armor.
Das mag überraschend klingen, denn beide Zugriffskontrollsysteme besitzen den Ruf, schwierig handhabbar zu sein. Und tatsächlich steht die händische(!) Pflege der Kontrolllisten in keinem guten Verhältnis zum Nutzen. Distributionen, die jedoch eine der beiden als Standard ansehen, liefern zu allen Paketen auch eine funktionierende SE-Linux- beziehungsweise App-Armor-Konfiguration mit – so auch für Libvirt.
Das Härten von Qemu besteht im Wesentlichen aus der Aufgabe, eine Linux-Distribution zu wählen, welche von Haus aus SE Linux oder App Armor unterstützt. In einem solchen Fall erzeugt Libvirt die Regeln für entsprechende Schutzfunktionen automatisch, was die Privilegien des Qemu-Prozesses in geeigneter Weise einschränkt. Insbesondere limitiert dies den Zugriff auf fremde Festplattenabbilder, die lokal gespeichert sind.
Auch nutzt Libvirt andere Härtungsfunktionen wie Cgroups, um den Qemu-Prozess effektiv abzusichern, sofern das Betriebssystem dies unterstützt – ein weiterer Grund, bei der Linux-Distribution genau hinzusehen. Von Debian ist beispielsweise mangels Support für SE Linux und App Armor abzuraten. Ubuntu, Red Hat Enterprise Linux 7 und Centos 7 dagegen empfehlen sich mit serienmäßigem App Armor beziehungsweise SE Linux.
Kernel Samepage Merging
RHEL und sein Klon patzen jedoch an anderer Stelle: Sie aktivieren bei der Installation von Qemu automatisch Kernel Samepage Merging (KSM, [5]). Diese eigentlich gut gemeinte Technik dedupliziert Speicherseiten identischen Inhalts. Dies verspricht gerade auf einem Virtualisierungshost Effizienz, da Gäste mit gleichen Betriebssystemen viele Speicherseiten mit identischem Inhalt besitzen, die der Host dank KSM nur einmal im RAM halten braucht.
Abgesehen davon, dass KSM in der Praxis oft wesentlich weniger Arbeitsspeicher einspart als erwartet, birgt es auch erhebliche sicherheitstechnische Gefahren. Das Problem ist, dass zwei Gäste, die auf dieselbe physische Speicherseite Zugriff haben, das Verhalten des jeweils anderen Gastes auf eben dieser Speicherseite ermitteln können. Beim ersten Zugriff landet die Seite im CPU-Cache, der ab dem zweiten Lesezugriff die Daten gut messbar schneller ausliefert. Mit KSM kann ein zweiter Gast so feststellen, ob der erste zuvor zu den eigenen Daten identische gelesen hat.
Wer annimmt, dies sei nur unter Laborbedingungen bedeutsam, irrt: Das Beispiel [6] zeigt, wie in einer realen Cloud ein Gast den AES-Schlüssel für Open SSL eines anderen Gastes ermitteln konnte.
Jeder Admin produktiv genutzter Virtualisierungsumgebungen sollte daher sicherstellen, dass KSM deaktiviert ist. Bei Red Hat Enterprise Linux 7, Centos 7 und anderen muss er dies manuell tun. Listing 1 zeigt, wie er überprüft, ob KSM aktiv ist. Weichen die Ausgaben des Systems von denen im Listing ab, so ist KSM mit hoher Wahrscheinlichkeit aktiv. Für diesen Fall zeigt Listing 2, wie sich KSM auf einem Centos-7-System abschalten lässt.
Listing 1
KSM-Zustand überprüfen
01 # cat /sys/kernel/mm/ksm/run 02 0 03 # cat /sys/kernel/mm/ksm/pages_shared 04 0 05 # pgrep ksmtuned
Listing 2
KSM deaktivieren
01 # systemctl stop ksmtuned 02 Stopping ksmtuned: [ OK ] 03 # systemctl stop ksm 04 Stopping ksm: [ OK ] 05 # systemctl disable ksm 06 # systemctl disable ksmtuned 07 # echo 2 > /sys/kernel/mm/ksm/run
Heikel: Die Netzanbindung
Eine weitere Herausforderung für jeden Virtualisierungshost ist die sichere Anbindung der Gäste an das Netzwerk. Im Wesentlichen entstehen drei Arten von Netzwerkkommunikation: Erstens die der Gäste mit anderen Gästen oder der Außenwelt. Zweitens die administrative Kommunikation zum Verwalten und Steuern der Gäste. Drittens der Traffic hin zum Speicherbackend zum Zugriff auf die Festplattenabbilder. Typischerweise trennen Admins diese Ströme mittels mehrerer physischer Netzwerke voneinander. Einen einfachen Aufbau eines Hosts mit drei Netzwerkschnittstellen skizziert Abbildung 2.
Das Problem hierbei ist, dass der Linux-Kernel gerne kommuniziert. Konkret bedeutet dies, dass bei fehlerhafter Konfiguration der Gast nicht nur auf das Gast-, sondern auch die anderen Netzwerke zugreifen darf. Im ungünstigen Fall kann dies beispielsweise zur Folge haben, dass der Gast auf Festplattenabbilder anderer Gäste Zugriff erlangt.
Ein Angriffsszenario
Das folgende Beispiel geht davon aus, dass der Host die Anbindung als eine Linux-Bridge realisiert. (Aber auch bei anderen Anbindungsmethoden, wie Macvtap [7], entstehen ähnliche Gefahren.) Paketweiterleitungen soll der Host dann auf Layer 2 ausführen. Im einfachsten Fall fungiert er also als Switch, der Pakete zwischen den Gästen untereinander oder zwischen Gast und externer Netzwerkschnittstelle des Gastnetzwerkes vermittelt. Das Routing übernimmt meist ein externes Gerät, dessen Adresse der Gast per DHCP erfährt.
Was aber ist, wenn der Gast den Host als Router verwendet? Wie verhält sich der Host, wenn er vom Gast ein Paket empfängt, dessen Ziel-IP-Adresse zu einem Rechner des Speicherbackends gehört? Technisch gesehen reduziert sich das auf die Frage, ob IP-Forwarding auf dem Host aktiviert ist. Nein, möchte man annehmen, denn es gibt keinen Grund, dies zu tun.
Leider geschieht genau das automatisch im Rahmen der Installation von Libvirt. Wenn der Administrator nun noch den Fehler begeht, nicht nur den Netzwerkschnittstellen von Management- und Storagenetz, sondern auch der des Gastnetzwerkes eine IP-Adresse zuzuweisen, geht das Scheunentor auf. Nun verhält sich der Host wie ein Router, der freimütig Pakete zwischen den Netzwerken vermittelt, wenn man ihn nur darum bittet.
Routing ohne IP-Adresse
Aber auch wenn die Schnittstelle des Gastnetzwerkes keine IP-Adresse besitzt, gelingt es dem Gast unter Umständen, über die Grenze des Gastnetzwerkes hinaus zu kommunizieren. Das liegt am Mechanismus des IP-Forwarding, der zwar im Grunde einfach gestrickt, aber wenig intuitiv ist. Denn was macht ein Linux-System mit einem empfangenen Paket, das auf Layer 2 (MAC-Adresse) an sich, auf Layer 3 (IP-Adresse) aber an ein anderes System adressiert ist? Vereinfacht gesagt passiert dies: Wenn IP-Forwarding aktiviert ist, dann schickt Linux das Paket an das Zielsystem weiter, andernfalls verwirft es das Paket. Hieraus folgt, dass die Netzwerkschnittstelle, auf der ein Paket ankommt, selber keine IP-Adresse besitzen muss, damit der Kernel auf die Idee kommt, es weiterzuleiten.
Zwar funktioniert die Weiterleitung eines Antwortpaketes in der Praxis oft nicht. Dennoch: Auch ein falsch vermitteltes DHCP- oder DNS-Paket kann großen Schaden anrichten. Der Admin muss daher sicherstellen, keine IP-Adresse an die Netzwerkschnittstelle des Gastnetzwerkes zu binden, das IP-Forwarding ab- und den RP-Filter anzuschalten.
Eine Studie als Quelle
Die Sicherheit KVM-basierter Virtualisierungen lässt sich getrost als sehr vielschichtig quantifizieren, weshalb dieser Artikel nur einige, wenn auch sehr zentrale Punkte herausgegriffen hat. Das Material dafür stammt aus einer neuen Sicherheitsanalyse, die das Unternehmen Open Source Security Ralf Spenneberg [8] im Auftrag des deutschen Bundesamtes für Sicherheit in der Informationstechnik [9] im Jahr 2016 unternahm. In dem Rahmen hat die Firma nicht nur die Sicherheit von KVM selbst untersucht, sondern auch von dessen Ökosystem, bestehend aus Qemu und Libvirt. Hinzu kam die Betrachtung der netzwerkbasierten Datenspeicherung per Ceph und Gluster-FS. Die Studie wird voraussichtlich in nächster Zeit veröffentlicht.
Infos
- KVM: https://www.linux-kvm.org
- Qemu: http://www.qemu-project.org
- Oliver Rath, Hans-Peter Merkel, Markus Feilner, “PCI-Devices des Hosts an die Kernel Virtual Machine (KVM) durchreichen”: Linux-Magazin 04/10, S. 76
- Libvirt: http://libvirt.org
- Christoph Mitasch, “KSM”: https://www.thomas-krenn.com/de/wiki/KSM_(Kernel_Samepage_Merging)
- Gorka Irazoqui, Mehmet Sinan Inci, et al., “Wait a minute!; A fast, Cross-VM attack on AES”: https://eprint.iacr.org/2014/435.pdf
- Macvtap: http://virt.kernelnewbies.org/MacVTap
- Open Source Security Ralf Spenneberg: https://opensource-security.de
- Bundesamt für Sicherheit in der Informationstechnik: https://www.bsi.bund.de








