带你玩转kubernetes-k8s(第41篇:深入分析集群安全机制四[Secret, PodSecurityPolicy])

释放双眼,带上耳机,听听看~!

Secret私密凭据

    上一节提刀Secret对象,Secret的主要作用是保管私密数据,比如密码、OAuth Tokens、 SSH Key等信息。将这些私密信息放在Secret对象中比直接放在Pod或Docker Image中更安全,也更便于使用和分发。

   下面的例子用于创建一个Secret:


1
2
3
4
5
6
7
8
9
1apiVersion: v1
2kind: Secret
3metadata:
4  name: mysecret
5type: Opaque
6data:
7  password: dmFsdWUtMg0K
8  username: dmFsdWUtMQ0K
9

带你玩转kubernetes-k8s(第41篇:深入分析集群安全机制四[Secret, PodSecurityPolicy])

     在上面的例子中,data域的各子域的值必须为BASE64编码值,其中password域和username域BASE64编码前的值分别为value-1和value-2。
一旦Secret被创建,就可以通过下面三种方式使用它。
(1)在创建Pod时,通过为Pod指定Service Account来自动使用该Secret。
(2)通过挂载该Secret到Pod来使用它。
(3)在Docker镜像下载时使用,通过指定Pod的spc.ImagePullSecrets来引用它。
第1种使用方式主要用在API Server鉴权方面,之前提到过。下面的例子展示了第2种使用方式:将一个Secret通过挂载的方式添加到Pod的Volume中:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1apiVersion: v1
2kind: Pod
3metadata:
4  name: mypod
5spec:
6  containers:
7  - name: mycontainer
8    image: tomcat
9    volumeMounts:
10    - name: foo1
11      mountPath: "/etc/foo1"
12      readOnly: true
13  volumes:
14  - name: foo1
15    secret:
16      secretName: mysecret
17
18

带你玩转kubernetes-k8s(第41篇:深入分析集群安全机制四[Secret, PodSecurityPolicy])

带你玩转kubernetes-k8s(第41篇:深入分析集群安全机制四[Secret, PodSecurityPolicy])

第3种使用方式的使用流程如下:

(1)执行login命令,登录私有Registry:


1
2
1docker login localhost:8000
2

输入用户名和密码,如果是第1次登录系统,则会创建新用户,相关信息被会写入~/.dockercfg文件中。
(2)用BASE64编码dockercfg的内容:


1
2
1cat ~/.dockercfg base64
2

(3)将上一步命令的输出结果作为Secret的data.dockercfg域的内容,由此来创建一个Secret:


1
2
3
4
5
6
7
8
9
1# image-poll-secret.yaml:
2apiVersion: v1
3kind: Secret
4metadata:
5  name: myregistrykey
6data:
7  dockercfg: .......................................
8  type: kubernetes.io/dockercfg
9

1
2
1kubectl create -f image-pull-secret.yaml
2

(4)在创建Pod时引用该Secret:


1
2
3
4
5
6
7
8
9
10
11
12
13
1# pods.yaml
2apiVersion: v1
3kind: Pod
4metadata:
5  name: mypod2
6spec:
7  containers:
8  - name: foo
9    image: jaychou/tomcat:v1
10  imagePullSecrets:
11  - name: myregistrykey
12
13

1
2
1kubectl create -f pods.yaml
2

在使用Mount方式挂载Secret时,Container中Secret的data域的各个域的Key值作为目录中的文件,Value值被BASE64编码后存储在相应的文件中。在前面的例子中创建的Secret,被挂载到一个叫作mycontainer的Container中,在该Container中可通过相应的查询命令查看所生成的文件和文件中的内容,如下所示:

带你玩转kubernetes-k8s(第41篇:深入分析集群安全机制四[Secret, PodSecurityPolicy])

      通过上面的例子可以得出如下结论:我们可以通过Secret保管其他系统的敏感信息(比如数据库的用户名和密码),并以Mount的方式将Secret挂载到Container中,然后通过访问目录中文件的方式获取该敏感信息。当Pod被API Server创建时,API Server不会校验该Pod引用的Secret是否存在。一旦这个Pod被调度,则kubelet将试着获取Secret的值。如果Secret不存在或暂时无法连接到API Server,则kubelet按一定的时间间隔定期重试获取该Secret,并发送一个Event来解释Pod没有启动的原因。一旦Secret被Pod获取,则kubelet将创建并挂载包含Secret的Volume。只有所有Volume都挂载成功,Pod中的Container才会被启动。在kubelet启动Pod中的Container后,Container中和Secret相关的Volume将不会被改变,即使Secret本身被修改。为了使用更新后的Secret,必须删除旧Pod,并重新创建一个新Pod。

Pod的安全策略配置

     为了更精细地控制Pod对资源的使用方式,Kubernetes从1.4版本开始引入了PodSecurityPolicy资源对象对Pod的安全策略进行管理,并在1.10版本中升级为Beta版,到1.14版本时趋于成熟。目前PodSecurityPolicy资源对象的API版本为extensions/v1beta1,从1.10版本开始更新为policy/v1beta1,并计划于1.16版本时弃用extensions/v1beta1。

1.PodSecurityPolicy的工作机制

  若想启用PodSecurityPolicy机制,则需要在kube-apiserver服务的启动参数–enable-admission-plugins中进行设置:

如果是高可用,所有apiserver均需要修改


1
2
3
1kubectl edit pod -n kube-system kube-apiserver-k8s-master1
2
3

1
2
1--enable-admission-plugins=PodSecurityPolicy
2

   带你玩转kubernetes-k8s(第41篇:深入分析集群安全机制四[Secret, PodSecurityPolicy])

   在开启PodSecurityPolicy准入控制器后,Kubernetes默认不允许创建任何Pod,需要创建PodSecurityPolicy策略和相应的RBAC授权策略(Authorizing Policies),Pod才能创建成功。

  例如,尝试创建如下Pod:


1
2
3
4
5
6
7
8
9
1apiVersion: v1
2kind: Pod
3metadata:
4  name: nginx
5spec:
6  containers:
7  - name: nginx
8    image: nginx
9

使用Kubectl命令创建时,系统将提示“禁止创建”的报错信息。

接下来创建一个PodSecurityPolicy,配置文件psp-non-privileged.yaml的内容如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1apiVersion: policy/v1beta1
2kind: PodSecurityPolicy
3metadata:
4  name: psp-non-privileged
5spec:
6  privileged: false # 不允许特权模式的Pod
7  seLinux:
8    rule: RunAsAny
9  supplementalGroups:
10    rule: RunAsAny
11  runAsUser:
12    rule: RunAsAny
13  fsGroup:
14    rule: RunAsAny
15  volumes:
16  - '*'
17

带你玩转kubernetes-k8s(第41篇:深入分析集群安全机制四[Secret, PodSecurityPolicy])

之后再次创建Pod既可成功。

    上面的PodSecurityPolicy“psp-non-privileged”设置了privileged: false,表示不允许创建特权模式的Pod。在下面的YAML配置文件pod-privileged.yaml中为Pod设置了特权模式:


1
2
3
4
5
6
7
8
9
10
11
12
1apiVersion: v1
2kind: Pod
3metadata:
4  name: nginx
5spec:
6  containers:
7  - name: nginx
8    image: nginx
9    securityContext:
10      privileged: true
11
12

创建Pod时,系统将提示“禁止创建特权模式的Pod”的报错信息.

2.PodSecurityPolicy配置详情

    在PodSecurityPolicy对象中可以设置下列字段来控制Pod运行时的各种安全策略。

1.特权模式相关配置
privileged:是否允许Pod以特权模式运行。

2.宿主机资源相关配置
(1)hostPID:是否允许Pod共享宿主机的进程空间。
(2)hostIPC:是否允许Pod共享宿主机的IPC命名空间。
(3)hostNetwork:是否允许Pod使用宿主机网络的命名空间。
(4)hostPorts:是否允许Pod使用宿主机的端口号,可以通过hostPortRange字段设置允许使用的端口号范围,以【min,max】设置最小端口号和最大端口号。
(5)Volumes:允许Pod使用的存储卷Volume类型,设置为“*”表示允许使用任意Volume类型,建议至少允许Pod使用下列Volume类型。
◎ configMap
◎ downwardAPI
◎ emptyDir
◎ persistentVolumeClaim
◎ secret
◎ projected
(6)AllowedHostPaths:允许Pod使用宿主机的hostPath路径名称,可以通过pathPrefix字段设置路径的前缀,并可以设置是否为只读属性,例子如下。


1
2
3
4
5
6
7
8
9
10
11
1apiVersion: policy/v1beta1
2kind: PodSecurityPolicy
3metadata:
4  name: allow-hostpath-volumes
5spec:
6  volumes:
7  - hostPath
8  allowedHostPaths:
9  - pathPrefix: "/foo"
10    readOnly: true
11

      结果为允许Pod访问宿主机上以“/foo”为前缀的路径,包括“/foo”“/foo/”“/foo/bar”等,但不能访问“/fool”“/etc/foo”等路径,也不允许通过“/foo/../”表达式访问/foo的上层目录。

(7)FSGroup:设置允许访问某些Volume的Group ID范围,可以将规则(rule字段)设置为MustRunAs、MayRunAs或RunAsAny。

◎ MustRunAs:需要设置Group ID的范围,例如1~65535,要求Pod的securityContext.fsGroup设置的值必须属于该Group ID的范围。
◎ MayRunAs:需要设置Group ID的范围,例如1~65535,不强制要求Pod设置securityContext.fsGroup。
◎ RunAsAny:不限制Group ID的范围,任何Group都可以访问Volume。

(8)ReadOnlyRootFilesystem:要求容器运行的根文件系统(root filesystem)必须是只读的。
(9)allowedFlexVolumes:对于类型为flexVolume的存储卷,设置允许使用的驱动类型,例子如下。


1
2
3
4
5
6
7
8
9
10
11
1apiVersion: policy/v1beta1
2kind: PodSecurityPolicy
3metadata:
4  name: allow-flex-volumes
5spec:
6  volumes:
7  - flexVolume
8  allowedFlexVolumes:
9  - driver: example/lvm
10  - driver: example/cifs
11

3.用户和组相关配置
(1)RunAsUser:设置运行容器的用户ID(User ID)范围,规则字段(rule)的值可以被设置为MustRunAs、MustRunAsNonRoot或RunAsAny。
◎ MustRunAs:需要设置User ID的范围,要求Pod的securityContext.runAsUser设置的值必须属于该User ID的范围。
◎ MustRunAsNonRoot:必须以非root用户运行容器,要求Pod的securityContext.runAsUser设置一个非0的用户ID,或者镜像中在USER字段设置了用户ID,建议同时设置allowPrivilegeEscalation=false以避免不必要的提升权限操作。
◎ RunAsAny:不限制User ID的范围,任何User都可以运行。

(2)RunAsGroup:设置运行容器的Group ID范围,规则字段的值可以被设置为MustRunAs、MustRunAsNonRoot或RunAsAny。
◎ MustRunAs:需要设置Group ID的范围,要求Pod的securityContext.runAsGroup设置的值必须属于该Group ID的范围。
◎ MustRunAsNonRoot:必须以非root组运行容器,要求Pod的securityContext.runAsUser设置一个非0的用户ID,或者镜像中在USER字段设置了用户ID,建议同时设置allowPrivilegeEscalation=false以避免不必要的提升权限操作。
◎ RunAsAny:不限制Group ID的范围,任何Group的用户都可以运行

(3)SupplementalGroups:设置容器可以额外添加的Group ID范围,可以将规则(rule字段)设置为MustRunAs、MayRunAs或RunAsAny。
◎ MustRunAs:需要设置Group ID的范围,要求Pod的securityContext.supplementalGroups设置的值必须属于该Group ID范围。
◎ MayRunAs:需要设置Group ID的范围,不强制要求Pod设置securityContext.supplementalGroups。
◎ RunAsAny:不限制Group ID的范围,任何supplementalGroups的用户都可以运行。

4.提升权限相关配置

(1)AllowPrivilegeEscalation:设置容器内的子进程是否可以提升权限,通常在设置非root用户(MustRunAsNonRoot)时进行设置。
(2)DefaultAllowPrivilegeEscalation:设置AllowPrivilegeEscalation的默认值,设置为disallow时,管理员还可以显式设置AllowPrivilegeEscalation来指定是否允许提升权限。

5.Linux能力相关配置

(1)AllowedCapabilities:设置容器可以使用的Linux能力列表,设置为“*”表示允许使用Linux的所有能力(如NET_ADMIN、SYS_TIME等)。
(2)RequiredDropCapabilities:设置不允许容器使用的Linux能力列表。
(3)DefaultAddCapabilities:设置默认为容器添加的Linux能力列表,例如SYS_TIME等,Docker建议默认设置的Linux能力请查看https://docs.docker.com/engine/reference/run/\#runtime-privilege-and-linux-capabilities。

6.SELinux相关配置

seLinux:设置SELinux参数,可以将规则字段(rule)的值设置为MustRunAs或RunAsAny。
◎ MustRunAs:要求设置seLinuxOptions,系统将对Pod的securityContext.seLinuxOptions设置的值进行校验。
◎ RunAsAny:不限制seLinuxOptions的设置。

7.其他Linux相关配置

(1)AllowedProcMountTypes:设置允许的ProcMountTypes类型列表,可以设置allowedProcMountTypes或DefaultProcMount。
(2)AppArmor:设置对容器可执行程序的访问控制权限,详情请参考https://kubernetes.io/docs/tutorials/clusters/apparmor/\#podsecuritypolicy-annotations

notations。
(3)Seccomp:设置允许容器使用的系统调用(System Calls)的profile。
(4)Sysctl:设置允许调整的内核参数,详情请参考https://kubernetes.io/docs/concepts/cluster-administration/sysctl-cluster/\#podsecuritypolicy

下面列举两种常用的PodSecurityPolicy安全策略配置。
例1:基本没有限制的安全策略,允许创建任意安全设置的Pod。


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
1apiVersion: policy/v1beta1
2kind: PodSecurityPolicy
3metadata:
4  name: privileged
5  annotations:
6    seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*'
7spec:
8  privileged: true
9  allowPrivilegeEscalation: true
10  allowedCapabilities:
11  - '*'
12  volumes:
13  - '*'
14  hostNetwork: true
15  hostPorts:
16  - min: 0
17    max: 65535
18  hostIPC: true
19  hostPID: true
20  runAsUser:
21    rule: 'RunAsAny'
22  seLinux:
23    rule: 'RunAsAny'
24  supplementalGroups:
25    rule: 'RunAsAny'
26  fsGroup:
27    rule: 'RunAsAny'
28

例2:要求Pod运行用户为非特权用户;禁止提升权限;不允许使用宿主机网络、端口号、IPC等资源;限制可以使用的Volume类型,等等。


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
34
35
36
37
38
39
1apiVersion: policy/v1beta1
2kind: PodSecurityPolicy
3metadata:
4  name: restricted
5  annotations:
6    seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default'
7    apparmor.security.beta.kubernetes.io/allowedProfileNames: 'runtime/default'
8    seccomp.security.alpha.kubernetes.io/defaultProfileName: 'docker/default'
9    apparmor.security.beta.kubernetes.io/dafaultProfileName: 'runtime/default'
10spec:
11  privileged: false
12  allowPrivilegeEscalation: false
13  requiredDropCapabilities:
14  - ALL
15  volumes:
16  - 'configMap'
17  - 'emptyDir'
18  - 'projected'
19  - 'secret'
20  - 'downwardAPI'
21  - 'persistentVolumeClaim'
22  hostNetwork: false
23  hostIPC: false
24  hostPID: false
25  runAsUser:
26    rule: 'MustRunAsNonRoot'
27  seLinux:
28    rule: 'MustRunAs'
29    ranges:
30    - min: 1
31      max: 65535
32  fsGroup:
33    rule: 'MustRunAs'
34    ranges:
35    - min: 1
36      max: 65535
37  readOnlyRootFilesystem: false
38
39

此外,Kubernetes建议使用RBAC授权机制来设置针对Pod安全策略的授权,通常应该对Pod的ServiceAccount进行授权。
例如,可以创建如下ClusterRole(也可以创建Role)并将其设置为允许使用PodSecurityPolicy:


1
2
3
4
5
6
7
8
9
10
11
1kind: ClusterRole
2apiVersion: rbac.authorization.k8s.io/v1
3metadata:
4  name: <role name>
5rules:
6- apiGroup: ['policy']
7  resources: ['podsecuritypolicies']
8  verbs: ['use']
9  resourceNames:
10  - <list of policies to authorize>  # 允许使用的PodSecurityPolicy列表
11

然后创建一个ClusterRoleBinding与用户和ServiceAccount进行绑定:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1kind: ClusterRoleBinding
2apiVersion: rbac.authorization.k8s.io/v1
3metadata:
4  name: <binding name>
5roleRef:
6  kind: ClusterRole
7  name: <roke name>  # 之前创建的ClusterRole名称
8  apiGroup: rbac.authorization.k8s.io
9subjects:
10# 对特定Namespace中的ServiceAccount进行授权
11- kind: ServiceAccount
12  name: <authorized servie account name> # ServiceAccount 的名称
13  namespace: <authorized pod namespace> # Namespace的名称
14# 对特定用户进行授权(不推荐)
15- kind: User
16  apiGroup: rbac.authorization.k8s.io
17  name: <authorized user name>  # 用户名
18

也可以创建RoleBinding对与该RoleBinding相同的Namespace中的Pod进行授权,通常可以与某个系统级别的Group关联配置,例如:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1kind: RoleBinding
2apiVersion: rbac.authorization.k8s.io/v1
3metadata:
4  name: <binding name>
5  namespace: <binding namespace>  # 该RoleBinding 所属的Namespace
6roleRef:
7  kind: Role
8  name: <role name>
9  apiGroup: rbac.authorization.k8s.io
10subjects:
11# 授权该Namespace中的全部ServiceAccount
12- kind: Group
13  apiGroup: rbac.authorization.k8s.io
14  name: system:serviceaccounts
15# 授权该Namespace中的全部哦用户
16- kind: Group
17  apiGroup: rbac.authorization.k8s.io
18  name: system:authenticated
19

Pod的安全设置详解

     在系统管理员对Kubernetes集群中设置了PodSecurityPolicy策略之后,系统将对Pod和Container级别的安全设置进行校验,对于不满足PodSecurityPolicy安全策略的Pod,系统将拒绝创建。
Pod和容器的安全策略可以在Pod或Container的securityContext字段中进行设置,如果在Pod和Container级别都设置了相同的安全类型字段,容器将使用Container级别的设置。
在Pod级别可以设置的安全策略类型如下。
◎ runAsUser:容器内运行程序的用户ID。
◎ runAsGroup:容器内运行程序的用户组ID。
◎ runAsNonRoot:是否必须以非root用户运行程序。
◎ fsGroup:SELinux相关设置。
◎ seLinuxOptions:SELinux相关设置。
◎ supplementalGroups:允许容器使用的其他用户组ID。
◎ sysctls:设置允许调整的内核参数。
在Container级别可以设置的安全策略类型如下。
◎ runAsUser:容器内运行程序的用户ID。
◎ runAsGroup:容器内运行程序的用户组ID。
◎ runAsNonRoot:是否必须以非root用户运行程序。
◎ privileged:是否以特权模式运行。
◎ allowPrivilegeEscalation:是否允许提升权限。
◎ readOnlyRootFilesystem:根文件系统是否为只读属性。
◎ capabilities:Linux能力列表。
◎ seLinuxOptions:SELinux相关设置。
例1:Pod级别的安全设置,作用于该Pod内的全部容器。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
1apiVersion: v1
2kind: Pod
3metadata:
4  name: security-context-demo
5spec:
6  securityContext:
7    runAsUser: 1000
8    runAsGroup: 3000
9    fsGroup: 2000
10  volumes:
11  - name: sec-ctx-vol
12    emptyDir: {}
13  containers:
14  - name: sec-ctx-demo
15    image: tomcat
16    volumeMounts:
17    - name: sec-ctx-vol
18      mountPath: /data/demo
19    securityContext:
20      allowPrivilegeEscalation: false
21
22

在spec.securityContext中设置了如下参数。
◎ runAsUser=1000:所有容器都将以User ID 1000运行程序,所有新生成文件的User ID也被设置为1000。
◎ runAsGroup=3000:所有容器都将以Group ID 3000运行程序,所有新生成文件的Group ID也被设置为3000。
◎ fsGroup=2000:挂载的卷“/data/demo”及其中创建的文件都将属于Group ID 2000。

创建该Pod之后进入容器环境,查看到运行进程的用户ID为1000:

带你玩转kubernetes-k8s(第41篇:深入分析集群安全机制四[Secret, PodSecurityPolicy])

 

查看从Volume挂载到容器的/data/demo目录,其Group ID为2000

带你玩转kubernetes-k8s(第41篇:深入分析集群安全机制四[Secret, PodSecurityPolicy])

 

在该目录下创建一个新文件,可见其用户ID为1000,组ID为2000:

带你玩转kubernetes-k8s(第41篇:深入分析集群安全机制四[Secret, PodSecurityPolicy])

 

例2:Container级别的安全设置,作用于特定的容器。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
1apiVersion: v1
2kind: Pod
3metadata:
4  name: security-context-demo-2
5spec:
6  securityContext:
7    runAsUser: 1000
8  containers:
9  - name: sec-ctx-demo-2
10    image: tomcat
11    securityContext:
12      runAsUser: 2000
13      allowPrivilegeEscalation: false
14

带你玩转kubernetes-k8s(第41篇:深入分析集群安全机制四[Secret, PodSecurityPolicy])

创建该Pod之后进入容器环境,查看到运行进程的用户ID为2000:

带你玩转kubernetes-k8s(第41篇:深入分析集群安全机制四[Secret, PodSecurityPolicy])

 

 

例3:为Container设置可用的Linux能力,为容器设置允许使用的Linux能力包括NET_ADMIN和SYS_TIME。

 


1
2
3
4
5
6
7
8
9
10
11
12
13
1apiVersion: v1
2kind: Pod
3metadata:
4  name: security-context-demo-3
5spec:
6  containers:
7  - name: sec-ctx-3
8    image: tomcat
9    securityContext:
10      capabilities:
11        add: ["NET_ADMIN","SYS_TIME"]
12
13

创建该Pod之后进入容器环境,查看1号进程的Linux能力设置:

带你玩转kubernetes-k8s(第41篇:深入分析集群安全机制四[Secret, PodSecurityPolicy])

带你玩转kubernetes-k8s(第41篇:深入分析集群安全机制四[Secret, PodSecurityPolicy])

 

 

小结:

    本节内容到此结束,明天开始,开始讲解k8s的网络原理。

     谢谢大家的支持!    

 

 

 

 

 

给TA打赏
共{{data.count}}人
人已打赏
安全运维

故障复盘的简洁框架-黄金三问

2021-9-30 19:18:23

安全运维

OpenSSH-8.7p1离线升级修复安全漏洞

2021-10-23 10:13:25

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索