PodSecurityPolicy 限制 Pod 使用安全上下文中的相关特性
PodSecurityPolicy 是一种 集群级别资源,用来限制用户能够在 Pod 的 安全上下文 中使用的各种安全相关的特性。通俗的说,用来限制 Pod 的定义中的安全上下文字段可以指定的相关配置。
🪐 PodSecurityPolicy 是由 API 服务器的 准入插件 完成的。
当 API 服务器收到 Pod 创建请求时,该准入插件会将 Pod 的定义与已配置的 PodSecurityPolicy 进行校验,集群中可以有多个该资源。若 Pod 符合其中一个资源,插件会根据匹配到的 PodSecurityPolicy 中定义的默认值对 Pod 进行修改,然后将该 Pod 存入 etcd;否则会被立刻拒绝。
🔥 其默认是没有被开启的,需要在启动 API 服务器时指定开启。一旦被开启,集群中的 PodSecurityPolicy 就会起作用,若当前没有任何该资源的话,则意味着任何用户都无法创建 Pod(因为 Pod 无法找到符合其需求的 PodSecurityPolicy 资源,所以通常集群中会存在一条最宽松的 PodSecurityPolicy 资源,保证系统自身可以正常运行、集群管理员可以创建任意安全级别的 Pod,然后再根据需求创建不同安全级别的 PodSecurityPolicy 资源,并将该资源的使用权交由用户,从而实现对用户创建的 Pod 的安全特性的控制)。
再次强调!!只要用户能够使用 PodSecurityPolicy 资源,那么该资源就会对该用户创建的 Pod 生效!!!
🥑 PodSecurityPolicy 可以定义的安全特性如下:
是否允许 Pod 使用宿主机节点的 PID、IPC 以及网络命名空间;
限制 Pod 可以绑定的宿主机节点端口;
容器运行时使用的用户 ID;
是否允许创建拥有特权模式的容器的 Pod;
允许添加哪些内核功能、默认添加哪些内核功能、禁用哪些内核功能;
允许容器使用哪些 SELinux 选项;
容器是否允许使用可写的根文件系统;
允许容器在哪些文件系统组下运行;
允许 Pod 使用哪些类型的存储卷;
🌝 修改 PodSecurityPolicy 对已存在的 Pod 无效,因为该资源是被准入插件使用的,因此仅在创建和更新 Pod 时才会起作用。
PodSecurityPolicy 定义案例
PodSecurityPolicy 是集群资源,因此同样可以通过定义 YAML 清单,然后通过 kubectl apply -f
命令生成。下面列举一个案例,创建一个名为 default
的 PodSecurityPolicy 资源,不允许 Pod 使用宿主机的 IPC、PID 以及网络命名空间,Pod 能够使用的宿主机的端口范围为 [1000, 11000] 和 [13000, 14000],不允许 Pod 中包含拥有特权模式的容器,Pod 中容器的根文件系统必须是只读的:
apiVersion: policy/v1beta1
kind: PodSecurityPolicy # 资源类型为 PodSecurityPolicy
metadata:
name: default
spec:
hostIPC: false # 不允许使用宿主机的 IPC 命名空间
hostPID: false # 不允许使用宿主机的 PID 命名空间
hostNetwork: false # 不允许使用宿主机的网络命名空间
hostPorts: # 限制 Pod 中的容器只能绑定(映射)宿主机的 1000~11000 和 13000~14000 端口(包含端点)
- min: 10000
max: 11000
- min: 13000
max: 14000
privileged: false # 不能创建特权模式的容器(若为 true,表示可以运行特权模式的容器,但并不是必须的)
readOnlyRootFilesystem: true # Pod 中的容器只能使用只读的根文件系统(若为 false,则用户可以通过安全上下文配置,自行定义哪些容器使用只读根文件系统,哪些不使用)
runAsUser: # 容器可以以任意用户 ID 运行
rule: RunAsAny
fsGroup: # 容器可以以任意用户组 ID 运行
rule: RunAsAny
supplementalGroups: # 容器可以以任意用户组 ID 运行
rule: RunAsAny
seLinux: # 容器可以使用任何 SELinux 选项
rule: RunAsAny
volumes: # 容器可以使用任何类型的存储卷
- '*'
Pod 安全性限制
限制用户 ID 和 用户组 ID
在上面的案例中可以了解到,可以通过 podsecuritypolicy.spec.runAsUser
限制用户 ID,通过 podsecuritypolicy.spec.fsGroup
和 podsecuritypolicy.spec.supplementalGroups
限制用户组 ID。
可以通过不同的 rule
字段进行限制,包括:
RunAsAny:可以使用任何 ID;
MustRunAs:限制可以使用的 ID 范围;
MustRunAsNonRoot (仅适用于
runAsUser
):限制使用 root 用户,即可以使用 ID 为 0 以为的任何 ID;
MustRunAs 规则
当使用了 MustRunAs 规则,则必须使用 ranges
字段定义使用的范围(若范围的最小值和最大值为同一个,表示只允许使用该 ID)。
如果 Pod 的安全上下文中相关定义中的任一字段在该范围之外,则会被拒绝创建。
下面展示一个例子:
runAsUser:
rule: MustRunAs
ranges: # 指定用户 ID 只能为 2
- min: 2
max: 2
fsGroup:
rule: MustRunAs
ranges: # 指定用户组 ID 范围只能为 2~10 和 20~30
- min: 2
max: 10
- min: 20
max: 30
supplementalGroups:
rule: MustRunAs
ranges: # 指定用户组 ID 范围只能为 2~10 和 20~30
- min: 2
max: 10
- min: 20
max: 30
🚀🚀🚀 对于 runAsUser
限定 Pod 运行时可使用的用户 ID 时,有两种情况需要注意:
Pod 定义中的安全上下文中指定限定范围外的用户 ID,即在
pod.spec.containers.securityContext.runAsUser
或pod.spec.securityContext.runAsUser
中指定 PodSecurityPolicy 中的podSecurityPolicy.spec.runAsUser.ranges
中指定的范围外的 ID 时,准入插件会将请求拒绝;容器的镜像中的默认用户 ID 在PodSecurityPolicy 中的
podSecurityPolicy.spec.runAsUser.ranges
中指定的范围外的 ID 时,PodSecurityPolicy 准入插件会将配置的用户 ID 覆盖容器中的默认 用户 ID;
配置允许、默认添加、禁止使用的内核功能
PodSecurityPolicy 允许在其定义中通过配置下面三个功能,分别配置 Pod 允许添加的内核功能、默认添加的内核功能以及禁止添加的内核功能:
allowedCapabilities
: 允许容器添加的内核功能;defaultAddCapabilities
: 默认为容器添加的内核功能;requiredDropCapabilities
: 要求容器禁用的内核功能;
下面展示一个例子:
spec:
allowedCapabilities: # 允许容器添加 SYS_TIME 功能。Pod 也可以不添加,要添加的话只能添加该列表以及 defaultAddCapabilities 列表中的
- SYS_TIME
defaultAddCapabilities: # 为每个容器添加 CHOWN 功能(会默认在 Pod 的安全上下文的 capabilities.add 列表中加上该字段的值)
- CHOWN
requiredDropCapabilities: # 要求容器禁用 SYS_ADMIN 和 SYS_MODULE 功能(会默认在 Pod 的安全上下文的 capabilities.drop 列表中加上该字段的值)
- SYS_ADMIN
- SYS_MODULE
限制 Pod 可使用的存储卷类型
在 PodSecurityPolicy 的定义的 spec.volumes
列表中可以指定 Pod 可使用的存储卷类型,若为 '*'
,则表示允许使用任意类型的存储卷,或者也可以通过指定卷类型名来单独制定。例如:
spec:
volumes:
- emptyDir
- configMap
- secret
- downwardAPI
- persistentVolumeClaim
为用户分配 PodSecurityPolicy
为指定用户分配 PodSecurityPolicy 资源需要配合 RBAC 机制 来实现。总共需要以下几步:
首先创建所需的 PodSecurityPolicy 资源;
然后创建 ClusterRole 资源指向该 PodSecurityPolicy 资源;
通过 ClusterRoleBinding 或 RoleBinding 将 ClusterRole 绑定至特定组或特定用户;
🦁 为用户分配 PodSecurityPolicy 的本质是让用户能够使用该资源,只要用户能够使用对应资源,那么这些 PodSecurityPolicy 就会限制该用户创建的 Pod。
听起来感觉用户有点贱,自己限制自己,其实不是这样的,集群管理员在分配用户权限时,往往不会授予其修改、甚至查看 PodSecurityPolicy 资源的权限。
下面展示一个例子。
用户的创建可以参考 minikube创建用户 章节,这里创建的用户名为 alice。
创建一个名为 psp-no-privileged
的 不允许创建特权模式容器的 Pod 的 PodSecurityPolicy,其 YAML 定义如下:
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: psp-no-privileged
spec:
privileged: false # 不允许使用特权模式的容器
readOnlyRootFilesystem: false
runAsUser:
rule: RunAsAny
fsGroup:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
seLinux:
rule: RunAsAny
volumes:
- '*'
创建一个名为 psp-no-privileged
的 ClusterRole,指向 psp-no-privileged
这个 PodSecurityPolicy,该 ClusterRole 使用能够执行的操作为 use,并且目前只能通过 YAML 文件定义,不能用命令行创建,定义如下:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: psp-no-privileged
rules:
- apiGroups: ["policy"]
resources: ["podsecuritypolicies"] # 限制的资源类型
verbs: ["use"] # 能够执行的操作为 use
resourceNames: ["psp-no-privileged"] # 精确到资源名
创建一个名为 psp-alice
的 ClusterRoleBinding,将名为 psp-no-privileged
的 ClusterRole 与 alice 这个用户进行绑定,该资源可以通过命令行创建,也可以通过 YAML 定义创建:
kubectl create clusterrolebinding psp-alice --clusterrole=psp-no-privileged --user=alice
上述流程执行完成后,用户 alice 目前可以使用该 PodSecurityPolicy 资源,即该用户创建的每个 Pod 请求会受该 PodSecurityPolicy 资源的限制。
Last updated
Was this helpful?