ACL & 安全组
同大部分使用OVS实现安全组功能的方案一样,OVN通过流表实现进出VM流量的有状态的ACL控制。状态还是通过linux conntrack维护,OVS 2.5版本起开始支持conntrack,在此之间需要通过Linux Bridge来使用ct,不可避免的对性能照成一定的影响。
OVS并为独立实现ct,实际上还是Linux内核的ct模块,我们通过conntrack命令可以看到他们是一个东西。我们知道在实现NAT、有状态防火墙这些功能的时候ct是一个重要的内核功能,能够一定程度上提高性能(降低 CPU 和延迟),这是因为只有第一个数据包需要完成整个网络栈的处理,参见 Comparing kube-proxy modes 一文,其中包含了这方面的例子。
但是如果需要同时处理非常大数量的活动连接,或者每秒处理极大数量的连接,ct就会成为瓶颈,ct表项的操作需要加自旋锁,应对这些情况对资源和性能消耗都会很大。如下,每秒处理大数量的连接时,内核在ct上的性能消耗。
6.53% [kernel] [k] _raw_qspin_lock
5.57% [kernel] [k] __nf_conntrack_find_get
5.01% [kernel] [k] copy_user_enhanced_fast_string
4.29% [kernel] [k] ebt_do_table
3.66% [kernel] [k] vhost_get_vq_desc
3.39% [kernel] [k] vhost_signal
所有如果能够预期会出现这些情况的话,可以考虑一下无状态的防火墙,当然无状态的防火墙的使用限制还是挺大的。详细可以参考Calico Do-not-track 策略。
配置
相关命令行
1、配置acl
// 命令行
ovn-nbctl acl-add entity direction priority match verdict
说明:
priority
指定acl规则的优先级,值越大优先级越高。如果匹配到的多条规则优先级相同,最终哪条规则生效是不确定的。
direction
指定报文的方向,只有两个值: from-lport和to-lport。前者表示入方向,后者表示出方向,这是在逻辑交换机的角度来说的,不是vm。
match
用来指定报文匹配域,具体的表达式规则可参考sbdb中 logical_flow table的match列。注意:类型为localnet和router的端口上不能应用acl规则。
action
对于匹配到规则的报文的处理,目前支持四个值:allow, allow-related, drop, or reject。
allow: 表示允许报文通过;
allow-related:表示允许报文和其响应报文通过;
drop:静默丢弃报文;
reject:丢弃报文,并回复报文。对于tcp协议报文,回复rst,对于其他类型的报文,回复ICMPv4/ICMPv6 unreachable。
2、配置地址集
// 创建ip地址集合
ovn-nbctl create Address_Set name=ipset addresses='10.10.20.2 10.10.10.3'
// 创建mac地址集合
ovn-nbctl create Address_Set name=macset addresses='"02:00:00:00:00:01","02:00:00:00:00:02"'
3、显示
ovn-nbctl list acl ## 显示acl rule
ovn-nbctl list Address_Set ## 显示地址集合
配置安全组
配置一个白名单 安全组,控制 vpc-400中 vm2 的入向规则。
踩坑:
- 注意配置地址集时,不能使用"-",使用错误不提示,控制层面数据生成都正确,但实际流表不下发。
- --name 并不是给acl 命名,而是打log用的,和log功能绑定。
### 默认 drop
ovn-nbctl --name=vm-400-2-in-default acl-add sw-400 to-lport 0 'outport == "sw-400-port-vm2" && ip' drop
### 配置 允许30.1.1.12访问 4444端口
ovn-nbctl --name=vm-400-2-in-permit4444 acl-add sw-400 to-lport 1000 'outport == "sw-400-port-vm2" && ip4.src == 30.1.1.12 && tcp.dst == 4444' allow-related
### 创建ip地址集合
ovn-nbctl create Address_Set name=vm_300_ipset addresses='30.1.1.111 30.1.1.112'
### 使用地址集,允许地址集中的vm访问5555端口
ovn-nbctl acl-add sw-400 to-lport 1000 'outport == "sw-400-port-vm2" && ip4.src == $vm_300_ipset && tcp.dst == 5555' allow-related
流表分析
附ct状态:
new 通过ct action指定报文经过conntrack模块处理,不一定有commit。
est 表示conntrack模块看到了报文双向数据流,一定是在commit 的conntrack后
rel 表示和已经存在的conntrack相关,比如icmp不可达消息或者ftp的数据流
rpl 表示反方向的报文
inv 无效的,表示conntrack模块没有正确识别到报文,比如L3/L4 protocol handler没有加载,或者L3/L4 protocol handler认为报文错误
trk 表示报文经过了conntrack模块处理,如果这个flag不设置,其他flag都不能被设置。任何进来的数据包,都是-trk状态,只有该数据包经过ct模块处理了,才会变为+trk状态。什么叫经过ct模块处理?流表的action指定了ct,并且报文通过了协议验证:pkt->md.ct_state = CS_TRACKED
snat 表示报文经过了snat,源ip或者port
dnat 表示报文经过了dnat,目的ip或者port
#### 1、ingress 方向安全组
## tcp rst 和 icmp type3 都是 acl的reject verdict 生成的报文,我们只配置了drop,所以没有实际的流量匹配这些流表
cookie=0x568f4201, duration=4690.495s, table=11, n_packets=0, n_bytes=0, priority=110,tcp,metadata=0x6,tcp_flags=rst actions=resubmit(,12)
cookie=0x568f4201, duration=4690.496s, table=11, n_packets=0, n_bytes=0, priority=110,icmp,metadata=0x6,icmp_type=3 actions=resubmit(,12)
cookie=0xf811791a, duration=4690.496s, table=11, n_packets=0, n_bytes=0, priority=110,ip,reg14=0x3,metadata=0x6 actions=resubmit(,12)
cookie=0x1c982666, duration=4690.496s, table=11, n_packets=9, n_bytes=706, priority=100,ip,metadata=0x6 actions=load:0x1->NXM_NX_XXREG0[96],resubmit(,12)
cookie=0x7ff1837, duration=4690.496s, table=14, n_packets=0, n_bytes=0, priority=65535,ct_state=-new-est+rel-inv+trk,ct_label=0/0x1,metadata=0x6 actions=resubmit(,15)
## 已双向跟踪 && 反向流量 && 打了blocked flag == drop
cookie=0xda49a9a8, duration=4690.496s, table=14, n_packets=0, n_bytes=0, priority=65535,ct_state=+est+rpl+trk,ct_label=0x1/0x1,metadata=0x6 actions=drop
## 无效报文 == drop
cookie=0xda49a9a8, duration=4690.496s, table=14, n_packets=0, n_bytes=0, priority=65535,ct_state=+inv+trk,metadata=0x6 actions=drop
## "ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0"
cookie=0x546d5489, duration=4690.496s, table=14, n_packets=9, n_bytes=706, priority=65535,ct_state=-new+est-rel+rpl-inv+trk,ct_label=0/0x1,metadata=0x6 actions=resubmit(,15)
## "ip && (!ct.est || (ct.est && ct_label.blocked == 1))" == 标记 reg0 = 1
cookie=0x1349518f, duration=4690.496s, table=14, n_packets=0, n_bytes=0, priority=1,ct_state=-est+trk,ip,metadata=0x6 actions=load:0x1->NXM_NX_XXREG0[97],resubmit(,15)
cookie=0x1349518f, duration=4690.496s, table=14, n_packets=0, n_bytes=0, priority=1,ct_state=+est+trk,ct_label=0x1/0x1,ip,metadata=0x6 actions=load:0x1->NXM_NX_XXREG0[97],resubmit(,15)
#### 2、egress 方向安全组
cookie=0x58a88198, duration=4690.496s, table=41, n_packets=0, n_bytes=0, priority=110,icmp,metadata=0x6,icmp_type=3 actions=resubmit(,42)
cookie=0x58a88198, duration=4690.496s, table=41, n_packets=0, n_bytes=0, priority=110,tcp,metadata=0x6,tcp_flags=rst actions=resubmit(,42)
cookie=0xe70e698d, duration=4690.496s, table=41, n_packets=9, n_bytes=706, priority=110,ip,reg15=0x3,metadata=0x6 actions=resubmit(,42)
cookie=0x8a28c202, duration=4690.496s, table=41, n_packets=37, n_bytes=2755, priority=100,ip,metadata=0x6 actions=load:0x1->NXM_NX_XXREG0[96],resubmit(,42)
#### 3、以下resubmit(,45)都是白名单放行的各种情况,其他都会进入 [4] 代表的 default action流表中 执行drop
## eg, 30.1.1.12 --> 40.1.1.12:4444,会先后走到这里的 91ef48b0(正方向 new),6169800e(正方向 est),a2bddbb0(反方向)放行。
## 流表中所有的控制器操作都是由于我配置了 --name,触发的 log处理,会触发上送控制器打日志。
##
cookie=0xa2bddbb0, duration=4690.496s, table=44, n_packets=9, n_bytes=706, priority=65535,ct_state=-new+est-rel+rpl-inv+trk,ct_label=0/0x1,metadata=0x6 actions=resubmit(,45)
cookie=0x628a564d, duration=4690.496s, table=44, n_packets=0, n_bytes=0, priority=65535,ct_state=+est+rpl+trk,ct_label=0x1/0x1,metadata=0x6 actions=drop
cookie=0xcc4f7527, duration=4690.496s, table=44, n_packets=0, n_bytes=0, priority=65535,ct_state=-new-est+rel-inv+trk,ct_label=0/0x1,metadata=0x6 actions=resubmit(,45)
cookie=0x628a564d, duration=4690.495s, table=44, n_packets=0, n_bytes=0, priority=65535,ct_state=+inv+trk,metadata=0x6 actions=drop
cookie=0x91ef48b0, duration=4690.496s, table=44, n_packets=0, n_bytes=0, priority=2000,ct_state=-new+est-rpl+trk,ct_label=0x1/0x1,tcp,reg15=0x2,metadata=0x6,nw_src=30.1.1.12,tp_dst=4444 actions=load:0x1->NXM_NX_XXREG0[97],controller(userdata=00.00.00.07.00.00.00.00.00.06.76.6d.2d.34.30.30.2d.32.2d.69.6e.2d.70.65.72.6d.69.74.34.34.34.34),resubmit(,45)
##
cookie=0x6169800e, duration=4690.496s, table=44, n_packets=8, n_bytes=537, priority=2000,ct_state=-new+est-rpl+trk,ct_label=0/0x1,tcp,reg15=0x2,metadata=0x6,nw_src=30.1.1.12,tp_dst=4444 actions=controller(userdata=00.00.00.07.00.00.00.00.00.06.76.6d.2d.34.30.30.2d.32.2d.69.6e.2d.70.65.72.6d.69.74.34.34.34.34),resubmit(,45)
cookie=0x4f257b76, duration=30.827s, table=44, n_packets=0, n_bytes=0, priority=2000,ct_state=-new+est-rpl+trk,ct_label=0x1/0x1,tcp,reg15=0x2,metadata=0x6,nw_src=30.1.1.111,tp_dst=5555 actions=load:0x1->NXM_NX_XXREG0[97],resubmit(,45)
cookie=0x32d72a94, duration=30.827s, table=44, n_packets=0, n_bytes=0, priority=2000,ct_state=-new+est-rpl+trk,ct_label=0/0x1,tcp,reg15=0x2,metadata=0x6,nw_src=30.1.1.111,tp_dst=5555 actions=resubmit(,45)
cookie=0x4f257b76, duration=30.827s, table=44, n_packets=0, n_bytes=0, priority=2000,ct_state=-new+est-rpl+trk,ct_label=0x1/0x1,tcp,reg15=0x2,metadata=0x6,nw_src=30.1.1.112,tp_dst=5555 actions=load:0x1->NXM_NX_XXREG0[97],resubmit(,45)
cookie=0x32d72a94, duration=30.827s, table=44, n_packets=0, n_bytes=0, priority=2000,ct_state=-new+est-rpl+trk,ct_label=0/0x1,tcp,reg15=0x2,metadata=0x6,nw_src=30.1.1.112,tp_dst=5555 actions=resubmit(,45)
cookie=0x91ef48b0, duration=4690.496s, table=44, n_packets=2, n_bytes=148, priority=2000,ct_state=+new-est+trk,tcp,reg15=0x2,metadata=0x6,nw_src=30.1.1.12,tp_dst=4444 actions=load:0x1->NXM_NX_XXREG0[97],controller(userdata=00.00.00.07.00.00.00.00.00.06.76.6d.2d.34.30.30.2d.32.2d.69.6e.2d.70.65.72.6d.69.74.34.34.34.34),resubmit(,45)
cookie=0x4f257b76, duration=30.827s, table=44, n_packets=0, n_bytes=0, priority=2000,ct_state=+new-est+trk,tcp,reg15=0x2,metadata=0x6,nw_src=30.1.1.111,tp_dst=5555 actions=load:0x1->NXM_NX_XXREG0[97],resubmit(,45)
cookie=0x4f257b76, duration=30.827s, table=44, n_packets=0, n_bytes=0, priority=2000,ct_state=+new-est+trk,tcp,reg15=0x2,metadata=0x6,nw_src=30.1.1.112,tp_dst=5555 actions=load:0x1->NXM_NX_XXREG0[97],resubmit(,45)
#### 4、默认acl,执行: 提交ct 表项;打日志;默认行为(drop);设置ct_label=1
### 另外 先建ct,再删除 permit的rule表项的情况下,也走到这里,drop并设置流表的ct_label
cookie=0x6a697aa1, duration=4690.496s, table=44, n_packets=0, n_bytes=0, priority=1000,ct_state=+est+trk,ct_label=0/0x1,ip,reg15=0x2,metadata=0x6 actions=ct(commit,zone=NXM_NX_REG13[0..15],exec(load:0x1->NXM_NX_CT_LABEL[0])),controller(userdata=00.00.00.07.00.00.00.00.01.06.76.6d.2d.34.30.30.2d.32.2d.69.6e.2d.64.65.66.61.75.6c.74)
### 到了这里,还没有ct.est 或 匹配有drop 标记的报文,打日志 + drop(没有resubmit)
### 先建ct,再配置rule,会打 ct_label,走到这里。
cookie=0xd4099538, duration=4690.496s, table=44, n_packets=0, n_bytes=0, priority=1000,ct_state=+est+trk,ct_label=0x1/0x1,ip,reg15=0x2,metadata=0x6 actions=controller(userdata=00.00.00.07.00.00.00.00.01.06.76.6d.2d.34.30.30.2d.32.2d.69.6e.2d.64.65.66.61.75.6c.74)
### 先配置 rule,再有流量的情况下会走到这里,-est+trk,drop
cookie=0xd4099538, duration=4690.496s, table=44, n_packets=24, n_bytes=1776, priority=1000,ct_state=-est+trk,ip,reg15=0x2,metadata=0x6 actions=controller(userdata=00.00.00.07.00.00.00.00.01.06.76.6d.2d.34.30.30.2d.32.2d.69.6e.2d.64.65.66.61.75.6c.74)
####
cookie=0xf90599e3, duration=4690.496s, table=44, n_packets=0, n_bytes=0, priority=1,ct_state=-est+trk,ip,metadata=0x6 actions=load:0x1->NXM_NX_XXREG0[97],resubmit(,45)
cookie=0xf90599e3, duration=4690.495s, table=44, n_packets=0, n_bytes=0, priority=1,ct_state=+est+trk,ct_label=0x1/0x1,ip,metadata=0x6 actions=load:0x1->NXM_NX_XXREG0[97],resubmit(,45)