kvm如何禁止虚拟机之间通信

一般来说,使用KVM创建虚拟机,都会有虚拟机之间通信的需求,KVM的四种网络模式也都默认允许同一网段的虚拟机之间互通。如果有特殊需求,需要禁止虚拟机之间的通信,该如何配置?

KVM四种网络模式

  • 首先隔离模式,相当于Vmware/Vbox 仅主机模式,VM之间可通信,VM与宿主可通信,VM与外部不可通信

  • NAT模式,VM之间可通信,VM与宿主可通信,VM可访问外部,外部访问VM需要做端口转发

  • 桥接模式,VM之间可通信,VM与宿主可通信,VM可访问外部,外部可访问VM。一般桥接模式下VM网段与宿主机同段。

  • 路由模式,VM之间可通信,VM与宿主可通信,VM可访问外部,外部可访问VM。路由模式下VM网段可以与宿主机不同端,外部需要配置路由才能访问VM

iptables解决方案

搜了资料,有人说可以用iptables实现,原理如下

NAT模式下,宿主机有一块网卡virbr0。针对virbr0,在iptables中FORWARD链限制同网段互访

1
-A FORWARD -i virbr0 -s 192.168.1.0/24 -d 192.168.1.0/24 -j DROP

我尝试了下,不知为何不生效,也许因为虚拟机互访实际流量并不经过virbr0?尝试将FORWARD链改为INPUT链也是不生效。后来放弃iptables,改用nwfilter。

nwfilter解决方案

nwfilter是kvm自带的网络流量工具,可以精确控制每一块vm网卡。上面iptables的方案是在宿主机上做策略,而nwfilter是对每一个vm做策略,nwfilter的策略可以应用在多个vm上。

总的来说nwfilter的用法就是,定义nwfilter策略,生效策略,应用策略。下面以NAT模式下禁止虚拟机之间互通为例介绍nwfilter解决方案

定义策略

在/etc/libvirt/nwfilter下建立xml文件

1
vi /etc/libvir/nwfilter/deny-inter.xml

写入规则

1
2
3
4
5
6
7
8
9
<filter name='deny-inter' chain='ipv4' priority='-700'>
<uuid>ab4b9613-3442-41af-a4b3-0a3bdaae7111</uuid>
<rule action='accept' direction='in' priority='200'>
<ip srcipaddr='192.168.122.1' srcipmask='32'/>
</rule>
<rule action='drop' direction='in' priority='201'>
<ip srcipaddr='192.168.122.0' srcipmask='24'/>
</rule>
</filter>

其中,

这里只采用了ipv4的链,只需要对ip包进行过滤

注意uuid不要与现有的相同

每条规则后的优先级越小越优,如果优先级相同优先匹配前面的规则

这里的规则将来是应用在虚拟机上,所以in/out是针对虚拟机网卡的

第一条规则是为了保证dhcp正常工作,这里用in方向策略会方便一点,因为dhcp discover包发出去是广播,dhcp offer包回来是单播,in方向只需要允许宿主机的单播包就可以了

更多nwfilter的详细用法可以参考VirtualNetworking - Libvirt Wiki

生效策略

1
2
virsh nwfilter-define deny-inter.xml #生效策略
virsh nwfilter-list #查看是否生效

应用策略

编辑虚拟机配置文件

1
virsh edit vm01

找到添加定义过的策略

1
2
3
4
5
6
<interface type='network'>
<mac address='52:54:00:ec:f5:4e'/>
<source network='default'/>
<model type='e1000'/>
<filterref filter='deny-inter'/> #ADD POLICY
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>

最后重启虚拟机,VM之间无法ping通,VM与宿主机可通,VM ping 外面可通。