k8s网络策略

网络策略介绍

网络策略官方文档:https://kubernetes.io/zh-cn/docs/concepts/services-networking/network-policies/

网络策略是控制Pod之间如何进行通信的规则,它使用标签来筛选Pod,并在该组Pod之上定义规则来定义管控其流量,从而为k8s提供更精细的流量控制和租户隔离机制。管理员和用户可以通过NetworkPolicy资源按需定义网络访问控制策略

网络策略的具体实现要依靠CNI网络插件完成,例如Calico、Weave和Antrea等。因此,仅在使用支持网络策略的网络插件时才能让自定义的网络策略生效。不同的网络插件实现网络策略的方式也是不一样的。

本文以Calico网络插件为例,它的calico-kube-contollers是用于将用户自定义的网络策略进行实现的组件,它主要依赖于在节点上构建iptales规则实现访问控制功能。

默认情况下,k8s并未对Pod的流量做任何限制。Pod对象能够与集群上其他任何Pod通信,也能够与集群外部的网络端点通信。NetworkPolicy是名称空间级别资源,允许用户在通过标签选择器筛选的一组Pod上分别管理入站(Ingress)和出站(Egress)流量。将NetworkPolicy应用到名称空间中后,被标签选择器选中的Pod将默认拒绝所有流量,仅放行由NetworkPolicy资源明确允许的流量。未被NetworkPolicy资源的标签选择器选中的Pod对象的流量则不受影响。

NetworkPolicy是Kubernetes API中标准的资源类型,它的部署文件常用字段如下:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: ...
  namespace: ...
spec:
  podSelector: >	#Pod标签选择器,用来在当前名称空间下筛选出一组Pod,之后定义的出入站规则对此组Pod生效
  policyTypes: <[]string>	#网络策略类型,Ingress表示对入站流量限制;Egress表示对出站流量限制,同时提供表示都限制
  ingress:	#允许通过的入站流量的规则定义,空值表示允许所有的入站流量通过
  - from:	#允许通过的入站流量的源端点列表,空值表示所有端点
    - ipBlock:	#用IP地址范围匹配源端点,不能与下面的namespacesSelector和podSelector同时使用
        cidr: >		#源端点的IP网段
        except: <[]string>	#从cidr中排除的网段范围或地址,这些源端点不能访问指定的Pod
      namespacesSelector: >	#由标签选择器筛选的名称空间中的端点,空值表示所有名称空间
      podSelector: >		#由标签选择器筛选的Pod端点,空值表示none
    ports: <[]Object>	#入站流量的目标端口列表,空值表示所有端口
  egress:	#允许通过的出站流量的规则定义,空值表示允许所有出站流量通过
  - to: <[]Object>	#允许出站流量访问的目标端点对象列表,空值表示所有端点,可嵌套字段通ingress.from
    ports: <[]Object>	#允许出站流量访问的目标端口对象列表,空值表示所有端口

为了方便理解NetworkPolicy资源及其功能,常用的术语如下:

  • Pod组:由NetworkPolicy通过标签选择器筛选出的一组Pod,它们是网络策略规则管控的目标
  • Egress规则:出站流量相关的规则,负责管控选定的Pod组发往其它端点的流量,可由流量的目标端点(spec.egress.to)和目标端口(spec.egress.ports)来定义
  • Ingress规则:入站流量的相关规则,负责管控选定的Pod组所能接收的流量,可由流量的源端点(spec.ingress.from)和流量的目标端口(spec.ingress.ports)来定义
  • 对端端点:与选定的Pod组交互的对端主机,可以由CIDR格式的地址段(ipBlock)来匹配指定地址段内的Pod对象、名称空间选择器(namespacesSelector)来匹配名称空间内的所有Pod对象,也可以结合Pod选择器(podSelector)在指定名称空间选出一组Pod对象

在Ingress规则中,由from字段指定的端点称为源端点;而在Egress规则中,网络端点也称为目标端点,用to字段标识。对于未启用Ingress或Egress规则的Pod组,出站和入站流量默认均为允许。一旦在networkpolicy.spec中定义了ingress或egress字段,则它们的from或to字段就代表白名单列表,空值意味着选定所有端点,即允许相应方向上所有流量通过,此时ingress和egress字段作用与未启用流量方向设置(即spec.policyTypes字段为空)时相同。

Ingress和Egress的生效逻辑略微复杂,Egress规则生效逻辑和Ingress类似,以Ingress规则为例:

  1. 定义了spec.policyTypes值为Ingress,但未定义spec.ingress字段时,它无法匹配任何流量,因此选定的Pod组不接受任何端点访问
  2. 定义了spec.policyTypes值为Ingress,但使用空值的spec.ingress或spec.ingress.from字段,表示匹配所有的端点,因而选出的Pod组可以被任意端点访问
  3. 最后,即使Egress规则拒绝所有流量,但由Ingress规则放行的请求流量的响应报文依然能够正常出站,它并不受限于Egress规则的限制,反之亦然

Ingress规则

在实际环境中,有些Pod提供的服务不需要或不能公开给所有人访问,这时候就需要对它们施加访问控制。在需要管控的Pod对象所在的名称空间创建一个NetworkPolicy资源,使用spec.podSelector筛选要管控的Pod,并使用spec.ingress定义入站规则就实现入站流量管控。

spec.ingress可嵌套的from和ports均为可选字段,空值表示允许所有入站流量通过。仅定义from字段时表示入站流量的目标端口不做限制,仅定义ports字段时表示入站流量的源端点不做限制。from和ports定义在一个列表项时,它们是逻辑与关系,表示匹配那些同时满足from和ports的入站流量

  • ingress.from字段
    from字段的值是一个列表,用于指定访问目标Pod组入站流量的来源,可嵌套使用ipBlock、namespaceSelector和podSelector 3个字段。这3个字段匹配Pod的方式各有不同,且ipBlock不能和另外两个字段同时使用,同时使用namespaceSelector和podSelector这两个字段时它们是逻辑与关系。from下的多个列表项是逻辑或关系,入站流量只要能匹配其中一个就可以。
    • ipBlock:根据IP地址或网络地址来匹配源端点
    • namespaceSelector:使用标签选择器筛选名称空间,它将匹配筛选出的名称空间内的所有Pod对象;空值表示匹配所有名称空间,即源端点可以是集群上的任意Pod对象
    • podSelector:在NetworkPolicy资源所在的名称空间中基于标签选择器筛选Pod对象,空值表示选中当前名称空间所有Pod对象。与namespaceSelector同时使用时,作用域为namespaceSelector筛选出的名称空间
  • ingress.ports 字段
    ports字段的值也是一个对象列表,用于定义入站流量可以访问的目标端口,可以嵌套使用port和protocol字段
    • port:端口号或在container上定义的端口名称,未定义时匹配所有端口
    • protocol: 协议,TCP或UDP,默认TCP

下面创建一些资源,用来后续测试网络策略的功能,包括两个名称空间project1和project2,在project1名称空间下部署一个nginx和tomcat,在project名称空间下部署一个nginx,部署文件如下:

apiVersion: v1
kind: Namespace
metadata:
  name: project1
  labels:
    name: project1

---
apiVersion: v1
kind: Namespace
metadata:
  name: project2
  labels:
    name: project2

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-project1
  namespace: project1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
      project: project1
  template:
    metadata:
      labels:
        app: nginx
        project: project1
        tier: fronted
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - name: http
          containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tomcat-project1
  namespace: project1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: tomcat
      project: project1
      tier: backend
  template:
    metadata:
      labels:
        app: tomcat
        project: project1
        tier: backend
    spec:
      containers:
      - name: tomcat
        image: tomcat:10.1.2
        ports:
        - name: http
          containerPort: 8080

---
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc-project1
  namespace: project1
spec:
  type: NodePort
  selector:
    app: nginx
    project: project1
  ports:
  - name: http
    port: 80
    targetPort: 80
    protocol: TCP

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-project2
  namespace: project2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
      project: project2
  template:
    metadata:
      labels:
        app: nginx
        project: project2
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - name: http
          containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc-project2
  namespace: project2
spec:
  type: NodePort
  selector:
    app: nginx
    project: project2
  ports:
  - name: http
    port: 80
    targetPort: 80
    protocol: TCP

在这里插入图片描述

示例1

限定指定的标签的Pod才能访问project1名称空间下的tomcat pod

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: network-policy-demo1
  namespace: project1
spec:
  policyTypes: ["Ingress"]
  podSelector:	#规则针对tomcat Pod生效
    matchLabels:
      app: tomcat
      project: project1
      tier: backend
  ingress:
  - from:
    - podSelector:	#拥有下面指定标签的Pod才能访问tomcat Pod,默认是在当前名称空间下筛选
        matchLabels:
          app: nginx
          project: project1
          tier: fronted
    ports:		#只能访问tomcat Pod的8080端口
    - port: 8080
      protocol: TCP

查看networkpPolicy资源
k8s网络策略_第1张图片
用同名称空间下nginx pod访问tomcat Pod,可以访问,因为nginx pod的标签符合NetworkPolicy的设定
在这里插入图片描述

在default名称空间中使用clinet-pod访问project1名称空间下的tomcat,无法访问,因为client-pod的标签不符合NetworkPolicy的设定
k8s网络策略_第2张图片

示例2

通过ip地址限定可以访问tomcat的Pod

kind: NetworkPolicy
metadata:
  name: network-policy-demo2
  namespace: project1
spec:
  policyTypes: ["Ingress"]
  podSelector:
    matchLabels:
      app: tomcat
      project: project1
      tier: backend
  ingress:
  - from:
    - ipBlock:
        cidr: 10.244.0.0/16
        except:
        - 10.244.169.0/24
    ports:
    - port: 8080
      protocol: TCP

在node-01和node-02上分别运行一个client-pod,然后去访问tomcat,node-01上的client-pod可以访问,node-02上的client-pod不能访问,因为它属于10.244.169.0/24网段
在这里插入图片描述
k8s网络策略_第3张图片

示例3
通过名称空间限定可以访问tomcat Pod

kind: NetworkPolicy
metadata:
  name: network-policy-demo3
  namespace: project1
spec:
  policyTypes: ["Ingress"]
  podSelector:
    matchLabels:
      app: tomcat
      project: project1
      tier: backend
  ingress:
  - from:	#限定只有project2名称空间下具有app=nginx的Pod才能访问tomcat
    - podSelector:	#podSlector筛选app=nginx的Pod
        matchLabels:
          app: nginx
      namespaceSelector:	#namespaceSelector和podSlector是逻辑与关系,表示在namespaceSelector筛选出的名称空间下用podSlector筛选Pod
        matchLabels:
          name: project2
    ports:
    - port: 8080
      protocol: TCP

在project1名称空间下用nginx-pod访问tomcat-pod,不能访问
在这里插入图片描述
在project2名称空间下用nginx-pod访问tomcat-pod,可以访问
在这里插入图片描述
在project2名称空间下使用其它pod访问tomcat,无法访问
在这里插入图片描述

Egress规则

大多数情况下,一个名称空间下的Pod资源总有对外请求的需求,例如向CoreDns请求名称解析等。因此,通常应该将出站流量的默认策略设置为允许通过。但如果要实现更精细的控制,仅放行有对外请求必要的Pod对象的出站流量,可以通过Egress实现。

spec.egress字段用于定义出站流量规则,它可以嵌套使用to和ports字段,to用于定义选定的Pod组的出站流量可访问的目标端点,其格式和逻辑与ingress.from一致;ports用于定义选定的Pod组的出站流量可访问的目标端口。

下面是一个示例:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: network-policy-egress-demo1
  namespace: project1
spec:
  policyTypes: ["Egress"]	#网络策略类型为Egress
  podSelector:	#对project1名称空间下的nginx-pod进行限制
    matchLabels:
      app: nginx
      project: project1
      tier: fronted
  ingress:
  - to:		#Egress条件1,限制nginx只能访问同名称空间下的tomcat-pod的8080端口
    - podSelector:
        matchLabels:
          app: tomcat
          project: project1
          tier: backend
    ports:
    - port: 8080
      protocol: TCP
  - to:		#Egress条件2,限制nginx只能访问192.168.211.0/24网段的主机的任何端口(不定义ports字段表示不限制)
    - ipBlock:
        cidr: 192.168.211.0/24

测试在project1名称空间下nginx-pod访问同名称空间下的tomcat-pod,可以正常访问
在这里插入图片描述
测试在project1名称空间下nginx-pod访问192.168.211.12:80,可以正常访问
k8s网络策略_第4张图片

测试在project1名称空间下nginx-pod访问coredns服务,解析域名失败,无法访问
k8s网络策略_第5张图片

综合示例

下面是一个综合示例,用于实现名称空间隔离。它大致实现了以下几点需求:

1.本 名称空间内的Pod可以互相访问
2. 集群上管理类应用所在名称空间中的Pod(例如日志收集、监控、dashboard等)可以访问本名称空间中的Pod
3. 本名称空间中的Pod可以访问CoreDns、Kubernetes API等必要的服务

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-networkpolicy
  namespace: project1
spec:
  policyTypes: ["Ingress", "Egress"]
  podSelector: {}	#project1名称空间下所有Pod对象
  ingress:
  - from:	#入站规则1,允许指定名称空间中的Pod访问任意端口
    - namespaceSelector:
        matchExpressions:
        - {key: "name", operator: In, values: ["kube-system", "kube-dashboard", "log", "monitor", "project1"]}
  egress:
  - to:		#出战规则1,允许访问同名称空间下Pod的任意端口
    - namespaceSelector:
        matchLabels:
          name: project1
  - to: []	#出站规则2,允许访问任何端点的UDP 53端口,DNS服务
    ports:
    - port: 53
      protocol: UDP
  - to:		#出站规则3,允许访问kube-apierver
    - podSelector:
        matchLabels:
          component: kube-apiserver
      namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: kube-system
    ports:
    - port: 443
      protocol: TCP

你可能感兴趣的:(kubernetes)