22-K8S Basic-Network Policy应用

一、网络策略

1.1、Kubernetes网络策略介绍

  • 网络策略(Network Policy )是 Kubernetes 的一种资源。Network Policy 通过 Label 选择 Pod,并指定其他 Pod 或外界如何与这些 Pod 通信。
  • Pod的网络流量包含流入(Ingress)和流出(Egress)两种方向。默认情况下,所有 Pod 是非隔离的,即任何来源的网络流量都能够访问 Pod,没有任何限制。当为 Pod 定义了 Network Policy,只有 Policy 允许的流量才能访问 Pod。
  • Kubernetes的网络策略功能也是由第三方的网络插件实现的,因此,只有支持网络策略功能的网络插件才能进行配置网络策略,比如Calico、Canal、kube-router等等。
  • PS:Kubernetes自1.8版本才支持Egress网络策略,在该版本之前仅支持Ingress网络策略。

1.2、部署Cancal提供网络策略功能

  • calico官网 :https://www.projectcalico.org/
  • 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。
#设置RBAC
[root@k8s-master ~]# kubectl apply -f https://docs.projectcalico.org/v3.2/getting-started/kubernetes/installation/hosted/canal/rbac.yaml
 
#部署Canal提供网络策略
[root@k8s-master ~]# kubectl apply -f https://docs.projectcalico.org/v3.2/getting-started/kubernetes/installation/hosted/canal/canal.yaml
 
[root@k8s-master ~]# kubectl get ds canal -n kube-system
NAME      DESIRED   CURRENT   READY     UP-TO-DATE   AVAILABLE   NODE SELECTOR                 AGE
canal     3         3         0         3            0           beta.kubernetes.io/os=linux   2m
 
部署canal需要的镜像,建议先拉取镜像,避免耗死资源:
quay.io/calico/node:v3.2.6
quay.io/calico/cni:v3.2.6
quay.io/coreos/flannel:v0.9.1
 
[root@k8s-master ~]# kubectl get pods -n kube-system -o wide |grep canal
canal-2hqwt                            3/3       Running        0          1h        192.168.56.11   k8s-master
canal-c5pxr                            3/3       Running        0          1h        192.168.56.13   k8s-node02
canal-kr662                            3/3       Running        6          1h        192.168.56.12   k8s-node01
  • Canal作为DaemonSet部署到每个节点,属于kube-system这个名称空间。需要注意的是,Canal只是直接使用了Calico和flannel项目,代码本身没有修改,Canal只是一种部署的模式,用于安装和配置项目。

1.3、配置网络策略

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

image

  • 默认情况下,Pod对象的流量控制是为空的,报文可以自由出入。在附加网络策略之后,Pod对象会因为NetworkPolicy而被隔离,一旦名称空间中有任何NetworkPolicy对象匹配了某特定的Pod对象,则该Pod将拒绝NetworkPolicy规则中不允许的所有连接请求,但是那些未被匹配到的Pod对象依旧可以接受所有流量。
  • 就特定的Pod集合来说,入站和出站流量默认是放行状态,除非有规则可以进行匹配。还有一点需要注意的是,在spec.policyTypes中指定了生效的规则类型,但是在networkpolicy.spec字段中嵌套定义了没有任何规则的Ingress或Egress时,则表示拒绝入站或出站的一切流量。定义网络策略的基本格式如下:
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 ["Ingress"]               #NetworkPolicy类型,可以是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
   
# 该网络策略就是将default名称空间中拥有标签"app=myapp"的Pod资源开放80/TCP端口给10.244.0.0/16网段,并排除10.244.3.0/24网段的访问,并且也开放给标签为app=myapp的所有Pod资源进行访问。
  • 为了看出Network Policy的效果,先部署一个httpd的应用。配置清单文件如下:
[root@k8s-master ~]# mkdir network-policy-demo
[root@k8s-master ~]# cd network-policy-demo/
[root@k8s-master network-policy-demo]# vim httpd.yaml
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: httpd
spec:
  replicas: 3
  template:
    metadata:
      labels:
        run: httpd
    spec:
      containers:
      - name: httpd
        image: httpd:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
 
---
apiVersion: v1
kind: Service
metadata:
  name: httpd-svc
spec:
  type: NodePort
  selector:
    run: httpd
  ports:
  - protocol: TCP
    nodePort: 30000
    port: 8080
    targetPort: 80
  • 创建三个副本,通过NodePort类型的Service对外方服务,部署应用:
[root@k8s-master network-policy-demo]# kubectl apply -f httpd.yaml
deployment.apps/httpd unchanged
service/httpd-svc created
[root@k8s-master network-policy-demo]# kubectl get pods -o wide |grep httpd
httpd-75f655479d-882hz                1/1       Running    0          4m        10.244.0.2     k8s-master
httpd-75f655479d-h7lrr                1/1       Running    0          4m        10.244.2.2     k8s-node02
httpd-75f655479d-kzr5g                1/1       Running    0          4m        10.244.1.2     k8s-node01
 
[root@k8s-master network-policy-demo]# kubectl get svc httpd-svc
NAME        TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
httpd-svc   NodePort   10.99.222.179   <none>        8080:30000/TCP   4m
  • 当前没有定义任何Network Policy,验证应用的访问:
#启动一个busybox Pod,可以访问Service,也可以ping副本的Pod
 
[root@k8s-master ~]# kubectl run busybox --rm -it --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget httpd-svc:8080
Connecting to httpd-svc:8080 (10.99.222.179:8080)
index.html           100% |*********************************************************************************************|    45  0:00:00 ETA
/ # ping -c 2 10.244.1.2
PING 10.244.1.2 (10.244.1.2): 56 data bytes
64 bytes from 10.244.1.2: seq=0 ttl=63 time=0.507 ms
64 bytes from 10.244.1.2: seq=1 ttl=63 time=0.228 ms
 
--- 10.244.1.2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.228/0.367/0.507 ms
 
 
#集群节点也可以访问Sevice和ping通副本Pod
[root@k8s-node01 ~]# curl 10.99.222.179:8080
<html><body><h1>It works!</h1></body></html>
[root@k8s-node01 ~]# ping -c 2 10.244.2.2
PING 10.244.2.2 (10.244.2.2) 56(84) bytes of data.
64 bytes from 10.244.2.2: icmp_seq=1 ttl=63 time=0.931 ms
64 bytes from 10.244.2.2: icmp_seq=2 ttl=63 time=0.812 ms
 
--- 10.244.2.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.812/0.871/0.931/0.066 ms
 
#集群外部访问192.168.56.11:30000也是通的
[root@localhost ~]# curl 192.168.56.11:30000
<html><body><h1>It works!</h1></body></html>
  • 下面再去设置不同的Network Policy来管控Pod的访问。

1.4、管控入站流量

  • NetworkPolicy资源属于名称空间级别,它的作用范围为其所属的名称空间。

1.4.1、设置默认ingress策略

  • 用户可以创建一个NetworkPolicy来为名称空间设置一个默认的隔离策略,该策略选择所有的Pod对象,然后允许或拒绝任何到达这些Pod的入站流量,如下:
[root@k8s-master network-policy-demo]# vim policy-demo.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-ingress
spec:
  podSelector: {}
  policyTypes: ["Ingress"] 
  #指明了Ingress生效规则,但不定义任何Ingress字段,因此不能匹配任何源端点,从而拒绝所有的入站流量
 
[root@k8s-master network-policy-demo]# kubectl apply -f policy-demo.yaml
networkpolicy.networking.k8s.io/deny-all-ingress created
[root@k8s-master network-policy-demo]# kubectl get networkpolicy
NAME               POD-SELECTOR   AGE
deny-all-ingress   <none>         11s
 
#此时再去访问测试,是无法ping通,无法访问的
[root@k8s-master ~]# kubectl run busybox --rm -it --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget httpd-svc:8080
Connecting to httpd-svc:8080 (10.99.222.179:8080)
wget: can't connect to remote host (10.99.222.179): Connection timed out
  • 如果要将默认策略设置为允许所有入站流量,只需要定义Ingress字段,并将这个字段设置为空,以匹配所有源端点,但本身不设定网络策略,就已经是默认允许所有入站流量访问的,下面给出一个定义的格式:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-ingress
spec:
  podSelector: {}
  policyTypes: ["Ingress"]
  ingress:
  - {}
 
# 实践中,通常将默认的网络策略设置为拒绝所有入站流量,然后再放行允许的源端点的入站流量。

1.4.2、放行特定的入站流量

[root@k8s-master network-policy-demo]# vim policy-demo.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: access-httpd
spec:
  podSelector:
    matchLabels:
      run: httpd
  policyTypes: ["Ingress"]
  ingress:
  - from:
    - ipBlock:
        cidr: 10.244.0.0/16
        except:
        - 10.244.2.0/24
        - 10.244.1.0/24
    - podSelector:
        matchLabels:
          access: "true"
    ports:
    - protocol: TCP
      port: 80
 
[root@k8s-master network-policy-demo]# kubectl apply -f policy-demo.yaml
networkpolicy.networking.k8s.io/access-httpd created
[root@k8s-master network-policy-demo]# kubectl get networkpolicy
NAME           POD-SELECTOR   AGE
access-httpd   run=httpd      6s
 
 
# 验证NetworkPolicy的有效性:
#创建带有标签的busybox pod访问,是可以正常访问的,但是因为仅开放了TCP协议,所以PING是无法ping通的
[root@k8s-master ~]# kubectl run busybox --rm -it --labels="access=true" --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget httpd-svc:8080
Connecting to httpd-svc:8080 (10.99.222.179:8080)
index.html           100% |*********************************************************************************************|    45  0:00:00 ETA
/ # ping -c 3 10.244.0.2
PING 10.244.0.2 (10.244.0.2): 56 data bytes
 
--- 10.244.0.2 ping statistics ---

1.5、管控出站流量

  • 通常,出站的流量默认策略应该是允许通过的,但是当有精细化需求,仅放行那些有对外请求需要的Pod对象的出站流量,也可以先为名称空间设置“禁止所有”的默认策略,再细化制定准许的策略。networkpolicy.spec中嵌套的Egress字段用来定义出站流量规则。

1.5.1、设置默认ingress策略

  • 和Igress一样,只需要通过policyTypes字段指明生效的Egress类型规则,然后不去定义Egress字段,就不会去匹配到任何目标端点,从而拒绝所有的出站流量。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-egress
spec:
  podSelector: {}
  policyTypes: ["Egress"]
 
 
# 实践中,需要进行严格隔离的环境通常将默认的策略设置为拒绝所有出站流量,再去细化配置允许到达的目标端点的出站流量。

1.5.2、放行特定的出站流量

  • 下面举个例子定义一个Egress规则,对标签run=httpd的Pod对象,到达标签为access=true的Pod对象的80端口的流量进行放行。
[root@k8s-master network-policy-demo]# vim egress-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: httpd-egress
spec:
  podSelector:
    matchLabels:
      run: httpd
  policyTypes: ["Egress"]
  egress:
  - to:
    - podSelector:
        matchLabels:
          access: "true"
    ports:
    - protocol: TCP
      port: 80
 
 
#NetworkPolicy检测,一个带有access=true标签,一个不带
[root@k8s-master ~]# kubectl run busybox --rm -it --labels="access=true" --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget httpd-svc:8080
Connecting to httpd-svc:8080 (10.99.222.179:8080)
index.html           100% |*********************************************************************************************|    45  0:00:00 ETA
/ # exit
Session ended, resume using 'kubectl attach busybox-686cb649b6-6j4qx -c busybox -i -t' command when the pod is running
deployment.apps "busybox" deleted
 
[root@k8s-master ~]# kubectl run busybox2 --rm -it --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget httpd-svc:8080
Connecting to httpd-svc:8080 (10.99.222.179:8080)
wget: can't connect to remote host (10.99.222.179): Connection timed out
 

# 从上面的检测结果可以看到,带有标签access=true的Pod才能访问到httpd-svc,说明上面配置的Network Policy已经生效。

1.6、隔离名称空间

  • 实践中,通常需要彼此隔离所有的名称空间,但是又需要允许它们可以和kube-system名称空间中的Pod资源进行流量交换,以实现监控和名称解析等各种管理功能。下面的配置清单示例在default名称空间定义相关规则,在出站和入站都默认均为拒绝的情况下,它用于放行名称空间内部的各Pod对象之间的通信,以及和kube-system名称空间内各Pod间的通信。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: namespace-deny-all
  namespace: default
spec:
  policyTypes: ["Ingress","Egress"]
  podSelector: {}
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: namespace-allow
  namespace: default
spec:
  policyTypes: ["Ingress","Egress"]
  podSelector: {}
  ingress:
  - from:
    - namespaceSelector:
        matchExpressions:
        - key: name
          operator: In
          values: ["default","kube-system"]
  egress:
  - to:
    - namespaceSelector:
        matchExpressions:
        - key: name
          operator: In
          values: ["default","kube-system"]
  • 需要注意的是,有一些额外的系统附件可能会单独部署到独有的名称空间中,比如将prometheus监控系统部署到prom名称空间等,这类具有管理功能的附件所在的名称空间和每一个特定的名称空间的出入流量也是需要被放行的。
posted @ 2021-05-16 20:23  SRE运维充电站  阅读(114)  评论(0编辑  收藏  举报