目录

Kubernetes网络策略之详解

NetWork Policy简介

​随着微服务架构的日渐盛行,Serverless框架的逐步落地,应用上云后带来了模块间网络调用需求的大规模增长,Kubernetes 自 1.3 引入了 Network Policy,其提供以应用为中心, 基于策略的网络控制,用于隔离应用以减少攻击面。

网络策略(Network Policy )是 Kubernetes 的一种资源。Network Policy 通过 Label 选择 Pod,并指定其他 Pod 或外界如何与这些 Pod 通信。

Pod的网络流量包含流入(Ingress)和流出(Egress)两种方向。默认情况下,所有 Pod 是非隔离的,即任何来源的网络流量都能够访问 Pod,没有任何限制。当为 Pod 定义了 Network Policy,只有 Policy 允许的流量才能访问 Pod。

​Pod之间能否通信可通过如下三种组合进行确认:

  • 其他被允许的 Pods(例如:Pod 无法限制对自身的访问)
  • 被允许访问的namespace
  • IP CIDR(例如:与 Pod 运行所在节点的通信总是被允许的)

在定义基于 Pod 或namespace的 NetworkPolicy 时,可以使用标签选择器来设定哪些流量可以进入或离开 Pod。同时,当创建基于 IP 的 NetworkPolicy 时,可以基于 IP CIDR 来定义策略。

​Kubernetes的网络策略功能也是由第三方的网络插件实现的,因此,只有支持网络策略功能的网络插件才能进行配置网络策略,比如Calico、Canal、kube-router等等。

部署calico网络插件提供网络策略功能

Calico可以独立地为Kubernetes提供网络解决方案和网络策略,也可以和flannel相结合,由flannel提供网络解决方案,Calico仅用于提供网络策略,此时将Calico称为Canal。结合flannel工作时,Calico提供的默认配置清单式以flannel默认使用的10.244.0.0/16为Pod网络,因此在集群中kube-controller-manager启动时就需要通过–cluster-cidr选项进行设置使用该网络地址,并且—allocate-node-cidrs的值应设置为true。

本文使用calico作为网络插件,并提供网络策略功能来加以说明

1、下载calico安装文件,修改网段

1
curl -LO https://docs.projectcalico.org/archive/v3.15/manifests/calico.yaml

将配置文件中CALICO_IPV4POOL_CIDR注释取消,并将值修改为: 10.244.0.0/16

2、安装calico

1
kca -f calico.yaml

配置网络策略

​在Kubernetes系统中,报文的流入和流出的核心组件是Pod资源,它们也是网络策略功能的主要应用对象。NetworkPolicy对象通过podSelector选择 一组Pod资源作为控制对象。NetworkPolicy是定义在一组Pod资源之上用于管理入站流量,或出站流量的一组规则,有可以是出入站规则一起生效,规则的生效模式通常由spec.policyTypes进行 定义。如下图:

https://tc.ctq6.cn/tc/1349539-20190313170340204-1497786108.png

​默认情况下,Pod对象的流量控制是为空的,报文可以自由出入。在附加网络策略之后,Pod对象会因为NetworkPolicy而被隔离,一旦名称空间中有任何NetworkPolicy对象匹配了某特定的Pod对象,则该Pod将拒绝NetworkPolicy规则中不允许的所有连接请求,但是那些未被匹配到的Pod对象依旧可以接受所有流量。

​就特定的Pod集合来说,入站和出站流量默认是放行状态,除非有规则可以进行匹配。还有一点需要注意的是,在spec.policyTypes中指定了生效的规则类型,但是在networkpolicy.spec字段中嵌套定义了没有任何规则的Ingress或Egress时,则表示拒绝入站或出站的一切流量。定义网络策略的基本格式如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
apiVersion: networking.k8s.io/v1		#定义API版本
kind: NetworkPolicy					   #定义资源类型
metadata:
  name: allow-myapp-ingress			    #定义NetwokPolicy的名字
  namespace: default
spec:								  #NetworkPolicy规则定义
  podSelector: 						   #匹配拥有标签app:myapp的Pod资源
    matchLabels:
      app: myapp
  policyTypes:        #NetworkPolicy类型,可以是Ingress,Egress,或者两者共存
  - Ingress
  - Egress
  ingress:							  #定义入站规则
  - from:
    - ipBlock:						  #定义可以访问的网段
        cidr: 10.244.0.0/16
        except:						  #排除的网段
        - 10.244.3.0/24
    - podSelector:					  #选定当前default名称空间,标签为app:myapp可以入站
        matchLabels:
          app: myapp
    ports:							 #开放的协议和端口定义
    - protocol: TCP
      port: 80
  egress:
  - to:
    - ipBlock:              #指定端口上的流量匹配到 10.244.0.0/24 中的任何目的地
        cidr: 10.244.0.0/24
    ports:
    - protocol: TCP
      port: 80
  
该网络策略就是将default名称空间中拥有标签"app=myapp"的Pod资源开放80/TCP端口给10.244.0.0/16网段,并排除10.244.3.0/24网段的访问,并且也开放给标签为app=myapp的所有Pod资源进行访问。
  • 必需字段:与所有其他的 Kubernetes 对象一样,NetworkPolicy 需要 apiVersion、 kind 和 metadata 字段。

  • spec:NetworkPolicy 规约中包含了在名字空间中定义特定网络策略所需的所有信息。

  • podSelector:每个 NetworkPolicy 都包括一个 podSelector,它选择适用该该策略的 Pod。示例中的策略选择带有 “app=myapp” 标签的 Pod。若podSelector为空的,则选择名字空间下所有 Pod。

  • policyTypes: 每个 NetworkPolicy 都包含一个 policyTypes 列表,其中包含 Ingress 或 Egress 或(两者亦可)。policyTypes 字段表示给定的策略是应用于 所选 Pod 的入口流量还是来出口流量(两者亦可)。如果 NetworkPolicy 未指定 policyTypes 则默认情况下始终设置 Ingress;如果 NetworkPolicy 有任何出口规则的话则设置 Egress。

  • ingress: 每个 NetworkPolicy 可包含一个 ingress 规则的白名单列表。每个规则都允许同时匹配 from 和 ports 部分的流量。示例策略中包含一条 简单的规则:它匹配某个特定端口,第一个通过 ipBlock 指定,第二个通过 podSelector 指定。

  • egress: 每个 NetworkPolicy 可包含一个 egress 规则的白名单列表。每个规则都允许匹配 to 和 port 部分的流量。该示例策略包含一条规则, 该规则指定端口上的流量匹配到 10.0.0.0/24 中的任何目的地。

该网络策略总结如下:

  • 隔离 default名字空间下 app=myapp 的 Pod 。

  • 出口限制:允许符合以下条件的 Pod 连接到 default名字空间下标签为 app=myapp的所有 Pod 的 80 TCP 端口:

    • a) default名字空间下带有 app=myapp 标签的所有 Pod
    • b) IP 地址范围为10.244.0.0–10.244.0.255 和 10.244.3.0–10.244.255.255(即除了 10.244.3.0/24 之外的所有 10.244.0.0/16)
  • 入口限制:允许从带有 app=myapp标签的名字空间下的任何 Pod 到 CIDR 10.244.0.0/16 下 80 TCP 端口。

部署应用

1、部署nginx服务

1
2
3
4
5
[root@localhost ~]# kubectl create deployment nginx --image=nginx
deployment.apps/nginx created

[root@localhost ~]# kubectl expose deployment nginx --port=80
service/nginx exposed

2、测试网络

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
[root@localhost ~]# kubectl get svc,pod
NAME                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP   9d
service/nginx        ClusterIP   10.105.249.196   <none>        80/TCP    22m

NAME                         READY   STATUS    RESTARTS   AGE
pod/nginx-6799fc88d8-dpqrp   1/1     Running   0          22m

[root@localhost ~]# kubectl run busybox --rm -ti --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget --spider --timeout=1 nginx
Connecting to nginx (10.105.249.196:80)
remote file exists

3、测试网络策略

如果只让那些拥有标签 access: true 的 Pod 访问 nginx 服务, 那么可以创建一个如下所示的 NetworkPolicy 对象:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
cat << EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: access-nginx
spec:
  podSelector:
    matchLabels:
      app: nginx
  ingress:
  - from:
    - podSelector:
        matchLabels:
          access: "true"
EOF
networkpolicy.networking.k8s.io/access-nginx created
  • 不带 access=true 标签的 Pod 还是无法访问 nginx 服务

    1
    2
    3
    4
    5
    
    [root@localhost ~]# kubectl run busybox --rm -ti --image=busybox /bin/sh
    If you don't see a command prompt, try pressing enter.
    / # wget --spider --timeout=1 nginx
    Connecting to nginx (10.105.249.196:80)
    wget: download timed out
    
  • 而带有 access=true 标签的 Pod 可以访问 nginx 服务

    1
    2
    3
    4
    5
    
    [root@localhost ~]# kubectl run busybox --rm -ti --labels="access=true" --image=busybox /bin/sh
    If you don't see a command prompt, try pressing enter.
    / # wget --spider --timeout=1 nginx
    Connecting to nginx (10.105.249.196:80)
    remote file exists
    

应用场景

管控入站流量