Ports an Gäste in libvirt / KVM weiterleiten

33

Wie kann ich Ports auf einem Server, auf dem libvirt / KVM ausgeführt wird, an bestimmte Ports auf VMs weiterleiten, wenn NAT verwendet wird?

Zum Beispiel hat der Host eine öffentliche IP von 1.2.3.4. Ich möchte Port 80 auf 10.0.0.1 und Port 22 auf 10.0.0.2 weiterleiten.

Ich gehe davon aus, dass ich iptables-Regeln hinzufügen muss, bin mir aber nicht sicher, wo dies angemessen ist und was genau angegeben werden sollte.

Ausgabe von iptables -L

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     udp  --  anywhere             anywhere            udp dpt:domain 
ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:domain 
ACCEPT     udp  --  anywhere             anywhere            udp dpt:bootps 
ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:bootps 

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             10.0.0.0/24         state RELATED,ESTABLISHED 
ACCEPT     all  --  10.0.0.0/24          anywhere            
ACCEPT     all  --  anywhere             anywhere            
REJECT     all  --  anywhere             anywhere            reject-with icmp-port-unreachable 
REJECT     all  --  anywhere             anywhere            reject-with icmp-port-unreachable 

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Ausgabe von ifconfig

eth0      Link encap:Ethernet  HWaddr 00:1b:fc:46:73:b9  
          inet addr:192.168.1.14  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::21b:fcff:fe46:73b9/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:201 errors:0 dropped:0 overruns:0 frame:0
          TX packets:85 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:31161 (31.1 KB)  TX bytes:12090 (12.0 KB)
          Interrupt:17 

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

virbr1    Link encap:Ethernet  HWaddr ca:70:d1:77:b2:48  
          inet addr:10.0.0.1  Bcast:10.0.0.255  Mask:255.255.255.0
          inet6 addr: fe80::c870:d1ff:fe77:b248/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:468 (468.0 B)

Ich benutze Ubuntu 10.04.

steveh7
quelle
1
Warum ifconfig verwenden? ip ist der Nachfolger von ifconfig. ;)
Manuel Faux
5
Frage 233760 befasst sich mit niemals Versionen von libvirt. serverfault.com/questions/233760
akaihola

Antworten:

36

Die neueste stabile Version für libvirt für Ubuntu ist Version 0.7.5, die einige neuere Funktionen (z. B. Skript-Hooks und Netzwerkfilter) nicht enthält, die die automatische Netzwerkkonfiguration erleichtern. Hier erfahren Sie, wie Sie die Portweiterleitung für libvirt 0.7.5 unter Ubuntu 10.04 Lucid Lynx aktivieren.

Diese iptables-Regeln sollten den Trick machen:

iptables -t nat -I PREROUTING -p tcp -d 1.2.3.4 --dport 80 -j DNAT --to-destination 10.0.0.1:80
iptables -t nat -I PREROUTING -p tcp -d 1.2.3.4 --dport 22 -j DNAT --to-destination 10.0.0.2:22
iptables -I FORWARD -m state -d 10.0.0.0/24 --state NEW,RELATED,ESTABLISHED -j ACCEPT

Die standardmäßige KVM-NAT-Konfiguration enthält eine ähnliche Regel wie die oben angegebene dritte, lässt jedoch den Status NEW aus, der für das Akzeptieren eingehender Verbindungen unerlässlich ist.

Wenn Sie ein Startskript schreiben, um diese Regeln hinzuzufügen, und Sie nicht vorsichtig sind, überschreibt libvirt 0.7.5 diese durch Einfügen eines eigenen Skripts. Damit diese Regeln beim Start ordnungsgemäß angewendet werden, müssen Sie sicherstellen, dass libvirt initialisiert wurde, bevor Sie Ihre Regeln einfügen.

Fügen Sie vor der Zeile die folgenden Zeilen in /etc/rc.local ein exit 0:

(
# Make sure the libvirt has started and has initialized its network.
while [ `ps -e | grep -c libvirtd` -lt 1 ]; do
        sleep 1
done
sleep 10
# Set up custom iptables rules.
iptables -t nat -I PREROUTING -p tcp -d 1.2.3.4 --dport 80 -j DNAT --to-destination 10.0.0.1:80
iptables -t nat -I PREROUTING -p tcp -d 1.2.3.4 --dport 22 -j DNAT --to-destination 10.0.0.2:22
iptables -I FORWARD -m state -d 10.0.0.0/24 --state NEW,RELATED,ESTABLISHED -j ACCEPT
) &

Das sleep 10obige ist ein Hack, um sicherzustellen, dass der libvirt-Daemon die Möglichkeit hat, seine iptables-Regeln zu initialisieren, bevor wir unsere eigenen hinzufügen. Ich kann es kaum erwarten, bis sie libvirt Version 0.8.3 für Ubuntu veröffentlichen.

Isaac Sutherland
quelle
3
Können Sie erklären, wie Sie dies mit der aktuellen libvirt tun würden?
Manuel Faux
1
Sie brauchen die Befehle hacked while loop und sleep nicht, wenn eines der Hook-Skripte ausgeführt wird, nachdem libvirt sein Netzwerk initialisiert hat. Ich bin nicht sicher, ob das Skript / etc / libvirt / hooks / daemon vor oder nach der Netzwerkinitialisierung ausgeführt wird. Wenn Sie jedoch / etc / libvirt / hooks / qemu verwenden, können Sie die Regeln erstellen und zerstören, wenn die entsprechenden virtuellen Maschinen gestartet werden und halt. Ich bin nicht sicher, wie Sie Netzwerkfilter verwenden würden (wenn überhaupt), aber einige der Beispiele unter libvirt.org/firewall.html riechen so, als könnten sie geändert werden, um die Erstellung von iptables-Regeln zu automatisieren.
Isaac Sutherland
Großartig, ich kann bestätigen, dass es funktioniert, aber ich habe nicht versucht, was passiert, wenn ich den Server neu starte ...
Aron Lorincz
18

Es gibt eine Möglichkeit, die Portumleitung im laufenden Betrieb einzurichten, wenn der Gast das Netzwerk im Benutzermodus verwendet . Ich habe hier darüber gebloggt:

http://blog.adamspiers.org/2012/01/23/port-redirection-from-kvm-host-to-guest/

Sie können die Details dort sehen, aber der Einfachheit halber ist hier die Lösung, die ich herausgefunden habe:

virsh qemu-monitor-command --hmp sles11 'hostfwd_add ::2222-:22'

Dieser Einzeiler ist viel einfacher als die anderen Antworten, funktioniert jedoch nur in einigen Szenarien (Benutzermodus-Netzwerkstapel).

Adam Spires
quelle
3
Ihre Lösung ist ziemlich interessant - Können Sie einige der wichtigsten Details (oder zumindest die Anleitungen) in Ihre Antwort aufnehmen, damit es immer noch nützlich ist, wenn Ihr Blog wegen Wartungsarbeiten nicht erreichbar ist? :)
voretaq7
Fertig, zögern Sie nicht, meine SF Ruf höher als 1 gehen zu helfen ;-)
Adam Spires
Dieser Ansatz erfordert die Verwendung eines Netzwerks im Benutzermodus, was zu uninteressanten Einschränkungen führen kann. Siehe: linux-kvm.org/page/Networking#User_Networking . Weitere Referenzen: topic.alibabacloud.com/a/… , snippets.webaware.com.au/howto/… ]
Eduardo Lucio
5

Eine "offizielle" [1] Möglichkeit, dies zu tun, besteht darin, ein Hook-Skript zu erstellen, wie auf der libvirt-Website beschrieben:

http://wiki.libvirt.org/page/Networking#Forwarding_Incoming_Connections

... im Grunde wird dieses Skript aufgerufen, wenn ein KVM-Gast hochgefahren wird. Das Skript selbst fügt die entsprechenden iptable-Regeln hinzu (ähnlich der Antwort von Isaac Sutherland oben), wobei der Verbindungsstatus "NEU" korrekt hinzugefügt wird. Beachten Sie, dass Sie das Skript mit den richtigen Werten für Ihre Hosts und Ports ändern müssen.

[1] obwohl die libvirt-dokumentation selbst sagt, dass dies eine art hack ist, mach weiter

Antony Nguyen
quelle
0

Die "einzige" Möglichkeit, mit KVM (libvirt) einen Port mit dem "Standardnetzwerk" (virbr0) weiterzuleiten, ist die Verwendung des von @Antony Nguyen mitgeteilten Hacks / Workarounds. Oder einfacher gesagt, Sie können libvirt-hook-qemu verwenden .

In diesem Thread wird ausführlich erklärt, wie Sie dieses Problem für CentOS 7 (und sicherlich auch für andere Distributionen) mithilfe von libvirt-hook-qemu lösen können: https://superuser.com/a/1475915/195840 .

Eduardo Lucio
quelle
-1
iptables -t nat -I PREROUTING -d 1.2.3.4 -p tcp --dport 80 -j DNAT --to-destination 10.0.0.1
 iptables -t nat -I PREROUTING -d 1.2.3.4 -p tcp --dport 22 -j DNAT --to-destination 10.0.0.1
Platzhirsch
quelle
1
Vielen Dank dafür, aber speziell bei KVM brauchte es auch die NEUE Staatsflagge
steveh7