Freitag, 19. Juli 2013

Portforwarding an Guest VM unter KVM mit libvirt und iptables

Problembeschreibung

Ein Serversystem mit öffentlicher IP virtualisiert mehrere Gast(Server)systeme welche HTTP, MAIL, SVN(SSH) usw. bereitstellen. Als Virtualisierungslösung verwenden wir kvm mit libvirt. Als Netzwerkmodus wird "nat" verwendet, da die Gäste keine öffentlichen Adressen bekommen sollen. Die Standardkonfiguration lässt in diesen Modus die Kommunikation des Gasts nach aussen hin zu (MASQUERADING), schirmt diesen jedoch beim Zugriff auf ihn selbst ab. Dieses Problem können wir durch den gezielten Einsatz von Einträgen in den PREROUTING und FORWARDING Bereichen von iptables lösen.

Im folgenden heisst unser Gastsystem "ssh-server" und hat die Gast-IP im privaten Subnetz von "192.168.100.10". Auf den Gast läuft ein SSH Server auf Port 22 dieser soll von aussen über Port 10000 über die öffentliche IP erreichbar sein.

Lösungsansatz

Libvirt  unterstützt seit Version 0.8.0 hook Scripte. Diese werden bspw. beim starten/beenden/usw. des libvirt deamons oder auch beim starten/beenden/usw. von virtuellen Maschinen über qemu aufgerufen. Diese Funktionalität werden wir nutzen um die Gast spezifischen Firewall regeln zu realisieren.

Als erstes erstellen wir also ein qemu hook Script und machen dies ausführbar.

touch /etc/libvirt/hooks/qemu
chmod +rx /etc/libvirt/hooks/qemu
Libvirt  ruft dann später das Script u.a. beim Starten und Stoppen von Gästen mit folgenden Parametern auf
  1. Objekt (z.B. Name des Gasts)
  2. Operation (z.B. start, stopped, reconnect, etc.)
  3. Unter-Operation oder "-"
  4. Extra-Argument oder "-"
Eine umfangreiche Dokumentation über Hook Scripte und deren Argumente findet sich auf der libvirt Webseite http://www.libvirt.org/hooks.html.

Wir editieren nundas Script folgendermassen.

#!/bin/bash

Guest="ssh-server"
Guest_ip="192.168.100.10"

if [[ $1 = $Guest ]]
then
        if [[ $2 = "stopped" || $2 = "reconnect" ]]
        then
                iptables -t nat -D PREROUTING -p tcp --dport 10000 -j DNAT --to $Guest_ip:22
                iptables -D FORWARD -d $Guest_ip/32 -p tcp -m state --state NEW -m tcp \
                --dport 22 -j ACCEPT
        fi
        if [[ $2 = "start" || $2 = "reconnect" ]]
        then
                iptables -t nat -I PREROUTING -p tcp --dport 10000 -j DNAT --to $Guest_ip:22
                iptables -I FORWARD -d $Guest_ip/32 -p tcp -m state --state NEW -m tcp \
                --dport 22 -j ACCEPT
        fi
fi
Nun stoppen wir ggf. den Gast und machen das Script durch Neustarten des libvirt Deamons bekannt.
virsh destroy ssh-server
/etc/init.d/libvirt-bin restart
virsh start ssh-server
Wenn alles funktioniert hat sollten keinerlei Fehlermeldungen im Log auftauchen und die iptables die entsprechenden Regeln enthalten.
tail -f /var/log/libvirt/libvirtd.log

iptables -L
Chain FORWARD (policy ACCEPT)
target     prot opt source               destination        
ACCEPT     tcp  --  anywhere             192.168.100.10       state NEW tcp dpt:ssh

iptables -L -t nat

Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination        
DNAT       tcp  --  anywhere             anywhere             tcp dpt:10000 to:192.168.100.10:22

Referenzen

  • http://www.jimscode.ca/index.php/component/content/article/19-linux/142-linux-port-forwarding-to-guest-libvirt-vms
  • http://www.libvirt.org/hooks.html

1 Kommentar:

  1. Servus,

    Vielen Dank für den Tipp,

    Soweit hat das ganze auch geklappt ich sehe in den iptables die regeln , doch der Port ist nicht offen und ich kann von aussen nicht drauf.
    Warum ? DIE VM läuft und hat auch den NAmen der angegeben ist,

    Viele Grüße

    Christian

    AntwortenLöschen