一 Pod安全
1.1 PodSecurityPolicy启用
为了更精细地控制Pod对资源的使用方式,Kubernetes从1.4版本开始引入了PodSecurityPolicy资源对象对Pod的安全策略进行管理,并在1.1版本中升级为Beta版,到1.14版本时趋于成熟。
若想启用PodSecurityPolicy机制,需要在kube-apiserver服务的启动参数--enable-admission-plugins中进行设置:
[root@k8smaster01 ~]# vi /etc/systemd/system/kube-apiserver.service
1 …… 2 --enable-admission-plugins=PodSecurityPolicy 3 ……
[root@k8smaster01 ~]# systemctl daemon-reload
[root@k8smaster01 ~]# systemctl restart kube-apiserver.service
在开启PodSecurityPolicy准入控制器后,Kubernetes默认不允许创建任何Pod,需要创建PodSecurityPolicy策略和相应的RBAC授权策略(Authorizing Policies),Pod才能创建成功。
[root@k8smaster01 study]# vi nginx-pod.yaml #测试创建Pod
1 apiVersion: v1 2 kind: Pod 3 metadata: 4 name: nginx 5 spec: 6 containers: 7 - name: nginx 8 image: nginx 9 ports: 10 - name: web 11 containerPort: 80
[root@k8smaster01 study]# kubectl create -f nginx-pod.yaml
1.2 PodSecurityPolicy配置
[root@k8smaster01 study]# vi psp-non-privileged.yaml
1 apiVersion: policy/v1beta1 2 kind: PodSecurityPolicy 3 metadata: 4 name: psp-non-privileged 5 spec: 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 - '*'
[root@k8smaster01 study]# kubectl create -f psp-non-privileged.yaml
[root@k8smaster01 study]# kubectl get psp psp-non-privileged #查看策略
[root@k8smaster01 study]# kubectl create -f nginx-pod.yaml #再次创建Pod
解释:如上PodSecurityPolicy“psp-non-privileged”设置了privileged:false,表示不允许创建特权模式的Pod。
[root@k8smaster01 study]# vi nginx-pod2.yaml #开启Pod的特权模式
1 apiVersion: v1 2 kind: Pod 3 metadata: 4 name: nginx2 5 spec: 6 containers: 7 - name: nginx2 8 image: nginx 9 securityContext: 10 privileged: true 11 ports: 12 - name: web 13 containerPort: 80
[root@k8smaster01 study]# kubectl create -f nginx-pod2.yaml
解释:如上开启Pod的特权模式,在创建Pod时,系统将提示如上“禁止创建特权模式的Pod”的报错信息。
二 PodSecurityPolicy配置详解
在PodSecurityPolicy对象中可以设置下列字段来控制Pod运行时的各种安全策略。
2.1 特权模式配置
privileged:是否允许Pod以特权模式运行。
2.2 宿主机资源相关配置
- hostPID:是否允许Pod共享宿主机的进程空间。
- hostIPC:是否允许Pod共享宿主机的IPC命名空间。
- hostNetwork:是否允许Pod使用宿主机网络的命名空间。
- hostPorts:是否允许Pod使用宿主机的端口号,可以通过hostPortRange字段设置允许使用的端口号范围,以[min,max]设置最小端口号和最大端口号。
- Volumes:允许Pod使用的存储卷Volume类型,设置为“*”表示允许使用任意Volume类型,建议至少允许Pod使用下列Volume类型。
- configMap
- downwardAPI
- emptyDir
- persistentVolumeClaim
- secret
- projected
- AllowedHostPaths:允许Pod使用宿主机的hostPath路径名称,可以通过pathPrefix字段设置路径的前缀,并可以设置是否为只读属性。
示例1:
1 apiVersion: policy/v1beta1 2 kind: PodSecurityPolicy 3 metadata: 4 name: allow-hostpath-volumes 5 spec: 6 volumes: 7 - hostPath 8 allowedHostPaths: 9 - pathPrefix: "/foo" 10 readOnly: true
解释:结果为允许Pod访问宿主机上以“/foo”为前缀的路径,包括“/foo”“/foo/”“/foo/bar”等,但不能访问“/fool”“/etc/foo”等路径,也不允许通过“/foo/../”表达式访问/foo的上层目录。
- 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。
- ReadOnlyRootFilesystem:要求容器运行的根文件系统(rootfilesystem)必须是只读的。
- allowedFlexVolumes:对于类型为flexVolume的存储卷,设置允许使用的驱动类型。
示例2:
1 apiVersion: policy/v1beta1 2 kind: PodSecurityPolicy 3 metadata: 4 name: allow-flex-volumes 5 spec: 6 volumes: 7 - flexVolume 8 allowedflexVolumes: 9 - driver: example/lvm 10 - driver: example/cifs
2.3 用户和组相关配置
- 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都可以运行。
- 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的用户都可以运行。
- 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的用户都可以运行。
2.4 提升权限相关配置
- AllowPrivilegeEscalation:设置容器内的子进程是否可以提升权限,通常在设置非root用户(MustRunAsNonRoot)时进行设置。
- DefaultAllowPrivilegeEscalation:设置AllowPrivilegeEscalation的默认值,设置为disallow时,管理员还可以显式设置AllowPrivilegeEscalation来指定是否允许提升权限。
2.5 Linux能力相关配置
- AllowedCapabilities:设置容器可以使用的Linux能力列表,设置为“*”表示允许使用Linux的所有能力(如NET_ADMIN、SYS_TIME等)。
- RequiredDropCapabilities:设置不允许容器使用的Linux能力列表。
- DefaultAddCapabilities:设置默认为容器添加的Linux能力列表,例如SYS_TIME等,Docker建议默认设置的Linux能力请查看https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linuxcapabilities。
2.6.SELinux相关配置
- seLinux:设置SELinux参数,可以将规则字段(rule)的值设置为MustRunAs或RunAsAny。
- MustRunAs:要求设置seLinuxOptions,系统将对Pod的securityContext.seLinuxOptions设置的值进行校验。
- RunAsAny:不限制seLinuxOptions的设置。
2.7 其他Linux相关配置
- AllowedProcMountTypes:设置允许的ProcMountTypes类型列表,可以设置allowedProcMountTypes或DefaultProcMount。
- AppArmor:设置对容器可执行程序的访问控制权限,详情请参考https://kubernetes.io/docs/tutorials/clusters/apparmor/#podsecuritypolicyannotations。
- Seccomp:设置允许容器使用的系统调用(SystemCalls)的profile。
- Sysctl:设置允许调整的内核参数,详情请参考https://kubernetes.io/docs/concepts/cluster-administration/sysctlcluster/#podsecuritypolicy。
2.8 常见PodSecurityPolicy安全策略配置
示例1:基本没有限制的安全策略,允许创建任意安全设置的Pod。
1 apiVersion: policy/v1beta1 2 kind: PodSecurityPolicy 3 metadata: 4 name: privileged 5 annotations: 6 seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*' 7 spec: 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'
示例2:要求Pod运行用户为非特权用户;禁止提升权限;不允许使用宿主机网络、端口号、IPC等资源;限制可以使用的Volume类型等。
1 apiVersion: policy/v1beta1 2 kind: PodSecurityPolicy 3 metadata: 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' 10 spec: 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
示例3:创建如下ClusterRole(也可以创建Role)并将其设置为:允许使用PodSecurityPolicy。
1 kind: ClusterRole 2 apiVersion: rbac.authorization.k8s.io/v1 3 metadata: 4 name: <role name> 5 rules: 6 - apiGroup: ['policy'] 7 resources: ['podsecuritypolicies'] 8 verbs: ['use'] 9 resourceNames: 10 - <list of policies to authorize> # 允许使用的PodSecurityPolicy列表
然后创建一个ClusterRoleBinding与用户和ServiceAccount进行绑定。
1 kind: ClusterRoleBinding 2 apiVersion: rbac.authorization.k8s.io/v1 3 metadata: 4 name: <binding name> 5 roleRef: 6 kind: ClusterRole 7 name: <roke name> # 之前创建的ClusterRole名称 8 apiGroup: rbac.authorization.k8s.io 9 subjects: 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> # 用户名
三 Pod的安全设置详解
3.1 Pod安全策略类型
当Kubernetes集群中设置了PodSecurityPolicy策略之后,系统将对Pod和Container级别的安全设置进行校验,对于不满足PodSecurityPolicy安全策略的Pod,系统将拒绝创建。
Pod和容器的安全策略可以在Pod或Container的securityContext字段中进行设置,如果在Pod和Container级别都设置了相同的安全类型字段,容器将使用Container级别的设置。
在Pod级别可以设置的安全策略类型如下:
- 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:
[root@k8smaster01 study]# vi security-context-pod01.yaml
1 apiVersion: v1 2 kind: Pod 3 metadata: 4 name: security-context-demo 5 spec: 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
[root@k8smaster01 study]# kubectl create -f security-context-pod01.yaml
[root@k8smaster01 study]# kubectl exec -ti security-context-demo /bin/bash
$ ps aux #运行进程的用户ID为1000
$ ls -l /data/ #挂载的目录Group ID为2000
total 0
drwxrwsrwx 2 root 2000 6 Nov 28 13:56 demo
解释:在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。
3.3 Container安全策略类型
- runAsUser: 容器内运行程序的用户ID。
- runAsGroup: 容器内运行程序的用户组ID。
- runAsNonRoot: 是否必须以非root用户运行程序。
- privileged: 是否以特权模式运行。
- allowPrivilegeEscalation: 是否允许提升权限。
- readOnlyRootFilesystem: 根文件系统是否为只读属性。
- capabilities: Linux能力列表。
- seLinuxOptions: SELinux相关设置。
示例2:
[root@k8smaster01 study]# vi security-context-pod02.yaml
1 apiVersion: v1 2 kind: Pod 3 metadata: 4 name: security-context-demo-2 5 spec: 6 securityContext: 7 runAsUser: 1000 8 containers: 9 - name: sec-ctx-demo-2 10 image: tomcat 11 securityContext: 12 runAsUser: 2000 13 allowPrivilegeEscalation: false
[root@k8smaster01 study]# kubectl create -f security-context-pod02.yaml
[root@k8smaster01 study]# kubectl exec security-context-demo-2 /bin/bash
$ ps aux #运行进程的用户ID为1000