作者简介:Mr Huang,SDN/NFV研发工程师,技术擅长:SDN、NFV、Openstack
本文是基于Openstack Queens版本,且采用Linuxbridge充当虚拟交换机,描述iptables在Openstack安全组中的应用分析。涉及的实验都以Ubuntu16.04环境为准。
1 什么是Iptables
本文不会对iptables相关知识做过多的描述,对于不了解iptables的读者,推荐阅读网上的一份连载文章,里面详细描述了iptables的基础知识及使用。链接请参见:http://www.zsythink.net/archives/tag/iptables/
2 Openstack安全组
2.1 什么是安全组
在Openstack中,安全组是作用在neutron port上的一组策略,这些策略我们其实可以理解为一些防火墙规则的集合。可用于过滤进出neutron port的数据报文。
2.2 安全组规则
一个安全组中可以包含多个安全组规则,其中一条规则中包含的重要字段有如下:
- Direction
安全组是区分ingress和egress两个方向的。因此定义规则的时候需要明确指定应用的方向。 - Ethertype
以太网类型,主要有:IPv4和IPv6两种。 - Protocol
IP协议。可以用字符串来表达,也可以用整数值来表达。用整数值来表达时,范围为0~255。对于协议字符串及其整数值可以通过链接:http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml查询到。 - Port Range
如果协议为TCP、UDP、DCCP、SCTP或UDP-Lite的话,则这个字段代表的是传输层协议端口范围。如果协议为ICMP,则这个字段代表的是ICMP协议报文中的type字段。 - Remote IP Prefix
指的是远端IP前缀地址。对于ingress方向,代表的是源IP前缀地址;对于egress方向,代表的是目的IP前缀地址。 - Remote group ID
Remote group ID对应安全组所关联的所有端口的IP地址。这些IP地址是离散的。 - openvswitch + iptables + connection track
- openvswitch + openflow + connection track
- linuxbridge + iptables + connection track
在Openstack中,对用户暴露的安全组规则添加接口,所有添加的规则都是ALLOW动作的,不会有DENY动作。即:用户只能添加白名单的规则而不允许添加黑名单的规则。
2.3 安全组的实现
Openstack中的安全组的实现有如下几个:
由于本文阐述的是linuxbridge的使用场景,因此不会对前面两种的实现方式进行阐述。
采用linuxbridge + iptables + connection track的实现方式,主要涉及iptables表为filter。而connection track主要用于跟踪数据报文的状态信息(因为安全组是有状态的防火墙),该技术不是本文的重点,所以不会进行相关的阐述,有兴趣的读者可以参考链接:http://conntrack-tools.netfilter.org/manual.html。
根据前面内容可知,安全组是作用在neutron port。本文主要分析虚拟机关联的安全组,因此这里只阐述虚拟机关联安全组后会产生哪些iptables规则。分为ingress和egress方向,在iptables中会产生两条链,即:neutron-linuxbri-oxxx和neutron-linuxbri-ixxx。其中字母’o’表示的是egress方向,’i’表示的是ingress方向,xxx则对应虚拟机所生成的neutron port的uuid的前10个字符,例如:neutron-linuxbri-offe6e45b-d和neutron-linuxbri-iffe6e45b-d。通过这种方式,进出虚拟机的报文都会去匹配这两条链上的规则,进而放行报文或丢弃报文。
2.4 默认安全组
在Openstack中,创建租户时会默认创建一个默认安全组,这个默认的安全组名字为default。
为了掌握默认安全组包含哪些默认的规则,我们这里提前进行实验分析。在我们的Openstack环境中,可以通过如下几个命令来创建租户及其租户用户:
1 2 3 |
openstack project create --domain default --description "Test Project" test openstack user create --domain default --password-prompt test openstack role add --project test --user test admin |
如上面这几条命令创建了一个test租户,并创建了test用户。我们登陆Openstack的dashboard查看test租户下的默认安全组包含了哪些规则,如下图所示:
从上图中可以看到默认安全组包含了4条规则,两条ingress方向,两条egress方向。从图中所示的规则来看,默认安全组包含的这4条规则意义如下:
- egress方向
允许IPv4或IPv6报文,任何协议,任何端口,任何远端IP的报文通过。 - ingress方向
允许IPv4或IPv6报文,任何协议,任何端口,任何来自同一个安全组关联的端口IP的报文通过。
但是这个只是用dashboard的视图看到的规则。实际上默认安全组包含的默认规则不止上述这些。为了探究默认安全组包含的所有规则信息,我们可以事先启动一个虚拟机示例(默认关联这个默认安全组),然后通过iptables命令查看。
下图给出的是虚拟机关联的neutron port信息:(红色标注部分)
根据2.3节的阐述,该虚拟机关联默认安全组后,会创建两条iptables链,即:neutron-linuxbri-offe6e45b-d和neutron-linuxbri-iffe6e45b-d。我们可以通过执行iptables -t filter -nvL来查看这两条链的具体信息,如下所示:
- egress方向
我们来分析上图所示的每一条规则的意义:
第一条:允许虚拟机发出的DHCP Client报文(广播)。
第二条:匹配所有的报文,然后会跳转到另外一条iptables链上继续匹配。这条链上的规则信息如下图所示。从图中的规则可以看出,从虚拟机发出来的报文需要严格匹配IP+MAC,即:MAC spoof prevention。因此,如果人为在虚拟机里面将网卡的IP地址修改为其他或修改网卡的MAC地址,将被安全组过滤掉发出的任何报文。
第三条:和第一条规则类似,也是允许虚拟机发出的DHCP Client报文。不同的是这条规则匹配的目的IP地址为0.0.0.0/0,这是因为有些DHCP Client报文是以单播的形式发出去的。因此这条规则是用来匹配单播的DHCP Client报文。
第四条:丢弃虚拟机发出的DHCP Server报文,即虚拟机不能充当DHCP Server。
第五条:允许状态为RELATED或ESTABLISHED的报文。
第六条:允许所有发出的报文(这条规则就是我们上面在dashboard看到的)
第七条:丢弃状态为INVALID的报文。
第八条:匹配所有的报文,然后跳转到另外一条链上,这条链上的规则信息如下图所示。从图中所示的规则可以看出,egress方向的最后一条iptables规则为丢弃所有发出的报文。
- ingress方向
我们来分析上图所示的每一条规则的意义:
第一条:允许状态为RELATED或ESTABLISHED的报文进入虚拟机。
第二条:允许DHCP Server发来的报文(单播)进入虚拟机。
第三条:允许DHCP Server发来的报文(广播)进入虚拟机。
第四条:允许关联了同一个安全组的其他虚拟机发来的报文进入虚拟机(这条规则就是我们上面在dashboard看到的)。
第五条:丢弃状态为INVALID的报文。
第六条:匹配所有的报文,然后跳转到另外一条链上,这条链上的规则信息如下图所示。从图中所示的规则可以看出,ingress方向的最后一条iptables规则为丢弃所有进入的报文。
2.5 实验分析
这节我们主要通过几个实验来进一步分析安全组。涉及如下几个实验:
- 虚拟机关联默认安全组,分别从dhcp namespace和另外一个虚拟机ping目标虚拟机。
首先启动两个虚拟机,如下图所示:
两个虚拟机都属于同一个子网。现在从dhcp namespace去ping testvm1,看看是否能ping通,结果如下图所示,无法ping通。
现在再从testvm2去ping testvm1看看是否能ping通,结果如下图所示,可以ping通。
结果分析:按照前面内容的描述,testvm1和testvm2都关联了同一个默认安全组,因此从规则上二者是可以相互访问的。但是从dhcp neutron port是没有关联任何安全组的,因此是无法访问testvm1的。
为了从dhcp namespace里能够ping通testvm1,我们可以在默认安全组上添加相应的规则。如下图所示,添加了ingress方向上允许ICMP的报文。
再查看下后台的iptables规则有哪些变化,如下图所示,红色框住的规则就是手工添加的。
现在再来看看从dhcp namespace里是否可以ping通testvm1,结果如下图所示(是可以ping通的):
同理,如果想从外部ssh到testvm1,同样需要手工添加允许TCP的规则,这里就不再赘述了。
- 虚拟机不关联任何安全组
将testvm1的虚拟机关联的安全组取消掉,再观察下后台的iptables规则会有哪些变化:
egress方向
变化后:
变化前:
对比前后的iptables规则,发现虚拟机取消关联安全组后,只剩下了隐藏的规则,在dashboard上能看到的所有规则都去掉了。这个时候从虚拟机再发送报文(非DHCP报文)都会被丢弃。
ingress方向
变化后:
变化前:
同样,只剩下了隐藏的规则,在dashboard上能看到的所有规则都去掉了。这个时候进入虚拟机的报文(非DHCP报文)都会被丢弃。
- 虚拟机禁用安全组
这种情况和上一种情况不同。上一种情况只是把虚拟机关联的安全组取消掉,但是虚拟机对应的neutron port依然是允许安全组的。我们可以通过查看虚拟机对应的neutron port的详细信息得知,如下图所示:
现在我们将完全禁用掉虚拟机使用安全组。可以通过修改虚拟机的neutron port属性来达到此目的,命令如下:
1 |
neutron port-update <port uuid> --port-security-enabled false |
设置后,再次查看neutron port的信息,如下图所示:
从上图看已经禁用掉了安全组。再观察后台的iptables规则的变化情况,已经完全看不到neutron-linuxbri-offe6e45b-d和neutron-linuxbri-iffe6e45b-d这两条链了。这个时候我们再次从dhcp namespace和testvm2去ping testvm1看看结果(先将之前添加的允许ICMP规则去掉),如下图所示:
从上面两个图可知,禁用掉虚拟机的安全组后,进出该虚拟机的报文将不再被限制了。
3 结论
本文从原理分析再到实验验证详细地阐述了Openstack中采用linuxbridge + iptables + connection track方式实现的安全组,对希望入门Openstack安全组提供了较好的帮助。