跳至主要內容

6.6 Pod的安全策略配置

Change Lee...大约 10 分钟容器k8s

为了更精细的控制Pod对资源的使用方式,kubernetes 从1.4 版本引入了PodSecurityPolicy资源对象对Pod的安全策略进行管理。并在 1.10 版本升级了Beta 版,到 1.14 时趋于成熟。

6.6.1 PodSecurityPolicy 的工作机制。

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

--enable-admission-plugins=PodSecurityPolicy

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

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx

使用 kubectl 命令创建时,系统将提示 "禁止创建" 的报错信息:

[root@master k8s]## kubectl create -f pods.yaml 
Error from server (Forbidden): error when creating "pods.yaml": pods "nginx" is forbidden: PodSecurityPolicy: no providers available to validate pod request

接下来,创建一个PodSecurityPolicy ,配置文件psp-non-provileged.yaml

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: psp-non-privileged
spec:
  privileged: false
  seLinux:
    rule: RunAsAny
  supplementalGroups:
    rule: RunAsAny
  runAsUser:
    rule: RunAsAny
  fsGroup:
    rule: RunAsAny
  volumes:
  - '*'

使用kubectl create 命令创建该PodSecurityPolicy:

[root@master k8s]## kubectl create -f psp-non-privileged.yaml 
podsecuritypolicy.policy/psp-non-privileged created

查看PodSecurityPolicy

[root@master k8s]## kubectl get psp 
NAME                 PRIV    CAPS   SELINUX    RUNASUSER   FSGROUP    SUPGROUP   READONLYROOTFS   VOLUMES
psp-non-privileged   false          RunAsAny   RunAsAny    RunAsAny   RunAsAny   false            *
[root@master k8s]## 

再次创建Pod 就能成功:

[root@master k8s]## kubectl create -f pods.yaml       
pod/nginx created
[root@master k8s]## 

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

apiVersion: v1
kind: Pod
metadata:
  name: nginx-priveliged
spec:
  containers:
  - name: nginx
    image: nginx
    securityContext:
      privileged: true

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

[root@master k8s]## kubectl create -f nginx-privileged.yaml 
Error from server (Forbidden): error when creating "nginx-privileged.yaml": pods "nginx-priveliged" is forbidden: PodSecurityPolicy: unable to admit pod: [spec.containers[0].securityContext.privileged: Invalid value: true: Privileged containers are not allowed]

6.6.2PodSecurityPolicy 配置详解

在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 类型,设置为"*" 表示允许使用任意类型,建议至少允许Pod 使用下列的Volume 类型。

  • configMap
  • downwardAPI
  • emptyDir
  • persistentVolumeClaim
  • secret
  • projected

(6) AllowedHostPaths: 允许Pod使用宿主机的hostPath 路径名称,可以通过pathPrefix 字段设置路径的前缀,并可以设置是否为只读属性,例子如下:

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: allow-hostpath-volumes
spec:
  volumes:
    - hostPath
  allowedHostPaths:
  - pathPrefix: "/foo"
    readOnly: true 

结果为允许Pod访问宿主机上以 "/foo" 为前缀的路径,包括 "/foo","/foo/","foo/bar"等,但不能访问"/fool","/etc/foo"等路径,也不允许通过 "/foo/../"表达式访问 /foo 的上层目录。
(7) FSGroup: 设置允许说某些Volume的GroupID范围,可以将规则(rule字段)设置为 MustRunAs、MayRunAs、RunAsAny。

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

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

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: allow-flex-volumes
spec:
  volumes:
    - flexVolume
  allowedFlexVolumes:
    - driver: example/lvm
    - driver: example/cifs

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的范围。
  • MayRunAs: 不要求设置 RunAsGroup。 不过,如果指定了 RunAsGroup 被设置,所设置值必须处于所定义的范围内
  • 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) DefaultAllowPrivilegeEsalation: 设置AllowPrivilegeEscalation 的默认值,设置为disallow时,管理员还可以显式设置AllowPrivilegeEscalation来指定是否允许提升权限

5. Linux能力相关配置

(1) AllowCapabilities:设置容器可以使用的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-capabilitiesopen in new window

6. SELinux 相关配置

seLinux : 设置 SELinux 参数,可以将规则字段 (rule) 的值设置为 MustRunAs 或 RunAsAny。

  • MustRunAs:要求设置seLinuxOptions ,系统将对Pod的seurityContext.seLinuxOptions 设置的值进行校验。
  • RunAsAny: 不限制seLinuxOptions的设置。

7. 其他Linux相关配置

(1) AllowedProcMountTypes: 设置允许的ProcMountTypes类型列表,可以设置allowedProcMountTypes或DefaultProcMount。
(2) AppArmor: 设置对容器可执行程序的访问控制权限,详情请参考 https://kubernetes.io/docs/tutorials/security/apparmor/#podsecuritypolicyannotationsopen in new window
(3) Seccomp: 设置允许容器使用的系统调用(System Calls)的profile。
(4) Sysctl: 设置允许调整的内核参数,详情参考 https://kubernetes.io/docs/tasks/administer-cluster/sysctl-cluster/#podsecuritypolicyopen in new window

下面列举常用的PodSecurityPolicy安全策略配置

例1: 基本没有限制的安全策略,允许创建任意安全设置的Pod。

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: privileged
  annotations:
    seccomp.security.alpha.kubernetes.io/allowedProfileNames: "*"
spec:
  privileged: true
  allowPrivilegeEscalation: true
  allowedCapabilities:
  - '*'
  volumes:
  - '*'
  hostNetwork: true
  hostPorts:
  - min: 0
    max: 65535
  hostIPC: true
  hostPID: true
  runAsUser:
    rule: 'RunAsAny'
  seLinux:
    rule: 'RunAsAny'
  supplementalGroups:
    rule: 'RunAsAny'
  fsGroup:
    rule: 'RunAsAny'

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

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: restricted
  annotations:
    seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default'
    apparmor.security.beta.kubernetes.io/allowedProfileNames: 'runtime/default'
    seccomp.security.alpha.kubernetes.io/defaultProfileName: 'docker/default'
    apparmor.security.beta.kubernetes.io/defaultProfileName: 'runtime/default'
spec:
  privileged: false
  allowPrivilegeEscalation: false
  requiredDropCapabilities:
  - ALL
  volumes:
  - 'configMap'
  - 'emptyDir'
  - 'projected'
  - 'secret'
  - 'downwardAPI'
  - 'persistentVolumeClaim'
  hostNetwork: false
  hostIPC: false
  hostPID: false
  runAsUser:
    rule: 'MustRunAsNonRoot'
  seLinux:
    rule: 'RunAsAny'
  supplementalGroups:
    rule: 'MustRunAs'
    ranges:
      - min: 1
        max: 65535
  fsGroup:
    rule: 'MustRunAs'
    ranges:
      - min: 1
        max: 65535
  readOnlyRootFilesystem: false

此外,Kubernetes 建议使用RBAC 授权机制来设置针对Pod安全策略的授权,通常应该对Pod的SevicesAccount进行授权。

例如: 可以创建如下ClusterRole(也可以创建Role) ,并将其设置为允许使用PodSecurityPolicy:

kind: ClousterRole
apiVersio: rbac.authorization.k8s.io/v1
metadata:
  name: <role name>
rules:
- apiGroups: ['policy']
  resources: ['podsecuritypolicies']
  verbs: ['use']
  resourceNames:
  - <list of policies to authorize> #允许使用的PodSecurityPolicy列表

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

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: <binding name>
roleRef:
  kind: ClusterRole
  name: <role name> #之前创建的ClusterRole
  apiGroup: rbac.authorization.k8s.io
subjects:
  #对特定Namespace中的ServiceAccount进行授权
- kind: ServiceAccount
  name: <authorized pod namespace> ## ServiceAccount的名称
  namespace: <authorized pod namespace> ## Namespace的名称
  #对特定用户授权(不推荐)
- kind: User
  apiGroup: rbac.authorization.k8s.io
  name: <authorized user name> ## 用户名

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

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: <binding name>
  namespace: <binding namespace> ## 访RoleBinding所属的Namespace
roleRef:
  kind: Role
  name: <role name>
  apiGroup: rbac.authorization.k8s.io
subjects:
  #授权该Namespace 中的全部ServiceAccount
- kind: Group
  apiGroup: rbac.authorization.k8s.io
  name: system:serviceaccounts
- kind: Group
  apiGroup: rbac.authorization.k8s.io
  name: system:authenticated

6.6.3 Pod的安全设置详解

在系统管理员对Kubernetes集群中设置了PodSecurityPolicy策略之后 ,系统将对Pod和Container级别的安全设置进行校验,对于不满足PodSecurityPolicy安全策略的Pod,系统将拒绝创建。
Pod和容器的安全策略可以在Pod或Container的securityContext字段中进行设置,如果在Pod和Container级别都设置相同的安全类型字段,容器将使用Container级别的设置。
在Pod级别可以设置的安全策略类型如下:

  • runAsUser:容器内运行程序的用户ID。
  • runAsGroup:容器内运行程序的用户组ID。
  • runAsNonRoot: 是否必须以非root用户运行运行程序。
  • fsGroup:设置允许说某些Volume的GroupID范围。
  • seLinuxOptions:SELinux 相关设置。
  • supplementalGroups:允许容器使用的其他用户组ID。
  • sysctls:设置允许调整的内核参数。

在Container级别可以设置的安全策略类型如下:

  • runAsUser:容器内运行程序的用户ID。
  • runAsGroup:容器内运行程序的用户组ID。
  • runAsNonRoot: 是否必须以非root用户运行运行程序。
  • privileged:是否以特权模式运行。
  • allowPrivilegeEscalation:是否允许提升权限。
  • readOnlyRootFilesystem:根文件系统是否为只读属性。
  • capabilities:Linux能力列表。
  • seLinuxOptions:SELinux 相关设置。

下面通过几个例子对Pod的安全设置进行说明:

例1:Pod级别的安全设置,作用于该Pod内的全部容器。

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo
spec:
  securityContext:
    runAsUser: 1000
    runAsGroup: 3000
    fsGroup: 2000
  volumes:
  - name: sec-ctx-demo
    emptyDir: {}
  containers:
  - name: sec-ctx-demo
    image: gcr.io/google-samples/node-hello:1.0
    volumeMounts:
    - name: sec-ctx-demo
      mountPath: /data/demo
    securityContext:
      allowPrivilegeEscalation: false

TIPS

如果上面的镜像无法下载,可以使用busybox 镜像测试
  containers:
  - name: sec-ctx-demo
    image: busybox
    command:
    - tail
    - -f
    - /dev/null

在spec.securityContext中设置了如下参数:

  • runAsUser=1000 : 所有容器都将以 UserID 1000运行程序,所有新生成文件的UserID也被设置为1000
  • runAsGroup=1000 : 所有容器都将以 GroupID 3000运行程序,所有新生成文件的GroupID也被设置为3000
  • fsGroup=2000: 挂载卷 "/data/demo" 及其中创建的文件都将属于GroupID 2000。

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

/ $ ps aux
PID   USER     TIME  COMMAND
    1 1000      0:00 tail -f /dev/null
   11 1000      0:00 sh
   16 1000      0:00 ps aux

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

/ $ ls -l /data
total 0
drwxrwsrwx    2 root     2000             6 Mar 22 10:17 demo

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

/ $ cd /data/demo/
/data/demo $ ls
/data/demo $ touch hello
/data/demo $ ls -l 
total 0
-rw-r--r--    1 1000     2000             0 Mar 22 10:20 hello

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

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo-2
spec:
  securityContext:
    runAsUser: 1000
  containers:
  - name: sec-ctx-demo-2
    image: busybox
    command:
    - tail
    - -f
    - /dev/null
    securityContext:
      runAsUser: 2000
      allowPrivilegeEscalation: false

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

/ $ ps aux 
PID   USER     TIME  COMMAND
    1 2000      0:00 tail -f /dev/null
    6 2000      0:00 sh
   11 2000      0:00 ps aux

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

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo-3
spec:
  containers:
  - name: sec-ctx-3
    image: busybox
    command:
    - ping
    - 127.0.0.1
    securityContext:
      capabilities:
        add: ['NET_ADMIN','SYS_TIME']

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

~ ## cd /proc/1
/proc/1 ## cat status | grep Cap
CapInh: 00000000aa0435fb
CapPrm: 00000000aa0435fb
CapEff: 00000000aa0435fb
CapBnd: 00000000aa0435fb
CapAmb: 0000000000000000

未设置这两个能力的配置为:

/ $ cd /proc/1
/proc/1 $ cat status | grep Cap
CapInh: 00000000a80425fb
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 00000000a80425fb
CapAmb: 0000000000000000

可以看到系统在第12位和第25位添加了CAP_NET_ADMIN和CAP_SYS_TIME这两个Linux 能力。

补充知识:

使用capsh 去解码,更多知识查看 Linux Capabilities 简介open in new window

[root@master ~]## capsh --decode=00000000aa0435fb
0x00000000aa0435fb=cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_admin,cap_net_raw,cap_sys_chroot,cap_sys_time,cap_mknod,cap_audit_write,cap_setfcap
上次编辑于:
贡献者: change,lichangyangccm@163.com
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v3.1.3