Kubernetes的网络策略

Network Policy的主要功能是对Pod或者Namespace之间的网络通讯进行限制和准入控制,设置方式为将目标对象的Label作为查询条件,设置允许访问或禁止访问的客户端Pod列表。目前查询条件可以作用于Pod和Namespace级别。

网络策略设置说明

网络策略的设置主要用于对目标Pod的网络访问进行控制,在默认情况下对所有Pod都是允许访问的,在设置了指向Pod的NetworkPolicy网络策略后,到Pod的访问才会被限制。

下面通过一个例子对NetworkPolicy资源对象的使用进行说明:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978

对主要参数说明如下:

  • podSelector:定义该网络策略作用的Pod范围,本例的选择条件为包含role=db标签的Pod。
  • policyTypes:网络策略的类型,包括ingress和egress两种,用于设置目标Pod的入站和出站的网络限制。如果未指定policyTypes,则系统默认会设置Ingress类型;若设置了egress策略,则系统自动设置Egress类型。
  • ingress:定义允许访问目标Pod的入站白名单规则,满足from条件的客户端才能访问ports定义的目标Pod端口号。
    • from:对符合条件的客户端Pod进行网络放行,规则包括基于客户端Pod的Label、基于客户端Pod所在命名空间的Label或者客户端的IP范围。
    • ports:允许访问的目标Pod监听的端口号。
  • egress:定义目标Pod允许访问的“出站”白名单规则,目标Pod仅允许访问满足to条件的服务端IP范围和ports定义的端口号。
    • to:允许访问的服务端信息,可以基于服务端Pod的Label、基于服务端Pod所在命名空间的Label或者服务端IP范围。
    • ports:允许访问的服务端的端口号。

通过本例所示的NetworkPolicy设置,对不同命名空间中的目标Pod进行了网络访问,发现该网络策略作用于命名空间default中包含role=db标签的全部Pod

Ingress规则包括:

  • 允许与目标Pod在同一个命名空间中的包含role=frontend标签的客户端Pod访问目标Pod;
  • 允许属于包含project=myproject标签的命名空间的客户端Pod访问目标Pod;
  • 允许属于IP地址范围172.17.0.0/16的客户端Pod访问目标Pod,但不包括属于IP地址范围172.17.1.0/24的客户端应用。

Egress规则包括:

  • 允许目标Pod去访问属于IP地址范围10.0.0.0/24并监听5978端口的服务。

Selector功能说明

在form或to配置中,namespaceSelector和PodSelector可以单独设置,也可以组合设置。ingress的from段落和egress的to段落总共可以有4种选择器(Selector)的设置方式。

  • podSelector:同一个命名空间选中的目标Pod应作为ingress来源或egress目标允许网络访问。
  • namespaceSelector:目标命名空间中的全部Pod应作为ingress来源或egress目标允许网络访问。
  • podSelector和namespaceSelector:在from或to配置中如果既设置了namespaceSelector又设置了podSelector,则表示选中指定命名空间的Pod。这在YAML定义中需要进行准确设置。
  • ipBlock:其设置的IP地址范围应作为ingress来源或egress目标允许网络访问,通常应设置为集群外部的IP地址。

通过两个例子对Selector的作用进行说明。
例1,在from中同时设置namespaceSelector和podSelector,该策略允许从拥有user=alice标签的命名空间中,且拥有role=client标签的Pod发起访问:

......
  ingress:
    - from:
      - namespaceSelector:
          matchLabels:
            user: alice
        podSelector:
          matchLabels:
            role: client
.....

例2,在from中分别设置namespaceSelector和podSelector,该策略即允许从有user=alice标签的命名空间中任意Pod发起访问,也允许从当前命名空间中有role=client标签的Pod发起访问:

......
  ingress:
    - from:
      - namespaceSelector:
          matchLabels:
            user: alice
      - podSelector:
          matchLabels:
            role: client
.....

为命名空间配置默认的网络策略

在一个命名空间没有配置任何网络策略的情况下,对其中的Pod的ingress和egress网络流量并不会有任何限制。在命名空间级别可以设置一些默认的全局网络策略,以便管理员对整个命名空间进行统一的网络策略设置。
以下是一些常用的命名空间级别的默认网络策略。

  1. 默认禁止ingress访问。该策略禁止任意客户端访问该命名空间中的任意Pod,起到隔离访问的作用:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  1. 默认允许ingress访问。该策略允许任意客户端访问该命名空间中的任意Pod:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all
spec:
  podSelector: {}
  ingress:
  - {}
  policyTypes:
  - Ingress
  1. 默认禁止egress访问。该策略禁止该命名空间中的所有Pod访问任意外部服务:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
spec:
  podSelector: {}
  policyTypes:
  - Egress
  1. 默认允许egress访问。该策略允许该命名空间中的所有Pod访问任意外部服务:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all
spec:
  podSelector: {}
  egress:
  - {}
  policyTypes:
  - Egress
  1. 默认同时禁止ingress和egress访问。该策略禁止任意客户端访问该命名空间中的任意Pod,同时禁止该命名空间的所有Pod访问任意外部服务:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

网络策略应用示例

下面以一个提供服务的Nginx Pod为例,为两个客户端Pod设置不同的网络访问权限:允许拥有role=nginxclient标签的Pod访问Nginx容器,没有这个标签的客户端容器会被禁止访问。

  1. 创建一个名为nginx.yaml的目标Pod,设置app=nginx标签:
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx

创建Pod:

[root@master1 ~]# kubectl create -f nginx.yaml 
pod/nginx created
  1. 创建一个名为networkpolicy-allow-nginxclient.yaml为目标Nginx Pod设置网络策略,创建NetworkPolicy的YAML文件,内容如下:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: allow-nginxclient
spec:
  podSelector:
    matchLabels:
      app: nginx
  ingress:
    - from:
      - podSelector:
          matchLabels:
            role: nginxclient
      ports:
      - protocol: TCP
        port: 80

该网络策略的作用目标Pod应包含app=nginx标签,通过from设置允许客户端包含role=nginxclient标签的Pod访问,并设置允许客户端访问的端口号为80。

创建该NetworkPolicy资源对象,并查看信息:

[root@master1 ~]# kubectl create -f networkpolicy-allow-nginxclient.yaml 
networkpolicy.networking.k8s.io/allow-nginxclient created
[root@master1 ~]# kubectl describe networkpolicies allow-nginxclient 
Name:         allow-nginxclient
Namespace:    default
Created on:   2022-06-24 17:54:36 +0800 CST
Labels:       <none>
Annotations:  <none>
Spec:
  PodSelector:     app=nginx
  Allowing ingress traffic:
    To Port: 80/TCP
    From:
      PodSelector: role=nginxclient
  Not affecting egress traffic
  Policy Types: Ingress
  1. 创建两个客户端Pod,一个包含role=nginxclient标签,另一个无此标签。分别进入Pod,访问Nginx容器,验证网络策略的效果:

client1.yaml文件内容如下:

apiVersion: v1
kind: Pod
metadata:
  name: client1
  labels:
    role: nginxclient
spec:
  containers:
    - name: client1
      image: busybox
      command: ["sleep", "3600"]

client2.yaml文件内容如下:

apiVersion: v1
kind: Pod
metadata:
  name: client2
spec:
  containers:
    - name: client2
      image: busybox
      command: ["sleep", "3600"]

创建两个Pod,并查看所有Pod信息:

[root@master1 ~]# kubectl create -f client1.yaml -f client2.yaml 
pod/client1 created
pod/client2 created
[root@master1 ~]# kubectl get pods -o wide
NAME      READY   STATUS    RESTARTS   AGE    IP             NODE    NOMINATED NODE   READINESS GATES
client1   1/1     Running   0          11s    10.0.166.144   node1   <none>           <none>
client2   1/1     Running   0          11s    10.0.104.25    node2   <none>           <none>
nginx     1/1     Running   0          9m5s   10.0.104.28    node2   <none>           <none>

看到刚刚创建nginx的IP是10.0.104.28,用client1尝试连接Nginx容器的80端口:

[root@master1 ~]# kubectl exec -it client1 -- wget 10.0.104.28
Connecting to 10.0.104.28 (10.0.104.28:80)
saving to 'index.html'
index.html           100% |********************************|   615  0:00:00 ETA
'index.html' saved

成功访问到Nginx服务器,说明NetworkPolicy生效。

用client2尝试连接Nginx容器的80端口:

[root@master1 ~]# kubectl exec -it client2 -- wget --timeout=5  10.0.104.28
Connecting to 10.0.104.28 (10.0.104.28:80)
wget: download timed out
command terminated with exit code 1

访问超时,说明NetworkPolicy生效,对没有role=nginxclient标签的客户端Pod拒绝访问。

原文:《Kubernetes权威指南(第5版)》