NetworkPolicy
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata:name: test-network-policynamespace: defaultspec:podSelector:matchLabels:role: dbpolicyTypes:- Ingress- Egressingress:- from:- ipBlock:cidr: 172.17.0.0/16except:- 172.17.1.0/24- namespaceSelector:# 也可以使用matchExpressionsmatchLabels:project: myproject- podSelector:# 也可以使用matchExpressionsmatchLabels:role: frontendports:- protocol: TCPport: 6379egress:- to:- ipBlock:cidr: 10.0.0.0/24ports:- protocol: TCPport: 5978
Kubernetes 里的 Pod 默认都是“允许所 有”(Accept All)的,即:Pod 可以接收来自任何发送方的请求;或者,向任何接收方 发送请求。而如果你要对这个情况作出限制,就必须通过 NetworkPolicy 对象来指定。
而在上面这个例子里,你首先会看到 podSelector 字段。它的作用,就是定义这个 NetworkPolicy 的限制范围,比如:当前 Namespace 里携带了 role=db 标签的 Pod。
而如果你把 podSelector 字段留空:
spec:
podSelector: {}
那么这个 NetworkPolicy 就会作用于当前 Namespace 下的所有 Pod。 而一旦 Pod 被 NetworkPolicy 选中,那么这个 Pod 就会进入“拒绝所有”(Deny All) 的状态,即:这个 Pod 既不允许被外界访问,也不允许对外界发起访问。 而 NetworkPolicy 定义的规则,其实就是“白名单”
例如,在我们上面这个例子里,我在 policyTypes 字段,定义了这个 NetworkPolicy 的类型是 ingress 和 egress,即:它既会拒绝流入(ingress)请求,也会拒绝流出(egress) 请求。
然后,在 ingress 字段里,我定义了 from 和 ports,即:允许流入的“白名单”和端口。 其中,这个允许流入的“白名单”里,我指定了三种并列的情况,分别是:ipBlock、 namespaceSelector 和 podSelector。
而在 egress 字段里,我则定义了 to 和 ports,即:允许流出的“白名单”和端口。这里允许流出的“白名单”的定义方法与 ingress 类似。只不过,这一次 ipblock 字段指定的,是目的地址的网段。 综上所述,这个 NetworkPolicy 对象,指定的隔离规则如下所示:
- 该隔离规则只对 default Namespace 下的,携带了 role=db 标签的 Pod 有效。限制的请求类型包括 ingress(流入)和 egress(流出)。
- Kubernetes 会拒绝任何访问被隔离 Pod 的请求,除非这个请求来自于以下“白名单”里的对象,并且访问的是被隔离 Pod 的 6379 端口。这些“白名单”对象包括:
- default Namespace 里的,携带了 role=fronted 标签的 Pod;
- 任何 Namespace 里的、携带了 project=myproject 标签的 Pod;
- 任何源地址属于 172.17.0.0/16 网段,且不属于 172.17.1.0/24 网段的请求。
- Kubernetes 会拒绝被隔离 Pod 对外发起任何请求,除非请求的目的地址属于 10.0.0.0/24 网段,并且访问的是该网段地址的 5978 端口。
需要注意的是,定义一个 NetworkPolicy 对象的过程,容易犯错的是“白名单”部分 (from 和 to 字段)。
举个例子:
...
ingress:
- from:
- namespaceSelector:
matchLabels:
user: alice
- podSelector:
matchLabels:
role: client
...
像上面这样定义的 namespaceSelector 和 podSelector,是“或”(OR)的关系。所以说,这个 from 字段定义了两种情况,无论是 Namespace 满足条件,还是 Pod 满足条 件,这个 NetworkPolicy 都会生效。 而下面这个例子,虽然看起来类似,但是它定义的规则却完全不同:
...
ingress:
- from:
- namespaceSelector:
matchLabels:
user: alice
podSelector:
matchLabels:
role: client
...
注意看,这样定义的 namespaceSelector 和 podSelector,其实是“与”(AND)的关系。所以说,这个 from 字段只定义了一种情况,只有 Namespace 和 Pod 同时满足条件,这个 NetworkPolicy 才会生效。
命名空间隔离
当K8s集群上运行着多项目时,每个项目应当拥有自己的命名空间,自然我们希望这些命名空间之间的网络时隔离的,而命名空间之内的各个Pod的网络时连通的。同时命名空间里的Pod应当允许管理类应用的请求,包括kube-system、kubernetes-dashboard、日志收集系统(logs)、监控系统(monitoring)。同时命名空间里的Pod通常会请求DNS服务以及Kubernetes的API等。设命名空间为stage,yaml编写如下:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default
namespace: stage
spec:
podSelector: {} # 当前名称空间中的所有Pod对象
policyTypes: ["Ingress", "Egress"] # Ingress和Egress规则
ingress:
- from: # 入站规则1:所有端口
- namespaceSelector: # 流量:来自指定名称空间中的所有源端点
matchExpressions:
- key: name
operator: In
values: [stage, kube-system, logs, monitoring, kubernetes-dashboard]
egress:
- to: # 出站规则1:任意目标端点的UDP协议的53端口
ports:
- protocol: UDP
port: 53
- to: # 出站规则2:仅生效于TCP协议的443端口
- namespaceSelector: # 流量:指定命名空间内的指定Pod对象
matchLabels:
name: kube-system
podSelector:
matchLabels:
component: kube-apiserver
ports:
- protocol: TCP
port: 443
- to: # 出站规则3:所有端口
- namespaceSelector: # 流量:指定命名空间内的所有目标端点
matchLabels:
name: stage
