云原生|kubernetes|networkPolicy网络策略详解

前言:

networkPolicy是kubernetes集群的一个重要安全特性。顾名思义,网络策略,控制网络流量的一个资源。

那么,kubernetes集群的网络是由docker虚拟网卡,cni网络插件,flannel网络插件(也可能会使用calico,weaver等等其它网络插件)这些模块组成的。

主要还是基于Linux内核层面的iptables或者ipvs通过上述的网络插件使得整个集群的网络成为网络层次有若干个子网的,内部是可以跨节点,跨子网段的一个整体网络。

例如,我有一个kubeadm部署的集群,集群内部网络如下:

两个子网段,10.244.36 和10.244.169

root@k8s-master:~# kubectl get po -A -owide
NAMESPACE       NAME                                       READY   STATUS    RESTARTS         AGE     IP                NODE         NOMINATED NODE   READINESS GATES
a               a                                          1/1     Running   1 (5m27s ago)    13h     10.244.36.76      k8s-node1    <none>           <none>
b               b                                          1/1     Running   1 (5m27s ago)    13h     10.244.36.69      k8s-node1    <none>           <none>
default         busybox                                    1/1     Running   0                49s     10.244.36.79      k8s-node1    <none>           <none>
default         front-end-5f64577768-tsq76                 1/1     Running   14 (5m27s ago)   9d      10.244.36.75      k8s-node1    <none>           <none>
default         guestbook-86bb8f5bc9-2nk6c                 1/1     Running   13 (5m27s ago)   8d      10.244.36.82      k8s-node1    <none>           <none>
default         guestbook-86bb8f5bc9-2xrh6                 1/1     Running   13 (5m27s ago)   8d      10.244.36.78      k8s-node1    <none>           <none>
default         guestbook-86bb8f5bc9-78pq5                 1/1     Running   13 (5m27s ago)   8d      10.244.36.73      k8s-node1    <none>           <none>
default         guestbook-86bb8f5bc9-m4wr4                 1/1     Running   14 (5m21s ago)   9d      10.244.169.153    k8s-node2    <none>           <none>
default         guestbook-86bb8f5bc9-pkzpl                 1/1     Running   14 (5m21s ago)   9d      10.244.169.152    k8s-node2    <none>           <none>
default         guestbook-86bb8f5bc9-sq4xf                 1/1     Running   13 (5m21s ago)   8d      10.244.169.155    k8s-node2    <none>           <none>
剩下的略略略

OK,此时在集群内部启动一个临时的pod,以上的集群内部IP是都可以ping通的:

kubectl run busybox -it --rm  --image=busybox -- /bin/sh
/ # ping 10.244.36.80 -c 2
PING 10.244.36.80 (10.244.36.80): 56 data bytes
64 bytes from 10.244.36.80: seq=0 ttl=63 time=0.119 ms
64 bytes from 10.244.36.80: seq=1 ttl=63 time=0.129 ms

--- 10.244.36.80 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.119/0.124/0.129 ms
ping 10.244.169.147 -c 2
PING 10.244.169.147 (10.244.169.147): 56 data bytes
64 bytes from 10.244.169.147: seq=0 ttl=62 time=0.737 ms
64 bytes from 10.244.169.147: seq=1 ttl=62 time=0.802 ms

那就说明了一个问题,kubernetes集群的网络是一个自由的,无任何限制的网络,很显然,这样的网络是没有安全性可言的,因为,任意一个pod都可以连接到其它的pod,那么,如果有某一个不受控制的黑客部署的pod在集群内,不是非常的不安全吗?

其实说了这么多,基于网络插件比如calico的networkPolicy会对集群内的网络做一个细粒度的控制,例如,控制某类带有特定标签的pod能够访问其它的指定的pod,简单的说人话就是能够做一定的网络隔离。

Kubernetes提供了NetworkPolicy,支持按Namespace和按Pod级别的网络访问控制。它利用label指定namespaces或pod,底层用iptables实现。不是所有的 Kubernetes 网络方案都支持 Network Policy。比如 Flannel 就不支持,Calico 是支持的。

例如,calico网络方案的networkPolicy工作流程是这样的:

 a.通过kubectl client创建network policy资源;
 b.calico的policy-controller监听network policy资源,获取到后写入calico的etcd数据库;
 c.node上calico-felix从etcd数据库中获取policy资源,调用iptables做相应配置。

使用network policy资源可以配置pod的网络,networkPolicynamespace scoped的,他只能影响某个namespace下的pod的网络出入站规则。 

你首先需要有一个支持网络策略的 Kubernetes 集群。已经有许多支持 NetworkPolicy 的网络提供商,包括:




一,

ingress和egress

ingress 表示进口流量,egress表示出口流量,入口流量和出口流量都是相对networkPolcy所指定的namespace来说的,例如下面这个policy:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: access-nginx
spec:
  podSelector:
    matchLabels:
      app: nginx
  ingress:
  - from:
    - podSelector:
        matchLabels:
          access: "true"

以上这个policy意思是所有具有标签 access=true的pod才可以访问namespace为default的所有具有pod 标签 app=nginx的pod

OK,此时查看default这个命名空间下的所有pod的具有app=nginx的pod:

root@k8s-master:~# kubectl get po -owide --show-labels |grep nginx
nginx-6799fc88d8-ktjxh                    1/1     Running   5 (80m ago)    8d      10.244.169.140   k8s-node2    <none>           <none>            access=true,app=nginx,pod-template-hash=6799fc88d8
nginx-kusc0041                            1/1     Running   11 (80m ago)   12d     10.244.169.141   k8s-node2    <none>           <none>            run=nginx-kusc0041
task-2-ds-fcm5l                           1/1     Running   13 (80m ago)   14d     10.244.235.193   k8s-master   <none>           <none>            controller-revision-hash=688c88fb84,nginx=task-2-ds,pod-template-generation=1
task-2-ds-nwdlv                           1/1     Running   19 (80m ago)   18d     10.244.169.135   k8s-node2    <none>           <none>            controller-revision-hash=688c88fb84,nginx=task-2-ds,pod-template-generation=1
task-2-ds-pmlqw                           1/1     Running   19 (80m ago)   18d     10.244.36.81     k8s-node1    <none>           <none>            controller-revision-hash=688c88fb84,nginx=task-2-ds,pod-template-generation=1

此时,带标签access=true的pod可以访问140,如果不带access=true,将不可以访问140

不带标签的时候:

kubectl run test -it --rm --image=busybox  -- /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget 10.244.169.141
Connecting to 10.244.169.141 (10.244.169.141:80)
saving to 'index.html'
index.html           100% |***************************************************************************************************************************************|   615  0:00:00 ETA
'index.html' saved
/ # wget 10.244.169.140
Connecting to 10.244.169.140 (10.244.169.140:80)
^C

带符合的标签的时候:

root@k8s-master:~# kubectl run test -it --rm --image=busybox --labels="access=true" -- /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget 10.244.169.140
Connecting to 10.244.169.140 (10.244.169.140:80)
saving to 'index.html'
index.html           100% |***************************************************************************************************************************************|   615  0:00:00 ETA
'index.html' saved

 那么,有一点需要注意了,podSelector 前面加  -号和 不加-号的,如有-号表示范围扩大,这个时候是两个条件任意一个符合即可(逻辑关系是或)。如无-号表示精确匹配pod的label标签(逻辑关系是与),还是以上面的例子为例:

无减号,表示精确的匹配

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: access-nginx
spec:
  podSelector:
    matchLabels:
      app: nginx
  ingress:
  - from:
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          access: "true"

有减号,表示或者,范围匹配

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: access-nginx
spec:
  podSelector:
    matchLabels:
      app: nginx
  ingress:
  - from:
    - namespaceSelector: {}
    - podSelector:
        matchLabels:
          access: "true"

二,

实验1:

创建一个networkPolicy,使得名为a的namespace内的pod全部隔离,只有具有标签 access=true的pod才可以访问a namespace内的其它pod

网络策略未创建前:

OK,先创建名为a的namespace,并且在该namespace内创建两个都使用nginx镜像的名称分别为nginx1和nginx2

kubectl create ns a
kubectl run nginx1 --image=nginx -n a
kubectl run nginx2 --image=nginx -n a

查看pod的状态,可以看到有绑定两个IP,分别是10.244.36.86,10.244.36.96

root@k8s-master:~# kubectl get po -n   a  -owide 
NAME     READY   STATUS    RESTARTS       AGE     IP             NODE        NOMINATED NODE   READINESS GATES
nginx1   1/1     Running   1 (123m ago)   4h39m   10.244.36.86   k8s-node1   <none>           <none>
nginx2   1/1     Running   0              97m     10.244.36.96   k8s-node1   <none>           <none>

OK,这个时候我们进入nginx1,看看a 这个namespace内的pod是否互相隔离:

进入pod的命令:

kubectl exec -it po -n a nginx1 -- /bin/sh

可以发现,两个pod之间是可以直接互相访问的,没有任何的阻碍,当然了,其它的namespace内的pod也是没有任何阻碍的可以访问到

# curl 10.244.36.96
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
# curl 10.244.36.86
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>

网络策略创建后:

root@k8s-master:~# cat test.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: access-nginx
  namespace: a
spec:
  podSelector: {}
  ingress:
  - from:
    - podSelector:
        matchLabels:
          access: "true"

OK,这个网络策略表示名为a的namespace内的所有pod互相直接隔离,只有具有access=true的pod才可以访问a 这个namespace内的其它的pod。

上述文件执行后,此时,在进入nginx1,可以发现无法访问nginx2了:

# curl 10.244.36.96        
^C

但可以自由的访问其它的namespace内的pod,证明网络策略的作用范围只在a 这个namespace内:

root@k8s-master:~# kubectl get po -A -owide |grep  10.244.169.151
default         nginx-6799fc88d8-ktjxh                     1/1     Running   2 (141m ago)    22h     10.244.169.151    k8s-node2    <none>           <none>
curl 10.244.169.151
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }

OK,现在给nginx1增加符合网络策略进入策略的标签acces=true,然后登陆nginx1,再次访问nginx2,可以发现可以正常访问了:

给nginx1添加标签:

kubectl label po -n a nginx1 access=true

root@k8s-master:~# kubectl get po -n a nginx1 --show-labels 
NAME     READY   STATUS    RESTARTS       AGE    LABELS
nginx1   1/1     Running   1 (152m ago)   5h8m   access=true,run=nginx1

再次访问,可以发现恢复正常了,证明网络策略是生效了。 

# curl 10.244.36.96
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>

由以上实验我们可以得出一个结论:

1,namespace是networkPolicy的作用域

2,from表示方向,因此,上面的例子,标签是打在了nginx1,然后登陆的nginx1,那么,如果标签打到了nginx2上,就需要使用nginx2访问nginx1了。

三,

实验2

某个namespace(这里还是使用a这个namespace),拒绝所有的入站流量和出站流量

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: a
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

此时,在default这个namespace里有一个nginx,登陆这个pod,可以发现a这个namespace里的所有pod都无法访问了:

root@k8s-master:~# kubectl get po -owide
NAME                                      READY   STATUS    RESTARTS         AGE     IP               NODE         NOMINATED NODE   READINESS GATES
busybox                                   1/1     Running   1 (3h12m ago)    7h25m   10.244.36.105    k8s-node1    <none>           <none>
front-end-5f64577768-tsq76                1/1     Running   15 (3h12m ago)   10d     10.244.36.99     k8s-node1    <none>           <none>
nfs-client-provisioner-56dd5765dc-9z772   1/1     Running   30 (3h12m ago)   10d     10.244.169.162   k8s-node2    <none>           <none>
nginx-6799fc88d8-ktjxh                    1/1     Running   2 (3h12m ago)    23h     10.244.169.151   k8s-node2    <none>           <none>
root@k8s-master:~# kubectl exec -it -n default nginx-6799fc88d8-ktjxh -- /bin/sh
# curl 10.244.36.96
curl: (28) Failed to connect to 10.244.36.96 port 80: Connection timed out

猜你喜欢

转载自blog.csdn.net/alwaysbefine/article/details/128418087