作業ログ源泉垂れ流し

しがないIT技術者の作業ログを垂れ流す

KVMのネットワークフィルタ設定

libvirtに備わっているネットワークフィルタ機能 (nwfilter) をVMに適用してみる。

libvirtの公式ドキュメントを参考に作業を進める。

nwfilterは(バックエンドがnftablesであっても)iptablesを使ってフィルタリングを行うので、まずはnwfilter未設定時のiptables設定を確認する。

# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
  161 14807 LIBVIRT_INP  all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 LIBVIRT_FWX  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 LIBVIRT_FWI  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 LIBVIRT_FWO  all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
  122 11453 LIBVIRT_OUT  all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain LIBVIRT_FWI (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     all  --  *      virbr0  0.0.0.0/0            192.168.122.0/24     ctstate RELATED,ESTABLISHED
    0     0 REJECT     all  --  *      virbr0  0.0.0.0/0            0.0.0.0/0            reject-with icmp-port-unreachable

Chain LIBVIRT_FWO (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     all  --  virbr0 *       192.168.122.0/24     0.0.0.0/0           
    0     0 REJECT     all  --  virbr0 *       0.0.0.0/0            0.0.0.0/0            reject-with icmp-port-unreachable

Chain LIBVIRT_FWX (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     all  --  virbr0 virbr0  0.0.0.0/0            0.0.0.0/0           

Chain LIBVIRT_INP (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     udp  --  virbr0 *       0.0.0.0/0            0.0.0.0/0            udp dpt:53
    0     0 ACCEPT     tcp  --  virbr0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:53
    0     0 ACCEPT     udp  --  virbr0 *       0.0.0.0/0            0.0.0.0/0            udp dpt:67
    0     0 ACCEPT     tcp  --  virbr0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:67

Chain LIBVIRT_OUT (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     udp  --  *      virbr0  0.0.0.0/0            0.0.0.0/0            udp dpt:53
    0     0 ACCEPT     tcp  --  *      virbr0  0.0.0.0/0            0.0.0.0/0            tcp dpt:53
    0     0 ACCEPT     udp  --  *      virbr0  0.0.0.0/0            0.0.0.0/0            udp dpt:68
    0     0 ACCEPT     tcp  --  *      virbr0  0.0.0.0/0            0.0.0.0/0            tcp dpt:68

既にlibvirtによってDNSDHCPを通すフィルタリングなどが設定されている。

まずはフィルタtest-filterを定義する。 ここではホスト環境のIPアドレス192.168.122.1へのsshをブロックするルールを書いてみる。
ルールの詳細は公式ドキュメントを参考にする。

$ virsh nwfilter-define <(cat <<EOF
<filter name='test-filter'>
  <rule action='drop' direction='out'>
    <tcp dstipaddr='192.168.122.1' dstportstart='22'/>
  </rule>
</filter>
EOF
)
$ virsh nwfilter-dumpxml test-filter
<filter name='test-filter' chain='root'>
  <uuid>49978302-912f-45b2-8298-af957757177e</uuid>
  <rule action='drop' direction='out' priority='500'>
    <tcp dstipaddr='192.168.122.1' dstportstart='22'/>
  </rule>
</filter>

いま定義したフィルタtest-filterVM kvmdomに設定する。

$ virsh edit kvmdom
     <interface type='network'>
       <mac address='52:54:00:fa:68:d9'/>
       <source network='default'/>
       <model type='virtio'/>
+      <filterref filter='test-filter'/>
       <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
     </interface>
Domain kvmdom XML configuration edited.

VM kvmdomを起動する。

$ virsh start kvmdom

iptables設定を確認してみる。

# iptables -nvL

追加された部分

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
   21  2032 libvirt-host-in  all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 libvirt-in  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 libvirt-out  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 libvirt-in-post  all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain FI-vnet2 (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       tcp  --  *      *       0.0.0.0/0            192.168.122.1        tcp dpt:22

Chain FO-vnet2 (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       tcp  --  *      *       192.168.122.1        0.0.0.0/0            tcp spt:22

Chain HI-vnet2 (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       tcp  --  *      *       0.0.0.0/0            192.168.122.1        tcp dpt:22

Chain libvirt-host-in (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    2   656 HI-vnet2   all  --  *      *       0.0.0.0/0            0.0.0.0/0           [goto]  PHYSDEV match --physdev-in vnet2

Chain libvirt-in (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 FI-vnet2   all  --  *      *       0.0.0.0/0            0.0.0.0/0           [goto]  PHYSDEV match --physdev-in vnet2

Chain libvirt-in-post (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            PHYSDEV match --physdev-in vnet2

Chain libvirt-out (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 FO-vnet2   all  --  *      *       0.0.0.0/0            0.0.0.0/0           [goto]  PHYSDEV match --physdev-out vnet2 --physdev-is-bridged

先ほど定義したルールはChain FI-vnet2, FO-vnet2, HI-vnet2 に定義されている。
実際にVM kvmdomから192.168.122.1sshしてみても接続できない。

libvirtの機能を使ってVMにネットワークフィルタを設定できた!