KVM将端口转发到Linux上具有UFW的来宾VM

时间:2020-01-09 10:41:10  来源:igfitidea点击:

我的Debian/Ubuntu/CentOS Linux服务器使用KVM作为虚拟机的管理程序
如何使用UFW iptables将端口转发到来宾VM。
使用NAT时,如何将运行libvirt/KVM的Linux服务器上的端口转发到VM上的指定端口?
如何使用iptables配置KVM/libvirt转发端口到来宾?

本教程将学习如何使用ufw将端口转发到在CentOS 7或Debian 9或Ubuntu Linux LTS服务器上运行的libvirt/KVM中的来宾VM。
例如,主机的公共IP为192.54.1.4。
您要将所有端口转发到192.168.122.253。
假设您使用的是NAT版本的网络。
您想允许外部访问您的VM提供的服务。

本教程将学习使用Linux上运行的ufw将NAT端口转发到VM的过程。

查看有关您的KVM网络的信息

执行以下命令:

# virsh net-list
# virsh net-info default
# virsh net-dumpxml default

了解KVM网络和默认iptables/ufw规则

从上面的命令中可以明显看出,我在nat模式下设置了虚拟网络(virbr0)。
在nat模式下,所有VM均可建立传出连接。
默认网络中的每个来宾VM也可以互相通信。
主机操作系统也可以与所有来宾VM通信。
但是,所有来自Internet或LAN上其他主机的连接均被阻止。

KVM/libvirt设置默认规则如下:

iptables -A FORWARD -d 192.168.122.0/24 -o virbr0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

您需要按以下方式更新FORWARD以在nat模式下接受每个VM的新连接:

iptables -A FORWARD -s 192.168.1.0/24 -d 192.168.122.0/24 -o virbr0 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT

步骤1配置KVM防火墙挂钩

默认的KVM NAT配置提供了一个规则,但它忽略了NEW状态,这对于接受新的传入连接至关重要。
要解决此问题,请创建如下所示的钩子:

# cd /etc/libvirt/hooks/

使用文本编辑器(例如vim命令或nano命令)创建名为qemu的文件

# vi qemu

追加代码如下:

#!/bin/bash
# Hook to insert NEW rule to allow connection for VMs
# 192.168.122.0/24 is NATed subnet (replace this with your public IPv4 sub/net)
# virbr0 is networking interface for VM and host
# ----------------------------------------------------------------
# Written by  under GPL v3.x {https://www.theitroad.local}
# ----------------------------------------------------------------
# get count
#################################################################
## NOTE replace 192.168.122.0/24 with your public IPv4 sub/net ##
#################################################################
v=$(/sbin/iptables -L FORWARD -n -v | /usr/bin/grep 192.168.122.0/24 | /usr/bin/wc -l)
# avoid duplicate as this hook get called for each VM
[ $v -le 2 ] && /sbin/iptables -I FORWARD 1 -o virbr0 -m state -s 192.168.1.0/24 -d 192.168.122.0/24 --state NEW,RELATED,ESTABLISHED -j ACCEPT

在VIM/vi文本编辑器中保存并关闭文件。
使用chmod命令设置权限:

# chmod +xv /etc/libvirt/hooks/qemu

步骤2将UFW(Iptables防火墙)配置为端口转发

使用文本编辑器编辑/etc/ufw/before.rules文件:下一步将ssh流量转发到位于192.168.122.125的192.54.1.5 VM2。

# vim /etc/ufw/before.rules

在文件顶部添加:

# KVM/libvirt Forward Ports to guests with Iptables (UFW) #
*nat
:PREROUTING ACCEPT [0:0]
-A PREROUTING -d 192.54.1.4 -p tcp --dport 1:65535 -j DNAT --to-destination 192.168.122.253:1-65535 -m comment --comment "VM1/CentOS 7 ALL ports forwarding"
-A PREROUTING -d 192.54.1.5 -p tcp --dport 22 -j DNAT --to-destination 192.168.122.125:22 -m comment --comment "VM2/OpenBSD SSH port forwarding"
-A PREROUTING -d 192.54.1.6 -p tcp --dport 443 -j DNAT --to-destination 192.168.122.231:443 -m comment --comment "VM3/FreeBSD 443 port forwarding"
-A PREROUTING -d 192.54.1.7 -p tcp --dport 80 -j DNAT --to-destination 192.168.122.229:80 -m comment --comment "VM4/CentOS 80 port forwarding"
COMMIT

在vim/vi文本编辑器中保存并关闭文件。
您可以使用以下命令重新加载规则,或简单地重新引导Linux服务器:

# bash /etc/libvirt/hooks/qemu
# ufw reload

或者

# reboot

步骤3验证转发端口到libvirt/KVM中的guest虚拟机是否正常

您可以使用以下语法列出iptables规则。
首先确保在FORWARD链的顶部有新规则:

# iptables -L FORWARD -nv --line-number

接下来,确保使用/etc/ufw/before.rules文件中设置的DNAT将外部连接转发到每个VM。
您可以使用iptables命令列出nat/DNAT预路由规则:

# iptables -t nat -L PREROUTING -n -v --line-number
# iptables -t nat -L -n -v

请注意,MASQUERADE规则由KVM/libvirt自动添加。
尝试ping命令或curl命令或ssh命令从外部访问VM:

$ ping 192.54.1.4
$ curl -I 192.54.1.4
# login to VM2/openbsd
$ ssh [email protected]

Linux在libvirt/KVM iptables规则中将端口转发给来宾

如果您不使用UFW,则这里是实际iptables规则的转储:

# iptables-save -t nat

输出示例:

# Generated by iptables-save v1.4.21 on Tue Jul 31 03:14:18 2016
*nat
:PREROUTING ACCEPT [72:5501]
:INPUT ACCEPT [42:3301]
:OUTPUT ACCEPT [32:4304]
:POSTROUTING ACCEPT [32:4304]
-A PREROUTING -d 192.54.1.4/32 -p tcp -m tcp --dport 1:65535 -m comment --comment "VM1/CentOS 7 ALL ports forwarding" -j DNAT --to-destination 192.168.122.253:1-65535
-A PREROUTING -d 192.54.1.5/32 -p tcp -m tcp --dport 22 -m comment --comment "VM2/OpenBSD SSH port forwarding" -j DNAT --to-destination 192.168.122.125:22
-A PREROUTING -d 192.54.1.6/32 -p tcp -m tcp --dport 443 -m comment --comment "VM3/FreeBSD 443 port forwarding" -j DNAT --to-destination 192.168.122.231:443
-A PREROUTING -d 192.54.1.7/32 -p tcp -m tcp --dport 80 -m comment --comment "VM4/CentOS 80 port forwarding" -j DNAT --to-destination 192.168.122.229:80
-A POSTROUTING -s 192.168.122.0/24 -d 224.0.0.0/24 -j RETURN
-A POSTROUTING -s 192.168.122.0/24 -d 255.255.255.255/32 -j RETURN
-A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p tcp -j MASQUERADE --to-ports 1024-65535
-A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p udp -j MASQUERADE --to-ports 1024-65535
-A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -j MASQUERADE
COMMIT

以及来自kvm钩子shell脚本的FORWARD规则

# iptables-save -t filter | grep FORWARD

输出示例(将192.168.1.0/24替换为您的公共IPv4子网/网络):

:FORWARD DROP [0:0]
-A FORWARD -s 192.168.1.0/24 -d 192.168.122.0/24 -o virbr0 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -d 192.168.122.0/24 -o virbr0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -s 192.168.122.0/24 -i virbr0 -j ACCEPT
-A FORWARD -i virbr0 -o virbr0 -j ACCEPT
-A FORWARD -o virbr0 -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -i virbr0 -j REJECT --reject-with icmp-port-unreachable