本方法适用于 CentOS 7.9 或者 Iptables 不是以 nftable 作为后端的情况。
如果操作系统使用 nftable 管理流量,请期待下一篇文章。
在上文中提到了,在不做任何保护的情况下,K8S 节点同子网的服务器只需将路由配置为任一 K8S 节点,就可以访问到 Pod。
本文讲解如何使用 iptables 来保护 K8S 节点,只允许转发来自同集群的其他节点的 IP 包,来保护 Pod 不被同子网的其他服务器攻击。需要一些 iptables 的基础知识。
步骤
假设,我们的集群有 3 个节点,IP 是 172.18.10.1~3,我们先创建一个 ipset,名字叫做 cluster_nodes
,把这 3 个 IP 放进去:
1
2
3
4
|
sudo ipset create cluster_nodes iphash
sudo ipset add cluster_nodes 172.18.10.1
sudo ipset add cluster_nodes 172.18.10.2
sudo ipset add cluster_nodes 172.18.10.3
|
根据 iptables 的定义,IP 转发流量(非 NAT 和 Masquerading)对应的 Chain 是 FORWARD
。
因此我们要在 filter
Table 的 FORWARD
Chain 上添加规则,阻止来自于非 cluster_nodes
的 IP 转发流量,
因为我们的节点上已经安装了 K8S,所以 Calico 已经给 FORWARD
Chain 添加了一系列规则:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
> sudo iptables -t filter -L FORWARD -n --line-numbers
Chain FORWARD (policy DROP)
num target prot opt source destination
1 cali-FORWARD all -- 0.0.0.0/0 0.0.0.0/0 /* cali:wUHhoiAYhphO9Mso */
2 KUBE-FORWARD all -- 0.0.0.0/0 0.0.0.0/0 /* kubernetes forwarding rules */
3 KUBE-SERVICES all -- 0.0.0.0/0 0.0.0.0/0 ctstate NEW /* kubernetes service portals */
4 KUBE-EXTERNAL-SERVICES all -- 0.0.0.0/0 0.0.0.0/0 ctstate NEW /* kubernetes externally-visible service portals */
5 DOCKER-USER all -- 0.0.0.0/0 0.0.0.0/0
6 DOCKER-ISOLATION-STAGE-1 all -- 0.0.0.0/0 0.0.0.0/0
7 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
8 DOCKER all -- 0.0.0.0/0 0.0.0.0/0
9 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
10 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
11 ACCEPT all -- 10.42.0.0/16 0.0.0.0/0
12 ACCEPT all -- 0.0.0.0/0 10.42.0.0/16
13 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 /* cali:S93hcgKJrXEqnTfs */ /* Policy explicitly accepted packet. */ mark match 0x10000/0x10000
|
要记住 iptables 规则是按顺序执行的,因此新规则添加在哪里非常重要。
同时注意到 FORWARD Chain 的默认策略是 DROP,而最后一条规则又等于全部允许。
因此决定插入在 11
之后 12
这个之前是一个比较好的选择:
1
|
sudo iptables -t filter -I FORWARD 12 -i ens18 -m set ! --match-set cluster_nodes src -m comment --comment "路由转发保护" -j REJECT
|
这条命令的意思是,把一条规则插入在 12
之前,而这个规则的意思是:凡是来自于网卡 ens18
的 IP 转发包,如果其来源 IP 不在 ipset cluster_nodes
范围内,那么就拒绝。
12 这个插入点,也需要根据实际情况斟酌判断。
ens18
需要根据你的实际情况修改,因为你的网卡不一定是这个可以通过 ip link
来得到
检查一下规则是否插入成功:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
> sudo iptables -t filter -L FORWARD -n --line-numbers
Chain FORWARD (policy DROP)
num target prot opt source destination
1 cali-FORWARD all -- 0.0.0.0/0 0.0.0.0/0 /* cali:wUHhoiAYhphO9Mso */
2 KUBE-FORWARD all -- 0.0.0.0/0 0.0.0.0/0 /* kubernetes forwarding rules */
3 KUBE-SERVICES all -- 0.0.0.0/0 0.0.0.0/0 ctstate NEW /* kubernetes service portals */
4 KUBE-EXTERNAL-SERVICES all -- 0.0.0.0/0 0.0.0.0/0 ctstate NEW /* kubernetes externally-visible service portals */
5 DOCKER-USER all -- 0.0.0.0/0 0.0.0.0/0
6 DOCKER-ISOLATION-STAGE-1 all -- 0.0.0.0/0 0.0.0.0/0
7 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
8 DOCKER all -- 0.0.0.0/0 0.0.0.0/0
9 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
10 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
11 ACCEPT all -- 10.42.0.0/16 0.0.0.0/0
12 REJECT all -- 0.0.0.0/0 0.0.0.0/0 ! match-set cluster_nodes src reject-with icmp-port-unreachable
13 ACCEPT all -- 0.0.0.0/0 10.42.0.0/16
14 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 /* cali:S93hcgKJrXEqnTfs */ /* Policy explicitly accepted packet. */ mark match 0x10000/0x10000
|
以上操作在所有节点上都执行一遍。
然后观察你的集群是否正常工作。
观察效果
你可以按照上文提到的方式,看看还能不能 ping 通 POD,并且可以通过以下命令看到规则拦截的包的数量:
1
2
3
4
5
6
|
> sudo iptables -t filter -L FORWARD -nv --line-numbers
Chain FORWARD (policy DROP 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
...
12 1 60 REJECT all -- ens18 * 0.0.0.0/0 0.0.0.0/0 ! match-set cluster_nodes src reject-with icmp-port-unreachable
...
|
你可以我们的规则拦截了 1 个包,60 个字节。
节点增加/删除
给 ipset cluster_nodes
增加 IP:
1
|
sudo ipset add cluster_nodes <ip>
|
删除 IP:
1
|
sudo ipset del cluster_nodes <ip>
|
查看 IP:
1
|
sudo ipset list cluster_nodes
|
删除规则
如果集群工作异常,那么用下面命令删除这条规则:
1
|
sudo iptables -t filter -D FORWARD -i ens18 -m set ! --match-set cluster_nodes src -m comment --comment "路由转发保护" -j REJECT
|
注意:删除的规则时,规则定义必须和你增加规则时的定义完全一样,否则会出现下面这种结果:
1
|
iptables: No chain/target/match by that name.
|
参考资料
评论