これ・・全くプログラミングに関係ないネタなんですが、
Qiitaに投稿していいんでしたっけ・・・?
と不安になりつつも、強い心で第2回です。 @Qiita初心者
前回はnf_conntrackインテグレーションに対応したOpen vSwitchのインストールから起動までを紹介しました。
Open vSwitchのconntrack連携を試してみた(その1)
今回は、最も簡単な構成でステートフルインスペクションの設定をして通信確認をしてみます。
テスト構成
下図のように、物理ホスト上にVMを2個起動し、Open vSwitchにて接続します。ゲストOSとしてはCentOS6をインストールしました。
ここで、
- VM1からVM2向けにイニシエートされた通信の戻りパケットは許可し、それ以外は拒否する
というポリシーをOpen vSwitchのフローエントリで実装してみます。
Step1. VMの起動
CentOSをインストールしたディスクイメージを2個用意し、普通にqemuを2個起動します。
■ VM1
/usr/libexec/qemu-kvm -smp 1 -m 1024 -vnc :1 -k ja -enable-kvm -daemonize \
-drive file=centos6-1.qcow2,if=virtio,index=0,media=disk,cache=none,aio=native \
-netdev type=tap,vhost=on,vnet_hdr=off,id=tap1,ifname=tap1,script=no,downscript=no \
-device virtio-net-pci,netdev=tap1,mac=52:54:00:60:4d:6e \
-netdev type=tap,vhost=on,vnet_hdr=off,id=tap2,ifname=tap2,script=no,downscript=no \
-device virtio-net-pci,netdev=tap2,mac=52:54:00:60:84:ff \
■ VM2
/usr/libexec/qemu-kvm -smp 1 -m 1024 -vnc :2 -k ja -enable-kvm -daemonize \
-drive file=centos6-2.qcow2,if=virtio,index=0,media=disk,cache=none,aio=native \
-netdev type=tap,vhost=on,vnet_hdr=off,id=tap3,ifname=tap3,script=no,downscript=no \
-device virtio-net-pci,netdev=tap3,mac=52:54:00:ba:61:f3 \
-netdev type=tap,vhost=on,vnet_hdr=off,id=tap4,ifname=tap4,script=no,downscript=no \
-device virtio-net-pci,netdev=tap4,mac=52:54:00:99:90:78 \
それぞれ、2個目のNIC(tap2とtap4)をOpen vSwitch通信テスト用に利用します。
先頭のNIC(tap1とtap3)はsshログイン用です。
Step2. 仮想NICをOpen vSwitchに接続
Open vSwitch(br0)にtap2とtap4を普通に接続します。
ovs-vsctl add-port br0 tap2
ovs-vsctl add-port br0 tap4
正常に接続できると、以下のようになると思います。今回物理NIC(eth2)は使いません。
[root@sl67-r3 ~]# ovs-ofctl show br0
OFPT_FEATURES_REPLY (xid=0x2): dpid:000090e2ba230f70
n_tables:254, n_buffers:256
capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
1(eth2): addr:90:e2:ba:23:0f:70
config: 0
state: 0
current: 10GB-FD
advertised: 10GB-FD FIBER
supported: 10GB-FD FIBER
speed: 10000 Mbps now, 10000 Mbps max
2(tap2): addr:ae:b4:ef:2b:24:6b
config: 0
state: 0
current: 10MB-FD COPPER
speed: 10 Mbps now, 0 Mbps max
3(tap4): addr:02:c6:fe:6c:2f:73
config: 0
state: 0
current: 10MB-FD COPPER
speed: 10 Mbps now, 0 Mbps max
LOCAL(br0): addr:90:e2:ba:23:0f:70
config: 0
state: 0
speed: 0 Mbps now, 0 Mbps max
OFPT_GET_CONFIG_REPLY (xid=0x4): frags=normal miss_send_len=0
tap2(VM1)とtap4(VM2)は、それぞれofport=2とofport=3が割り当てられました。次節のフローエントリ設定では、このofport番号を使用します。
この状態で、VM1とVM2間で普通に通信できることを確認しておきます。
[root@centos6-1 ~]# ip addr show dev eth1
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 52:54:00:60:84:ff brd ff:ff:ff:ff:ff:ff
inet 192.168.0.1/24 brd 192.168.0.255 scope global eth1
inet6 fe80::5054:ff:fe60:84ff/64 scope link
valid_lft forever preferred_lft forever
[root@centos6-1 ~]# ping 192.168.0.2
PING 192.168.0.2 (192.168.0.2) 56(84) bytes of data.
64 bytes from 192.168.0.2: icmp_seq=1 ttl=64 time=0.956 ms
64 bytes from 192.168.0.2: icmp_seq=2 ttl=64 time=0.518 ms
ここまではいつも通り、問題なっしですね。
Step3. conntrack連携するフローエントリを設定
以下のようなフローエントリをovs-ofctlコマンドで設定します。
# cat a.flow
priority=100,ip,actions=ct(table=1)
priority=10,arp,actions=normal
priority=1,actions=drop
table=1,in_port=2,ct_state=+new,actions=ct(commit),normal
table=1,in_port=2,ct_state=+est,actions=normal
table=1,in_port=3,ct_state=+new,actions=drop
table=1,in_port=3,ct_state=+est,actions=normal
# ovs-ofctl add-flows br0 a.flow
ct_stateやactions=ct(xxxx)あたりがconntrackテーブルに登録したり、参照したりする構文です。
正しく設定できると、以下のようになると思います。
[root@sl67-r3 ~]# ovs-ofctl dump-flows br0
NXST_FLOW reply (xid=0x4):
cookie=0x0, duration=46.236s, table=0, n_packets=0, n_bytes=0, idle_age=46, priority=100,ip actions=ct(table=1)
cookie=0x0, duration=46.236s, table=0, n_packets=0, n_bytes=0, idle_age=46, priority=10,arp actions=NORMAL
cookie=0x0, duration=46.236s, table=0, n_packets=0, n_bytes=0, idle_age=46, priority=1 actions=drop
cookie=0x0, duration=46.236s, table=1, n_packets=0, n_bytes=0, idle_age=46, ct_state=+new,in_port=2 actions=ct(commit),NORMAL
cookie=0x0, duration=46.235s, table=1, n_packets=0, n_bytes=0, idle_age=46, ct_state=+new,in_port=3 actions=drop
cookie=0x0, duration=46.236s, table=1, n_packets=0, n_bytes=0, idle_age=46, ct_state=+est,in_port=2 actions=NORMAL
cookie=0x0, duration=46.235s, table=1, n_packets=0, n_bytes=0, idle_age=46, ct_state=+est,in_port=3 actions=NORMAL
Step4. 通信テスト
まずVM2側からVM1に対して通信できないことを確認します。icmpやtcpやudpパケットを飛ばしてみます。
[root@centos6-2 ~]# ping 192.168.0.1
[root@centos6-2 ~]# telnet 192.168.0.1
[root@centos6-2 ~]# dig 192.168.0.1
カウンタを確認すると、以下のようにdropエントリにマッチしていることがわかります。
[root@sl67-r3 ~]# ovs-ofctl dump-flows br0
NXST_FLOW reply (xid=0x4):
cookie=0x0, duration=282.937s, table=0, n_packets=8, n_bytes=736, idle_age=9, priority=100,ip actions=ct(table=1)
cookie=0x0, duration=282.937s, table=0, n_packets=2, n_bytes=84, idle_age=13, priority=10,arp actions=NORMAL
cookie=0x0, duration=282.937s, table=0, n_packets=0, n_bytes=0, idle_age=282, priority=1 actions=drop
cookie=0x0, duration=282.937s, table=1, n_packets=0, n_bytes=0, idle_age=282, ct_state=+new,in_port=2 actions=ct(commit),NORMAL
cookie=0x0, duration=282.936s, table=1, n_packets=8, n_bytes=736, idle_age=9, ct_state=+new,in_port=3 actions=drop
cookie=0x0, duration=282.937s, table=1, n_packets=0, n_bytes=0, idle_age=282, ct_state=+est,in_port=2 actions=NORMAL
cookie=0x0, duration=282.936s, table=1, n_packets=0, n_bytes=0, idle_age=282, ct_state=+est,in_port=3 actions=NORMAL
続いて、VM1からVM2に対して通信を行い、正常に接続できることを確認します。
[root@centos6-1 ~]# ping 192.168.0.2
[root@centos6-1 ~]# telnet 192.168.0.2 22
[root@centos6-1 ~]# dig @192.168.0.2
カウンタを確認すると、以下のようにconnection trackingのエントリにマッチしていることがわかります。
[root@sl67-r3 ~]# ovs-ofctl dump-flows br0
NXST_FLOW reply (xid=0x4):
cookie=0x0, duration=221.654s, table=0, n_packets=40, n_bytes=3154, idle_age=63, priority=100,ip actions=ct(table=1)
cookie=0x0, duration=221.654s, table=0, n_packets=10, n_bytes=420, idle_age=63, priority=10,arp actions=NORMAL
cookie=0x0, duration=221.653s, table=0, n_packets=0, n_bytes=0, idle_age=221, priority=1 actions=drop
cookie=0x0, duration=221.653s, table=1, n_packets=14, n_bytes=1058, idle_age=63, ct_state=+new,in_port=2 actions=ct(commit),NORMAL
cookie=0x0, duration=221.653s, table=1, n_packets=0, n_bytes=0, idle_age=221, ct_state=+new,in_port=3 actions=drop
cookie=0x0, duration=221.653s, table=1, n_packets=8, n_bytes=629, idle_age=85, ct_state=+est,in_port=2 actions=NORMAL
cookie=0x0, duration=221.653s, table=1, n_packets=12, n_bytes=945, idle_age=85, ct_state=+est,in_port=3 actions=NORMAL
nf_conntrackのテーブルにも登録されています。
[root@sl67-r3 ~]# conntrack -L -s 192.168.0.1
udp 17 28 src=192.168.0.1 dst=192.168.0.2 sport=38118 dport=53 [UNREPLIED] src=192.168.0.2 dst=192.168.0.1 sport=53 dport=38118 mark=0 use=1
tcp 6 105 TIME_WAIT src=192.168.0.1 dst=192.168.0.2 sport=48265 dport=22 src=192.168.0.2 dst=192.168.0.1 sport=22 dport=48265 [ASSURED] mark=0 use=1
icmp 1 4 src=192.168.0.1 dst=192.168.0.2 type=8 code=0 id=52997 [UNREPLIED] src=192.168.0.2 dst=192.168.0.1 type=0 code=0 id=52997 mark=0 use=1
conntrack v0.9.13 (conntrack-tools): 3 flow entries have been shown.
無事に動いてますね!
設定の意味するところ
今回以下の設定を行いましたが、実はこれ、ovs-ofctlコマンドのマニュアルに載っているサンプルを簡素化したものです。
1 priority=100,ip,actions=ct(table=1)
2 priority=10,arp,actions=normal
3 priority=1,actions=drop
4
5 table=1,in_port=2,ct_state=+new,actions=ct(commit),normal
6 table=1,in_port=2,ct_state=+est,actions=normal
7 table=1,in_port=3,ct_state=+new,actions=drop
8 table=1,in_port=3,ct_state=+est,actions=normal
- 1行目: IPv4パケットをconntrackインテグレーション機能の処理に回します。実際、5行目以降のtable1のルールが評価されます。
- 2行目: 1行目にマッチしなかったもののうち、ARPパケットはそもそもconntrackできませんので、ここで無条件に許可しています。
- 3行目: その他のパケット(IPv6とか)は破棄します。
- 5行目: VM1が発した新規セッションをconntrackに登録し、パケット転送します。
- 6行目: VM1が発したconntrackに載っているセッションにマッチするパケットを許可します。
- 7行目: VM2が発した新規セッションは破棄します。
- 8行目: VM2が発したconntrackに載っているセッション(5行目で登録された)にマッチするパケットを許可します。
次回へ続く
今回は最も簡単な構成で、nf_conntrack連携を利用したステートフルファイアウォールを実装してみました。
次回は弊社クラウドサービスにおける、仮想スイッチのお客様サーバ収容構成を想定したポリシーの実装方法を検討してみます。