NetworkPolicy

  1. apiVersion: networking.k8s.io/v1
  2. kind: NetworkPolicy
  3. metadata:
  4. name: test-network-policy
  5. namespace: default
  6. spec:
  7. podSelector:
  8. matchLabels:
  9. role: db
  10. policyTypes:
  11. - Ingress
  12. - Egress
  13. ingress:
  14. - from:
  15. - ipBlock:
  16. cidr: 172.17.0.0/16
  17. except:
  18. - 172.17.1.0/24
  19. - namespaceSelector:
  20. # 也可以使用matchExpressions
  21. matchLabels:
  22. project: myproject
  23. - podSelector:
  24. # 也可以使用matchExpressions
  25. matchLabels:
  26. role: frontend
  27. ports:
  28. - protocol: TCP
  29. port: 6379
  30. egress:
  31. - to:
  32. - ipBlock:
  33. cidr: 10.0.0.0/24
  34. ports:
  35. - protocol: TCP
  36. port: 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 对象,指定的隔离规则如下所示:

  1. 该隔离规则只对 default Namespace 下的,携带了 role=db 标签的 Pod 有效。限制的请求类型包括 ingress(流入)和 egress(流出)。
  2. Kubernetes 会拒绝任何访问被隔离 Pod 的请求,除非这个请求来自于以下“白名单”里的对象,并且访问的是被隔离 Pod 的 6379 端口。这些“白名单”对象包括:
    1. default Namespace 里的,携带了 role=fronted 标签的 Pod;
    2. 任何 Namespace 里的、携带了 project=myproject 标签的 Pod;
    3. 任何源地址属于 172.17.0.0/16 网段,且不属于 172.17.1.0/24 网段的请求。
  3. 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