Reenvío de puertos a invitados en libvirt / KVM

33

¿Cómo puedo reenviar puertos en un servidor que ejecuta libvirt / KVM a puertos específicos en máquinas virtuales, cuando uso NAT?

Por ejemplo, el host tiene una IP pública de 1.2.3.4. Quiero reenviar el puerto 80 a 10.0.0.1 y el puerto 22 a 10.0.0.2.

Supongo que necesito agregar reglas de iptables, pero no estoy seguro de dónde es apropiado y qué debe especificarse exactamente.

Salida de 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         

Salida de 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)

Estoy usando Ubuntu 10.04.

steveh7
fuente
1
¿Por qué usar ifconfig? ip es el sucesor de ifconfig. ;)
Manuel Faux
55
La pregunta 233760 aborda esto en las versiones nunca de libvirt. serverfault.com/questions/233760
akaihola

Respuestas:

37

La última versión estable de libvirt para Ubuntu es la versión 0.7.5, que no tiene algunas características más recientes (es decir, enlaces de script y filtros de red) que facilitan la configuración automática de la red. Dicho esto, aquí se explica cómo habilitar el reenvío de puertos para libvirt 0.7.5 en Ubuntu 10.04 Lucid Lynx.

Estas reglas de iptables deberían hacer el truco:

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

La configuración NAT KVM predeterminada proporciona una regla similar a la 3ra que di arriba, pero omite el estado NUEVO, que es esencial para aceptar conexiones entrantes.

Si escribe un script de inicio para agregar estas reglas y no tiene cuidado, libvirt 0.7.5 las anula insertando las suyas. Por lo tanto, para asegurarse de que estas reglas se apliquen correctamente en el inicio, debe asegurarse de que libvirt se haya inicializado antes de insertar sus reglas.

Agregue las siguientes líneas a /etc/rc.local, antes de la línea 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
) &

Lo sleep 10anterior es un truco para asegurarse de que el demonio libvirt haya tenido la oportunidad de inicializar sus reglas de iptables antes de agregar las nuestras. No puedo esperar hasta que publiquen libvirt versión 0.8.3 para Ubuntu.

Isaac Sutherland
fuente
3
¿Puedes explicar cómo harías esto con libvirt actual?
Manuel Faux
1
No necesita los comandos pirateados mientras que el bucle y el sueño si uno de los scripts de enlace se ejecuta después de que libvirt haya inicializado su red. No estoy seguro de si el script / etc / libvirt / hooks / daemon se ejecuta antes o después de la inicialización de la red, pero si usa / etc / libvirt / hooks / qemu podría crear y destruir las reglas cuando se inicien las máquinas virtuales apropiadas y detener. No estoy seguro de cómo usaría los filtros de red (si es que lo hace), pero algunos de los ejemplos en libvirt.org/firewall.html huelen como si pudieran modificarse para automatizar la creación de reglas de iptables.
Isaac Sutherland
Genial, puedo confirmar que funciona, sin embargo, no he probado lo que sucede si reinicio el servidor ...
Aron Lorincz
18

Hay una manera de configurar la redirección de puertos sobre la marcha cuando el invitado está utilizando la red en modo de usuario , escribí en un blog aquí:

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

Puede ver los detalles allí, pero por conveniencia, aquí está la solución que descubrí:

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

Esta línea es mucho más fácil que las otras respuestas, pero solo funciona en algunos escenarios (pila de red en modo de usuario).

Adam Spires
fuente
3
Su solución es bastante interesante: ¿puede incluir algunos de los detalles más destacados (o al menos los bits de procedimientos) en su respuesta para que siga siendo útil si su blog no funciona por mantenimiento? :)
voretaq7
Listo, siéntase libre de ayudar a que mi reputación SF supere 1 ;-)
Adam Spires
Este enfoque requiere el uso de una red en modo de usuario que puede traernos algunas limitaciones poco interesantes. Ver: linux-kvm.org/page/Networking#User_Networking . Otras referencias: topic.alibabacloud.com/a/… , snippets.webaware.com.au/howto/… ]
Eduardo Lucio
5

Una forma más "oficial" [1] de hacer esto es crear un script de enlace como se describe en el sitio web de libvirt:

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

... básicamente, este script se invocará cuando se inicie un invitado KVM. El script mismo agregará las reglas iptable apropiadas (similar a la respuesta de Isaac Sutherland anterior) con el estado de conexión 'NUEVO' agregado correctamente. Tenga en cuenta que debe modificar el script con los valores correctos para sus hosts y puertos.

[1] aunque la documentación de libvirt dice que esto es una especie de truco, imagínate

Antony Nguyen
fuente
0

La "única" forma en que podemos hacer un puerto hacia adelante usando KVM (libvirt) con la "red predeterminada" (virbr0) es usando el hack / solución informada por @Antony Nguyen. O más simplemente puedes usar libvirt-hook-qemu .

Este hilo tiene una explicación completa de cómo resolver este problema para CentOS 7 (y ciertamente para otras distribuciones) usando libvirt-hook-qemu: https://superuser.com/a/1475915/195840 .

Eduardo Lucio
fuente
-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
mandamás
fuente
1
Gracias por esto, pero con KVM específicamente también necesitaba la NUEVA bandera del estado
steveh7