《kubernetes in action》学习笔记——13、保障集群内节点和网络安全(SecurityContext PodSecurityPolicy NetworkPolicy)

(本文章是学习《kubernetes in action》 一书时做的笔记,由于本人是刚学习k8s,且自学方式就是把它敲一遍,然后加一些自己的理解。所以会发现很多内容是跟书中内容一模一样,如果本文是对本书的侵权,敬请谅解,告知后会删除。如果引用或转载,请注明出处——谢谢)

一、在pod中使用宿主节点的Linux命名空间

每一个pod拥有自己的IP和端口空间,因为他们有自己的网络命名空间
每一个pod拥有自己的进程树,因为它有自己的PID命名空间
每一个pod拥有自己的IPC命名空间,仅允许同一个pod内的进程通过进程间通信机制交流

在pod使用宿主节点的网络命名空间
可以再pod spec 中的hostNetwork设置为tree,从而共享宿主机的网络命名空间,这也意味着该pod没有自己的IP地址。

...
spec:
    hostNetwork: tree
    containers:
    - name: xxx
      image: xxx    

绑定宿主节点上的端口而不是使用宿主节点的网络命名空间
将pod端口绑定到宿主机的某一个端口,可以通过配置pod的spec.containers.ports 字段中某个容器某一个端口的hostPort属性来实现。
需要注意的是与NodePort service 服务暴露的pod进行区别,使用hostPort时,到达宿主节点的端口连接会直接被转发到pod对应的端口上。而在NodePort服务暴露中,到达宿主节点的端口连接会被随机转发到被选取的pod。
另一个区别是,使用了hostPort的pod,仅有运行了该类pod的节点会绑定对应的端口,而NodePode类型的服务会在所有的节点上绑定端口,即使这个节点上没有pod运行。

还有一个要注意的是使用了hostPod的pod,在一个节点上只能运行一个该类pod,因为两个pod不能同时绑定到宿主机上的同一个端口。

...
spec:
  containers:
  - name: xxx
    imange: xxx
    - containerPort: 8080  // 容器的端口
      hostPod: 9000  // 绑定到宿主机上的端口
      protocol: TCP 

最初hostPod功能是用于暴露用过DaemonSet部署在每个节点上的系统服务,从而保证一个pod的副本不会被调用到同一个节点,但是后面有更好的机制来实现该需求。

使用宿主节点的PID和IPC命名空间
pod spec中的hostPID和hostIPC选项与hostNetwork相似,当它们被设置成tree时,pod中的容器将使用宿主节点的PID和IPC命名空间,分别允许它们看到宿主机上的全部进程,或通过IPC与宿主节点上的进程进行通信

apiVersion: v1
kind: Pod
metadata:
  name: xxx
spec:
  hostPID: true
  hostIPC: true
  containers:
  - name: xxx
   iamge: xxx     

通常容器只能看到内容的进程,但这个pod可以列出宿主机上的所有进程。

二、配置节点的安全上下文

除了让pod使用宿主节点的Linux命名空间,还可以在pod或其所属容器的描述中通过security-context选项配置其他安全相关的特性,这个选项可以运用于整个pod,或者每个pod中的单独容器。

安全上下文可以配置的内容:

  • 指定容器运行进程的用户(用户ID)
  • 阻止容器用root用户启动(容器的默认运行用户通常可以在其镜像中指定,所以可能需要阻止容器以root用户运行)
  • 使用特权模式运行容器,使其对宿主节点的内核具有完全的访问权限
  • 与上相反,通过添加禁用内核功能,配置细粒度的内核访问权限
  • 设置SELinux选项,加强对容器的限制
  • 阻止进程写入容器的根文件系统

运行pod而不配置安全上下文
可以通过 kubectl exec podname id 查看没有任何安全上下文配置的pod
可以看到这个容器在用户ID(UID)为0的用户,即root用户,用户组ID(gid)为0(同样是root)的用户组下运行。同样它还属于一些其他的用户组
注意:容器运行时使用的用户是在镜像中指定,在Dockerfile中,是通过使用USER命令实现的,如果该命令被忽略,容器将使用root用户运行。

使用指定用户来运行容器
为了使用一个与镜像中不同的用户ID来运行pod,需要设置该pod的securityContext.runAsUser 选项

apiVersion: v1
kind: Pod
metadata:
  name: xxx
spec:
  containers:
  - name: xxx
    image: alpine
    command: ["/bin/sleep", "9999"]    
    securityContext:
      runAsUser: 405    // 需要的是用户ID,而不是用户名(ID 405对应guest用户)  

kubectl exec podname id 查看结果 uid=405(guest) gid=100(users)

阻止容器以root用户运行
如果攻击者获取了访问镜像仓库的权限,并上传一个标签一样的镜像,并以root用户运行。kubernetes的调度器运行该pod实例,kubelet会拉取攻击者的镜像,并运行该镜像中的任何代码。
虽然容器与宿主节点基本上是隔离的,使用root用户运行容器中的进程然然是不好的实践。例如,当宿主节点上的一个目录被挂载到容器中,如果该容器使用了root用户运行,那它就用于该目录的所有权限,如果是非root用户运行,它就只有部分权限。

apiVersion: v1
kind: Pod
metadata:
  name: xxx
spec:
  containers:
  - name: xxx
    image: alpine
    command: ["/bin/sleep", "9999"]
    securityContext:
      runAsNonRoot: true    

使用特权模式运行pod
有时pod需要做它们的宿主节点上能够做的任何事情,例如操作被保护的系统设备,或使用其他通常容器中不能使用的内核功能。
这种pod的一个例子就是kube-proxy,该pod需要修改主机的iptables 规则来让kubernetes中服务规则生效。为获取宿主机完整的内核权限,该pod需要在特权模式下运行,可以将容器的securityContext中的privileged设置为true实现

apiVersion: v1
kind: pod
metadata:
  name: xxx
spec:
  containers:
  - name: xxx
    image: alpine
    command: ["/bin/sleep", "9999"]
    securityContext:
      privileged: true  // 指定给容器在特权模式下运行    

部署该pod,可以跟没有使用特权模式运行的pod进行对比。
可以通过查看/dev 这个目录进行对比(或其他的方式也可以,只要能体现不一样就行)
进入在非特权模式下运行的pod中,ls /dev 可以看到一个比较短的列表
进入以特权模式运行的pod中,ls /dev 可以看到一个很长的列表,其中就包含了宿主节点上所有的设备。这也意味着它可以自由使用任何设备。
举个例子,如果要再一个树莓派上运行一个pod,用这个pod来控制相连的LED, 那么必须使用特权模式来运行该pod。

为容器单独添加内核功能
传统的Linux值区分特权和非特权进程,但是经过多件的发展,Linux已经可以通过内核功能支持更细粒度的权限系统。
相对于让容器在特权模式下给予所有的权限,一个更加安全的做法是给予它需要的内核功能特权,kubernetes允许为特定的容器添加内核功能,或禁用部分内核功能,以允许容器进行更加精细的权限控制,限制攻击者潜在的影响。
例如,一个容器是不允许修改系统时间的(硬件时钟的时间)。可以通过在一个非特权模式运行的pod中来实验。会发现提示没有权限修改。
如果需要容器修改系统时间,可以再容器的capabilities 里add一项名为CAP_SYS_TIME的功能

apiVersion: v1
kind: Pod
metadata:
  name: xxx
spec:
  containers:
  - name: xxx
    image: alpine
    commadn: ["/bin/sleep", "9999"]
    securityContext:
        capabilities:
            add:
            - SYS_TIME    

此时就可在pod中修改系统时间了
注意:Linux内核功能的名称通常是以CAP_开头的,但是在pod spec中指定内核功能时,必须省略CAP_前缀。
警告:自行尝试修改系统时间,可能导致节点不可用
添加指定的内核功能项,固然比使用privileged: true更好,可以在Linux手册送查看Linux内核功能列表

在容器中禁用内核功能
前面我们已经了解了如何给容器添加内核功能,同样我们可以禁用容器使用某项内核功能。例如,默认情况下容器拥有CAP_CHOWN内核功能,可以修改文件系统中文件的所有者。为阻止容器的此种行为,可以在容器的securityContext.capabilities.drop 列表中添加此项,以禁用这个修改文件所有者的内核功能。

apiVersion: v1
kind: Pod
metadata:
  name: xxx
spec:
  containers:
  - name: xxx
    image: alpine
    command: ["/bin/sleep", "9999"]    
    securityContext:
        capabilities:
            drop:
            - CHOWN    

阻止对容器根文件系统的写入
因为安全原因,你可以能需要阻止容器中的进程对容器的根文件系统进行写入,仅允许它们写入挂载的存储卷。
假如你在运行一个有隐藏的漏洞,可以允许攻击者写入文件系统的应用(使用非编译型语言编写的应用),这些应用文件在构建容器时放入容器镜像中,并且在容器根文件系统中提供服务。由于漏洞的存在,攻击者可以修改这些文件,在其中注入恶意代码。
这一类攻击可以通过阻止容器写入自己的根文件系统(应用的可执行代码通常存储的位置)来阻止。将容器的securityContext.readOnlyRootFilesystem 设置成true来实现

apiVersion: v1
kind: Pod
metadata:
  name: xxx
spec:
  containers:
  - name: xxx
    image: alpine
    command: ["/bin/sleep", "9999"]   
    securityContext:  
      readOnlyRootFilesystem: true  // 设置禁止修改容器的根文件系统
    volumeMounts:
    - name: my-volume
      mountPath: /volume
      readOnly: false  // 运行写入挂载卷
  volumes:
  - name: my-volume
    emptyDir:    
     

实验
kubectl exec -it podname touch /new-file // 会提示Read-only file system
kubectl exec -it podname touch /volume/newfile
kubectl exec -it podname – ls -la /volumenewfile // 可以看到创建成功了

如上例子,如果容器的根文件系统是只读的,那很可能要为应用程序会写入的每一个目录(如日志、磁盘缓存)挂载一个数据卷了
提示:为了增强安全性,建议生产环境中容器的readOnlyRootFilesystem设置成true

设置pod级别的安全上下文
上的例子都可以单独对容器的安全上下文进行设置。这些选项中的一部分也可以从pod级别进行设置,可设置pod.spec.securityContext 属性进行设置。它们会作为pod中每一个容器的安全上下文,但是会被容器的安全上下文所覆盖。下面来介绍一些pod级别独有的安全上下文属性。

容器使用不同用户运行时共享存储卷
在pod中不同的容器可以共享一个挂载存储卷,在一个容器中写,在另外一个容器中读。但这是因为两个容器都是以root用户运行的,拥有存储卷中文件的所有权限。如果使用了runAsUser选项。可能要在一个pod中用两个不同的用户来运行两个容器了(可能是一个第三方的容器,需要以它们特定的用户来运行进程),如果这样两个容器共享同一个存储卷,它们并不一定能读写另一个容器的文件。
因此,kubernetes允许为pod中所有的容器指定 supplemental组,以允许它们无论以哪个用户ID运行都可以共享文件,可以通过以下两个属性进行设置:

  • fsGroup
  • supplementalGroups
apiVersion: v1
kind: Pod
metadata:
  name: xxx
spec:
  securityContext:
    fsGroup: 555
    supplementalGroups: [666, 777]   
  containers:
  - name: c1
    image: alpine
    command: ["/bin/sleep", "9999"]  
    volumeMounts:
    - name: shared-volume
      mountPath: /volume
      readOnly: false
    securityContext:
      runAsUser: 1111
  - name: c2
    image: alpine
    command: ["/bin/sleep", "9999"]
    securityContext:
      runAsUser: 2222
    volumeMounts: 
      -name: shared-volume
       mountPath: /volume
       readOnly: false
  volumes:
  - name: shared-volume
    emptyDir:      

查看容器信息

kubectl  exec -it podname -c c1 sh 
$ id
uid=1111 gid=0(root) groups=555,666,777
$ ls -l / grep volume
total 4
-rw-r--r--    1 1111    555  ...

可以看到该容器以ID为 1111的用户运行,用户组为0(root),但同时555,666,777的用户组也关联到了该用户下。在pod中定义fsGroup为555,所以挂载的存储卷属于用户组ID为555的

此时在/volume 目录下创建一个文件,查看文件属性,该文件所属用户情况跟通常设置下的新建文件不同。在通常情况下,某一个用户创建的文件所属的用户组ID,应该与创建用户的所属组ID一致,在这种情况下应该为0。在这个容器的根文件系统创建一个文件,可以验证这一点。
由此可见,安全上下文中的fsGroup属性当进程在存储卷中创建文件时起到了作用,而supplemental属性定义了某个用户所关联的额外的用户组。

三、限制pod使用安全相关的特性

在上面已经介绍了如何在部署一个pod时在一个宿主节点上做任何想做的事情,很明显要有一种机制来限制用户使用其中部分功能,集群管理员可以使用 PodSecurityPolicy资源来限制对以上安全相关的特性的使用。

PodSecurityPolicy 资源介绍
PodSecurityPolicy是一种集群资源(无命名空间)的资源,它定义了用户能否在pod中使用各种安全相关的特性。维护PodSecurityPolicy资源中的配置策略的工作由集成在API服务器中的PodSecurityPolicy准入插件来完成。
注意:你的集群不一定开启了PodSecurityPoicy 准入控制插件,需要开启它才行

当向API服务器发送pod资源时,PodSecurityPolicy准入控制插件会将这个pod与已经配置的PodSecurityPolicy进行校验,如果这个pod符合集群中已有的安全策略,它会被存入etcd。如果不符合将会被直接拒绝。这个插件也会根据安全策略中配置的默认值对pod进行修改。

了解PodSecurityPolicy可以做的事情
一个PodSecurityPolicy资源可以定义以下事项:

  • 是否允许pod使用宿主节点的PID、IPC和网络命名空间
  • pod允许绑定宿主节点端口
  • 容器运行时允许使用用户的ID
  • 是否允许拥有特权模式容器的pod
  • 允许添加哪些内核功能、默认使用哪些内核功能,总是禁用哪些内核功能
  • 允许使用哪些SELinux选项
  • 容器是否允许使用可写入的根文件系统
  • 允许容器在哪些文件系统组下运行
  • 允许pod使用哪些类型的存储卷

查看一个PodSecurityPolicy样例

apiVersion: extensions/v1beta1
kind: PodSecurityPolicy
metadata:
  name: default
spec:
  hostPID: false      // 禁用宿主节点的PID命名空间
  hostIPC: false      // 禁用宿主节点的IPC命名空间
  hostNetwork: false  // 禁用宿主节点的网络命名空间
  hostPorts:   // 限制容器可以绑定宿主节点的哪些端口
  - min: 10000       // 10000-110000 可以绑定
    max: 11000
  - min: 13000       // 13000-14000 可以绑定
    max: 14000
  privileged: false  // 禁止使用特权模式的容器运行
  readOnlyRootFilesystem: true  // 容器强制使用只读的根文件系统
  runAsUser:        // 以supplemental、fsGroup 
    rule: RunAsAny  // 一起允许用户使用任何的用户或用户组运行容器
  fsGroup:       
    rule: RunAsAny
  supplementalGroups:
    rule: RunAsAny
  seLinux:         // 可以使用SELinux的任何选项
    rule: RunAsAny
  volumes:         // 可以使用任何类型的存储卷
  - '*'

部署了该PodSecurityPolicy后,集群创建新的资源时将要符合该安全策略才行,比如不能使用privileged 特权模式运行容器等。

了解runAsUser、fsGroup、supplementalGroup策略
前面的例子中没有对runAsUser、fsGroup、supplementalGroup等字段进行任何限制,如果要限制容器可以使用的用户和用户组ID,可以将规则改为MustRunAs,并制定允许使用的ID范围

使用MustRunAs规则

runAsUser:
  rule: MustRunAs
  range:
  - min: 2   // min=max 可以指定一个特定的ID
    max: 2
fsGroup:
  rule: MustRunAs
  range:    // 指定了用户组ID在 2-10,20-30(包含临界值) 范围内用户组ID
  - min: 2
   max: 10
 - min: 20
   max: 30
supplementalGropus:
  rule: MustRunAs
  range:
  - min: 2
    max: 10
  - min: 20
    max: 30   

如果pod spec中任何一个字段向设置该范围以外的值,那该pod将不会被API服务器接收。
注意:PodSecurityPolicy策略对已存在的pod无效,因为PodeSecurityPolicy资源只在创建和升级pod的时候生效

部署镜像中用户ID在指定范围以外的pod
通过前面我们知道在pod spec中使用范围以外的用户ID运行,会被API服务器拒绝。如果在容器镜像文件中Dockerfile USER指定的用户ID在范围以外,此时容器能被部署,但是进入该容器中可以查看ID,会发现用户运行时使用的ID为PodSecurityPolicy策略中指定的用户ID。PodSecurityPolicy可以将编码覆盖到镜像中的用户ID。

在runAsUser字段中还可以指定另一种规则:mustRunAsNonRoot。此策略会阻止用户部署以root用户运行容器。该情况下,必须在spec中为容器指定runAsUser字段,且不能为0(0为root用户),或者在镜像中USER指定一个非0的用户ID。

配置允许、默认添加、禁止使用的内核功能
容器可以运行在特权模式下,也可以通过对每个容器添加或禁用Linux内核功能来定义更加细粒度的权限设置。以下三个字段会影响容器使用内核功能。

  • allowedCapabilities 指定容器中可以添加的内核功能
  • defaultAddCapabilities 指定容器中默认添加的内核功能
  • requiredDropCapabilities 指定容器中禁止使用的内核功能
apiVersion: extensions/v1beta1
kind: PodSecurityPolicy
metadata:
  name: xxx
spec:
  allowedCapabilities:
  - SYS_TIME    // 容器可以添加修改系统时间的内核功能
  defaultAddCapabilities:
  - CHOWN       // 容器默认添加可以修改文件所属者的内核功能
  requiredDropCapabilities
  - SYS_ADMIN  // 容器禁用SYS_ADMIN、SYS_MODULE 内核功能
  - SYS_MODULE
  ...   

注意:SYS_ADMIN 功能允许使用一系列的管理操作,SYS_MODULE功能允许加载或卸载内核模块

defaultAddCapabilities 字段中列出的所有内核功能将添加到每个pod的每个容器中。如果用户希望某个容器不能使用其中某个内核功能,必须在容器的spec中显示禁用该内核功能。

requiredDropCapabilities字段中列出的所有禁用的内核功能,用户如果在SecurityContext.capabilities.add 字段中添加了该字段中的内核功能,将会被API服务器拒绝。PodSecurityPolicy访问控制插件将会每一个容器的SecurityContext.Capabilities.drop 字段中加入这些功能。

限制pod可以使用的存储类型
PodSecurityPolicy 可以定义用户再pod中使用哪些存储卷类型。但最低限度上,一个PodSecurityPolicy应该允许pod使用以下类型的存储卷:emptyDir、configMap、secret、downwardAPI、persistentVolumeClaim。

kind: PodSecurityPolicy
spec:
  volumes:
  - emptyDir
  - configMap
  - secret
  - downwardAPI
  - persistenVolumeClaim    

如果有多个PodSecurityPolicy资源,pod可以使用PodSecurityPolicy中任何一个存储卷类型,实际生效的是所有volume列表的合集

对不同的用户或用户组分配不同的PodSecurityPolicy
PodSecurityPolicy是集群级别的资源,它不属于存储或使用在某一个特定的命名空间上。这是否意味着它总是会应用在所有的命名空间上呢?不是的,因为这样会使得它们相当难用。毕竟系统pod需要允许做一些常规pod不应当做的事情。
对不同的用户或组分配不同的PodSecurityPolicy是通过RBAC机制来实现的。创建你需要的PodSecurityPolicy资源,然后创建ClusterRole资源,并通过名称将它们指向不同的策略,一次使PodSecurityPolicy资源中的策略对不同的用户或组生效。通过ClusterRoleBinding资源将特定的用户或组绑定到ClusterRole上,当PodSecurityPolicy访问控制插件需要决定是否接纳一个pod时,它只会考虑创建pod的用户可以访问到的PodSecurityPolicy中的策略。

创建一个允许部署特权容器的PodSecurityPolicy

apiVersion: extentsions/v1beta1
kind: PodSecurityPolicy
metadata:
  name: privileged
spec:
  privileged: true
  runAsUser:
    rule: RunAsAny
  fsGroup:
    rule: RunAsAny
  supplementalGroups:
    rule: RunAsAny
  seLinux:
    rule: RunAsAny
  volumes:
  - '*'    

首先创建一个PodSecurityPolicy,允许用户创建特权模式容器的pod

kubectl  get psp    // psp 是PodSecurityPolicy的简写
可以看到 default 和 privileged  两个psp 其中default 中PRIV是false

在部署pod时,如果任一策略允许使用pod中使用到的任何特性,API服务器就会接受这个pod。
现在考虑两个使用该集群的用户A和B,其中A只能创建受限的非特权pod,允许B可以创建特权模式的pod。可以通过让A只使用default PodSecurityPolicy,而B 使用以上两个PodSecurityPolicy来做到。

使用RBAC将不同的PodSecurityPolicy分配给不同的用户
RBAC可以给用户授予特定类型的资源的访问权限,但RBAC机制也可以通过使用其名字来授权对特定资源实例的访问权限。
先创建两个ClusterRole,分别名为psp-default、psp-privileged

kubectl create clusterrole  psp-default --verb=use \
 --resource=podsecuritypolicy  --resource-name=psp-default
kubectl create clusterrole psp-privileged --verb=use \
 --resource=podsecuritypolicy --resource-name=privileged 

注意:这里使用的动词是use,而不是get list watch或类似的动词

现在需要将这两个策略绑定到用户上,因为ClusterRole是集群资源,所以需要使用ClusterRoleBinding资源而非RoleBinding。
要将 psp-default ClusterRole绑定到所有已认证的用户上,而不单单是用户A。否则没有用户可以创建pod,因为PodSecurityPolicy访问控制插件会因为没有找到任何策略二拒绝创建pod。所有已认证的用户都属于system:authenticated,因此要将psp-default ClusterRole绑定到这个组。

kubectl create clusterrolebinding psp-all-user --clusterrole=psp-default \
  --group=system:authenticated

将psp-privileged ClusterRole 绑定到用户B

kubectl create clusterrolebinding psp-b  --clusterrole=psp-privileged \
  --user=b

作为一个已认证用户,A现在拥有default PodSecurityPolicy 的权限。而用户B拥有default 和 privileged PodSecurityPolicy的权限,A不能部署特权模式的pod,而用户B可以。

使用kubectl 创建不同用户
如何以用户A或用户B身份通过认证,而非用现在的已认证的用户。首先用kubectl 的子命令config 来创建两个新用户

kubectl config set-credentials a --username=a  --password=password
kubectl config set-credentials b --username=b  --password=password

然后使用这两个用户去创建特权模式的pod

kubectl --user=a create -f  pod-privileged.yaml  // 会提示创建失败
kubectl --user=a create -f  pod-privileged.yaml  // 可以创建成功

四、隔离pod网络

上面所讲的安全特性配置都是pod和pod中的容器上。现在来了解一下如何通过限制pod与pod之间通信,来确保pod之间的网络安全。
是否可以进行这些配置取决于集群中使用的网络插件,如果网络插件支持,可以通过NetworkPolicy资源配置网络隔离。
一个NetworkPolicy会应用在匹配它的标签选择器的pod上,指明这些允许访问这些pod的源地址,或这些pod可以访问的目标地址。这些分别由入向(ingress)和出向(egress)规则指定。这两者都可以匹配由标签选择器选出的pod,或者一个namespace中的所有pod,或者通过无类别域间路由CIDR指定的IP地址段。

在一个命名空间中启用网络隔离

apiVersion: network.k8s.io/v1
kind: NetworkPolicy
metadata: 
  name: default-deny
spec:
  podSelector:
               // 空的标签选择器会匹配命名空间中所有的pod

在任何一个命名空间内创建该NetworkPolicy之后,任何客户端都不能访问该命名空间中的pod

允许同一个命名空间中的部分pod访问一个服务端pod

apiVersion: network.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: xxx
spec:
  podSelector:
    matchLabels:
      app: database  // 确保了对具有app=database标签的pod的访问安全性
  ingress:
  - from:
    - podSlecetor:
        matchLabels:
          app: webserver  // 只允许具有app=webserver标签的pod访问
      ports:
      - port: 5432   // 仅允许对该端口访问

上面的NetworkPolicy表示,命名空间中的数据库服务,现在只允许webserver才能访问,其他的pod都不能访问。并且,webserver只能访问数据库的5432端口。
客户端pod通常通过Service而非直接访问pod来访问服务端拍pod,但这对结果没有影响,NetworkPolicy在通过Service访问时任然生效。

在不同kubernetes命名空间之间进行网络隔离
假设我们有一个多租户使用同一个kubernetes集群。每个租户都有多个命名空间,每个命名空间中有一个标签指明它们属于哪个租户。例如,有一个租户manning,它所有命名空间中都有标签tenant:manning。其中的一个命名空间中运行了一个微服务testserver,该微服务具有标签 app:testserver,它只允许同一租户下所有命名空间下的所有pod访问。禁止其他租户访问。
为了确保该微服务的安全,可以创建如下的NetworkPolicy。

apiVersion: network.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: xxx
spec:
  podSelector:
    matchLabels:
      app: testserver  // 该策略应用于具有app=testserver标签的pod
  ingress:
  - from:
    - namespaceSelector:
      matchLabels:
        tenant: manning  // 只有具有tenant=manning标签的命名空间中运行的
      ports:                //  pod可以访问该微服务
      - port: 80

注意:在多租户的kubernetes集群中,通常租户不能为他的命名空间添加标签或注释,否则,他们可以规避基于namespaceSelector的入向规则。

使用CIDR隔离网络
除了通过再pod选择器或命名空间选择器定义了哪些pod可以访问NetworkPolicy资源中指定的目标pod,还可以通过CIRD表示法指定一个IP段。例如,允许192.168.0.1/24 网段的客户端访问之前的testserver,可以再入向规则中添加一下代码

ingress:
- from:
  - ipBlock:
      cidr: 192.168.0.1/24   // 允许IP在该范围内的客户端访问testserve    

限制pod对外访问流量

spec:
  podSelector:
    matchLabels:
      app: webserver   // 这个策略应用于具有app=webserver标签的pod
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: database    // webserver的pod只能与具有app=database标签的pod通信
发布了13 篇原创文章 · 获赞 6 · 访问量 354

猜你喜欢

转载自blog.csdn.net/WuYuChen20/article/details/103683502