前言
我们在内网使用k8s时,有时候需要针对整个集群的节点设置防火墙,阻止一些外部访问,或者是仅允许白名单内的ip访问,传统做法是使用firewall之类的防火墙软件,但是,使用firewall存在如下问题:
- firewall针对k8s的nodeport端口设置的防火墙规则不生效
- 集群内节点较多时,挨个主机设置防火墙会比较繁琐。
如果集群的节点是托管到云平台上的,可以忽略本文章,直接去云平台设置防火墙策略。
如果我们的k8s插件是calico,可以通过calico的扩展功能来设置整个集群所有节点的防火墙,不会有上面两个问题的困扰。
calico的网络策略
calico网络策略的官方文档是: https://docs.tigera.io/calico/latest/network-policy/get-started/calico-policy/calico-network-policy
想要在安装了calico网络插件的k8s集群里面配置节点防火墙,首先我们需要将节点注册到calico上,在calico这个叫做 Host endpoint
, 一个Host endpoint
指的是节点对外的出口,一般是一块网卡,网卡上带有ip地址,我们需要通过声明HostEndpoint
来注册。
在声明HostEndpoint时,还可以指定该节点的标签,后期在进行防火墙配置时,可以通过标签来批量配置。
当声明HostEndpoint后,节点的网络策略将由Calico接管,默认的规则是拒绝所有连接。Calico为了防止整个节点的网络瘫痪,默认开放了一些端口,比如22等,后面会详细说明。
声明HostEndpoint
如前所述,我们首先需要声明一个HostEndpoint,下面是声明的Yaml:
apiVersion: projectcalico.org/v3
kind: HostEndpoint
metadata:
name: node1-eth0
labels:
kubernetes-host: ingress
spec:
interfaceName: eth0
node: node1
expectedIPs:
- INSERT_IP_HERE
这个是全局配置,不需要namespace。
metadata.name
是HostEndpoint的名字,一般是节点名-网卡
spec.interfaceName
是节点的网卡名,可以通过 ip addr
或者 ifconfig
等命令查看。
spec.node
是该节点在k8s中的name,可以通过 kubectl get node
来查看
spec.expectedIPs
是该网卡的ip,这个是必填项。
下面是一个配置好的样例:
apiVersion: projectcalico.org/v3
kind: HostEndpoint
metadata:
name: localhost.localdomain-enp0s8
labels:
kubernetes-host: ingress
spec:
interfaceName: enp0s8
node: localhost.localdomain
expectedIPs:
- 192.168.88.5
将上述内容保存到hostendpoint.yaml
中执行 kubectl apply -f hostendpoint.yaml
创建:
[root@localhost calico]# kubectl apply -f hostendpoint.yaml
hostendpoint.projectcalico.org/localhost.localdomain-enp0s8 created
配置默认开放的端口
接入calico的HostEndpoint
默认开放了一些端口,官方清单如下:
https://docs.tigera.io/calico/latest/reference/host-endpoints/failsafe
下面是摘抄:
如果想要关闭这里面的部分端口,或者默认在所有节点上开放其他端口,可以通过配置 FelixConfiguration
来完成,官方文档地址为: https://docs.tigera.io/calico/latest/reference/resources/felixconfig 。
如果想要修改,可以通过kubectl edit FelixConfiguration default
来修改配置,下面是一个样例,默认开放的端口仅保留了22,其他全部删掉了(实际操作过程不要这么做!这里只是为了方便演示,仅仅保留一个)。
apiVersion: projectcalico.org/v3
kind: FelixConfiguration
metadata:
name: default
spec:
bpfLogLevel: ""
floatingIPs: Disabled
healthPort: 9099
logSeverityScreen: Info
reportingInterval: 0s
failsafeInboundHostPorts:
- port: 22
protocol: tcp
开放ip白名单,其他ip默认禁止访问
设置好默认开放的端口后,下一步一般是拒绝其他的ip,仅保留指定的ip可以访问,下面是一个样例:
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
name: allow-cluster-internal-ingress-only
spec:
# 生效顺序从小到大排序,后面再增加开放端口的策略时,order < 20, 即可在这之前生效
order: 20
preDNAT: true
applyOnForward: true
ingress:
# 首先接受白名单的所有请求
- action: Allow
source:
# source 配置方法可以参考 https://docs.tigera.io/calico/latest/reference/resources/networkpolicy#entityrule
nets:
- 192.168.88.0/24
# 然后拒绝白名单ip以外的所有请求
- action: Deny
source:
# Deny规则要加上排除白名单的网段,理论上不需要这个,但是遇到过奇怪的BUG,没加上导致把上面开放的ip都Drop掉了
notNets:
- 192.168.88.0/24
selector: has(kubernetes-host) # 选择器。选择了包含kubernetes-host标签的所有HostEndpoint
开放指定端口
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
name: allow-external-port-ingress
spec:
order: 10
preDNAT: true
applyOnForward: true
ingress:
# 放通目标是指定端口的所有请求 当然也可以增加source字段指定来源ip/ip段
- action: Allow
destination:
# 配置方法可以参考 https://docs.tigera.io/calico/latest/reference/resources/networkpolicy#entityrule
ports:
- 3306
- 30030
selector: has(kubernetes-host) # 选择器。选择了包含kubernetes-host标签的所有HostEndpoint
注意这里的selector可以给某一两个节点打上特殊标签,选择到指定的一两个节点,给他们开放端口。
更多细节请查阅官方文档,这里仅给出了少量用法,官方支持的功能还是很多的。
修改或查看已有的网络策略/HostEndpoint
查看已有的网络策略:
kubectl get GlobalNetworkPolicy
kubectl describe GlobalNetworkPolicy xxx
修改已有的网络策略
kubectl edit GlobalNetworkPolicy xxx
删除网络策略
kubectl delete GlobalNetworkPolicy xx
HostEndpoint的操作也是一样的,只是把GlobalNetworkPolicy
改成HostEndpoint
就可以了