用k8s的networkpolicy模拟租户隔离、组间pod隔离
pod之间的通信默认是不隔离的,他们之是能相互通信的,但如果你想通过IP地址或者端口来管理网络通信,那么就可以使用k8s的networkpolicy功能。该功能的实现原理是默认都不通过,显示添加白名单。如果指定namespace,那么该network policy生效的范围是本namespace内。如果没有指定namespace,那么就是针对default namespace才能生效。另外network policy还会选择相应的pod来设置规则。下面通过两个例子来讲解network policy的使用方法。
模拟租户隔离
以下是一个模拟租户隔离的networkpolicy YAML文件,名称为user1.yaml.它对namespace为user1的有标签“appType=user1App”的Pod生效,只允许有“user=user1”的流入流量,对流出的流量不隔离。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: smlTenant
namespace: user1
spec:
podSelector:
matchLabels:
appType: user1App
ingress:
- from:
- podSelector:
matchLabels:
user: user1
egress:
- {}
policyTypes:
- Ingress
- Egress
必备字段:像其他Kubernetes配置一样,一个NetworkPolicy必备的字段有apiVersion, kind, and metadata.
- spec:NetworkPolicy spec 拥有在给定名称空间中定义特定网络策略所需的所有信息。
- namespace:注意这里的networkpolicy只对本域名内的资源生效。
- podSelector:每个NetworkPolicy都包含一个podSelector,它选择策略应用到的pods分组。示例策略选择标签为“appType: user1App”的pods也就是说这个NetworkPolicy应用到标签为appType=user1App的pod中,NetworkPolicy对没有这个标签的pod不生效。一个空的podSelector选择名称空间中的所有pods。若果为{}表示所有pod.
- policyTypes:每个NetworkPolicy都包含一个policyTypes列表,其中可以包含入口Ingress、出口Egress,也可以同时包含入口和出口。policyTypes字段指示给定的策略是否应用于将流量输入到选定的pod、将流量从选定的pod输出或同时应用于两者。如果在NetworkPolicy上没有指定策略类型,那么默认情况下将始终设置Ingress,如果NetworkPolicy有任何出口规则,则将具体设置Egress规则。
- ingress:每个NetworkPolicy可能包括一个允许进入规则的列表。每个规则都允许匹配from和ports字段的流量。如果值为{},表示默认允许所有ingress流量;如果没有值表示不允许任何ingress流量。
- egress:每个网络策略包括一张允许出口规则的列表。每个规则都允许匹配to和ports字段的流量。如果值为{},表示默认允许所有egress流量;如果没有值即egress: []表示不允许任何egress流量。
因为要配合pod的标签使用,所以创建资源的yaml可以定义在busybox.yaml文件中,内容如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: busybox
namespace: user1
labels:
app: busybox
spec:
replicas: 1
selector:
matchLabels:
app: busybox
template:
metadata:
labels:
app: busybox
appType: user1App
user: user1
spec:
containers:
- name: busybox
image: pml/busybox:0.1
ports:
- containerPort: 80
这样通过busybox.yaml创建的pod带有两个标签,一个是“appType=user1App”,该标签会让network policy生效。另外一个标签“user=user1”只允许user1的流量流入,从而达到模拟租户隔离的目的。但是egress中没有规则,也就是对egress不作限制,是可以通往外部namespace的。
网段隔离示例
该示例不限制ingress方向,只允许指定网段的出,即 DstIP 在101.1.0.0/16中才能出。因为允许域名解析所以放开53端口的通信。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels:
app: test-dvwa
policyTypes:
- Ingress
- Egress
ingress:
- {}
egress:
- to:
- ipBlock:
cidr: 101.1.0.0/16
- to:
ports:
- protocol: TCP
port: 53
- protocol: UDP
port: 53
注意ports前面的to不能去掉,否则就变成 101.1.0.0/16 且端口是53的才能出了。另外要限制的容器的namepace必须和networkpolicy的namespace一致。如上面的示例,该策略会生效到default 命名空间且带标签app=test-dvwa的容器上。如果运行两个网段出去,可以像下面这样定义:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels:
app: test-dvwa
policyTypes:
- Ingress
- Egress
ingress:
- {}
egress:
- to:
- ipBlock:
cidr: 101.1.0.0/16
- to:
- ipBlock:
cidr: 172.18.8.0/24
- to:
ports:
- protocol: TCP
port: 53
- protocol: UDP
port: 53
egress里面的几个to是或的关系,同一个to里面的多个条件是并且的关系。
参考文档
- https://xie.infoq.cn/article/b0cfe588251d024d9114c84f3 netfilter/iptables 原理