简介
原生 Kubernetes 存在级联删除机制,删除一个资源时会自动删除与之相关的其他资源,例如删除 Namespace 时会自动删除 Namespace 下所有的 Pod、Service、ConfigMap 等关联资源,可能导致业务故障。
K8S 自身的脆弱性会导致在生产环境存在稳定性和安全的风险,例如用户配置的镜像拉取来源没有限制,可能导致镜像被篡改;缺少容器级别的安全隔离策略,可能导致容器发生越权等行为。
容器服务(Tencent Kubernetes Engine,TKE)提供“策略管理”能力,通过系统预置策略或者用户自主开启策略的方式,防止误删除引起业务故障,支持通过对计算资源、网络资源进行策略的加固,提升 TKE 集群的稳定性和安全性。
策略说明
策略分类
删除防护:包含集群删除保护和集群内资源删除保护。在删除 TKE 集群内的各类资源时,如果资源正在使用中,或者存在和其他资源之间的引用关系,则不允许删除。
策略管控:用于约束和规范 K8S 集群内的资源配置。例如:要求 Pod 具有 Readiness 或 Liveness Probe;限制容器镜像来源必须在指定的列表内等。
安全加固:包含 PSP(PodSecurityPolicy)相关策略。TKE 提供基于 gatekeeper 的安全防护能力。例如,禁止创建特权容器,约束 PodSecurityPolicy 中的 hostPath、hostPID 和 hostIPC 字段等。
支持边界
支持1.16及以上 K8S 版本的 TKE 标准集群和 TKE Serverless 集群,暂不支持注册集群和边缘集群。
策略类型
基线策略:TKE 内置的策略,包含保护集群基础设施资源不被误删除等策略。
优选策略:TKE 最佳实践形成的标准和规范,对用户的各项配置进行校验,使得用户请求符合约束。用户可根据实际情况开启策略,并设置策略运行模式。
可选策略:官方 OPA gatekeeper 策略库支持的策略,包含替代 PSP 能力的策略和通用策略。用户可以根据实际情况,自行创建策略实例,具体创建流程请参见 新建策略实例。
策略库
基线策略
策略分类 | 策略名称 | 策略描述 | 拦截对象 | 运行模式 |
删除保护 | 存在节点的集群不允许删除 | 集群中存在任意节点(普通节点、原生节点、注册节点),需先下线节点后方可删除。 | 集群 | 默认 deny |
优选策略
策略分类 | 策略名称 | 策略描述 | 拦截对象 | 运行模式 |
删除保护 | 存在 pod 的命名空间不允许删除 | 命名空间内如果存在 pod,需先清除 pod 后方可删除 namespace。 | Namespace | 默认 dryrun |
删除保护 | 存在 cr 的 crd 不允许删除 | crd 定义的 apiversion 下如果有创建 cr 资源,则清空 cr 后方可删除 crd。 | CRD | 默认 dryrun |
删除保护 | 非封锁状态的 Node 不允许删除 | 节点处于非封锁状态不允许删除。 | Node | 默认不创建策略实例 |
删除保护 | CoreDNS 组件删除保护 | 禁止删除 CoreDNS 组件的 Service、ConfigMap 和 Deployment。 | Deployment、Service、ConfigMap | 默认不创建策略实例 |
删除保护 | 资源删除保护 | 存在指定 Label 的资源(Service、Ingress、Deployment、StatefulSet)不允许被删除。 | Service、Ingress、Deployment、StatefulSet | 默认不创建策略实例 |
删除保护 | PV 处于绑定状态则不允许删除 | PersistentVolume 如果处于 Bound 状态,则不允许被删除。 | PV | 默认不创建策略实例 |
策略管控 | 禁止挂载指定的 volume 类型 | 将可挂载的 volume 类型限制为用户指定的类型。 | Pod | 默认不创建策略实例 |
策略管控 | 禁止镜像拉取策略使用 Always | 禁止容器使用 Always 镜像拉取策略,减少对镜像仓库的访问。 | Pod | 默认不创建策略实例 |
策略管控 | 容器镜像来源限制 | 只允许从指定的镜像仓库拉取镜像。 | Pod | 默认不创建策略实例 |
策略管控 | 禁止未知的 DaemonSet 部署 | 只允许部署指定的 DaemonSet。 | DaemonSet | 默认不创建策略实例 |
策略管控 | 工作负载镜像版本升级策略管控 | 限制 Deployment 和 DaemonSet 只能在配置的镜像列表中升级。 | Deployment、DaemonSet | 默认不创建策略实例 |
策略管控 | ServiceAccount 权限管控 | 禁止 ServiceAccount 绑定较大权限的 Role 和 ClusterRole,提升集群安全性。 | ServiceAccount | 默认不创建策略实例 |
策略管控 | 不允许 Service 为 ClusterIP 类型 | 禁止创建 ClusterIP 类型的 Service 或将 Service 由其他类型更新为 ClusterIP 类型。 | Service | 默认不创建策略实例 |
策略管控 | 禁止公网访问 | 禁止通过创建公网类型的 Service 或 Ingress 的方式将后端服务暴露到公网。 | Service、Ingress | 默认不创建策略实例 |
策略管控 | 弹性网卡资源配置限制 | 限制跨租户弹性网卡必须配置 Request 资源。 | Pod | 默认不创建策略实例 |
可选策略
策略分类 | 策略名称 | 策略描述 | 拦截对象 |
策略管控 | tkeblockvolumemountpath | 禁止容器挂载指定的目录。 | pods |
策略管控 | k8sallowedrepos | 容器镜像必须以指定字符串列表中的字符串开头。 | pods |
策略管控 | k8spspautomountserviceaccounttokenpod | 约束容器不能设置 automountServiceAccountToken 为 true。 | pods |
策略管控 | k8sblockendpointeditdefaultrole | 默认情况下,许多 Kubernetes 都预定义了一个名为 system:aggregate-to-edit 的 ClusterRole,k8sblockendpointeditdefaultrole 策略定义禁止该 ClusterRole 对 Endpoints 进行 create、patch 和 update 操作。 | clusterroles |
策略管控 | k8sblockloadbalancer | 不允许 Service 为 LoadBalancer 类型。 | services |
策略管控 | k8sblocknodeport | 不允许 Service 为 NodePort 类型。 | services |
策略管控 | k8sblockwildcardingress | 禁止 ingress 配置空白或通配符类型的 hostname。 | ingresses |
策略管控 | k8scontainerlimits | 限制容器必须设置 CPU 和内存 Limit,并且小于设定的最大值。 | pods |
策略管控 | k8scontainerrequests | 限制 CPU 和内存的 Request 必须设置且小于配置的最大值。 | pods |
策略管控 | k8scontainerratios | 限制 CPU 和内存的 Request 与 Limit 的最大比率。 | pods |
策略管控 | k8srequiredresources | 必须配置内存的 Limit,CPU 和内存的 Request。 | pods |
策略管控 | k8sdisallowanonymous | 不允许将白名单以外的 ClusterRole 和 Role 关联到 system:anonymous User 和 system:unauthenticated Group。 | rolebindings
clusterrolebindings |
策略管控 | k8sdisallowedtags | 约束容器镜像 tag。 | pods |
策略管控 | k8sexternalips | 限制服务 externalIP 仅为允许的 IP 地址列表。 | services |
策略管控 | k8simagedigests | 容器镜像必须包含 digest。 | pods |
策略管控 | noupdateserviceaccount | 拒绝白名单外的资源更新 ServiceAccount。 | replicationcontrollers
replicasets
deployments
statefulsets
daemonsets
cronjobs |
策略管控 | k8sreplicalimits | 要求具有 “spec.replicas” 字段的对象(Deployments、ReplicaSets等)在定义的范围内。 | deployments |
策略管控 | k8srequiredannotations | 要求资源包含指定的 annotations,其值与提供的正则表达式匹配。 | services |
策略管控 | k8srequiredlabels | 要求资源包含指定的标签,其值与提供的正则表达式匹配。 | namespaces |
策略管控 | k8srequiredprobes | 要求 Pod 具有 Readiness 或 Liveness Probe。 | pods |
安全加固 | k8spspallowprivilegeescalationcontainer | 约束 PodSecurityPolicy 中的 “allowPrivilegeEscalation” 字段为 false。 | pods |
安全加固 | k8spspapparmor | 约束 AppArmor 字段列表。 | pods |
安全加固 | k8spspcapabilities | 限制 PodSecurityPolicy 中的 “allowedCapabilities” 和 “requiredDropCapabilities” 字段。 | pods |
安全加固 | k8spspflexvolumes | 约束 PodSecurityPolicy 中的 allowedFlexVolumes 字段类型。 | pods |
安全加固 | k8spspforbiddensysctls | 约束 PodSecurityPolicy 中的 “sysctls” 字段不能使用的 name。 | pods |
安全加固 | k8spspfsgroup | 控制 PodSecurityPolicy 中的 “fsGroup” 字段在限制范围内。 | pods |
安全加固 | k8spsphostfilesystem | 约束 PodSecurityPolicy 中的 “hostPath” 字段的参数。 | pods |
安全加固 | k8spsphostnamespace | 限制 PodSecurityPolicy 中的 “hostPID” 和 “hostIPC” 字段。 | pods |
安全加固 | k8spsphostnetworkingports | 约束 PodSecurityPolicy 中的 “hostNetwork” 和 “hostPorts” 字段。 | pods |
安全加固 | k8spspprivilegedcontainer | 禁止 PodSecurityPolicy 中的 “privileged” 字段为 true。 | pods |
安全加固 | k8spspprocmount | 约束 PodSecurityPolicy 中的 “allowedProcMountTypes” 字段。 | pods |
安全加固 | k8spspreadonlyrootfilesystem | 约束 PodSecurityPolicy 中的 “readOnlyRootFilesystem” 字段。 | pods |
安全加固 | k8spspseccomp | 约束 PodSecurityPolicy 上的 “seccomp.security.alpha.kubernetes.io/allowedProfileNames” 注解。 | pods |
安全加固 | k8spspselinuxv2 | 约束 Pod 定义 SELinux 配置的允许列表。 | pods |
安全加固 | k8spspallowedusers | 约束 PodSecurityPolicy 中的runAsUser、runAsGroup、supplementalGroups 和 fsGroup 字段。 | pods |
安全加固 | k8spspvolumetypes | 约束 PodSecurityPolicy 中的 “volumes” 字段类型。 | pods |
操作说明
开启/关闭策略
1. 登录 容器服务控制台,选择左侧导航栏中的集群。
2. 在集群管理页面,选择目标集群 ID,进入集群的基本信息页面。
3. 在左侧导航中选择策略管理,进入策略管理页面选择策略,单击开启/关闭。关闭策略需要二次确认,开启则不需要。如下图所示:
验证策略效果
以集群删除策略为例,创建 TKE 标准集群,验证集群在存在节点情况下删除请求是否会被拦截。
1. 创建有节点的 TKE 标准集群,详细步骤请参见 创建集群。
2. 发起删除集群请求。
3. 在策略管理页面,单击关联事件的数字,查看拦截事件信息。如下图所示:
新建策略实例
以禁止创建特权容器为例,演示如何新建策略实例。
策略名称:k8spspprivilegedcontainer
策略类型:K8sPSPPrivilegedContainer
策略描述:禁止 Pod securityContext 中的 privileged 字段为 true。
生效资源类型:Pod
需要修改的参数如下:
namespaces 可选参数:表示策略作用生效的命名空间。
不填该字段或者字段取值为空时,表示所有命名空间都生效。
支持前缀匹配,例如 namespaces: ["kube-*"] 匹配 "kube-system" 和 "kube-public"。
excludedNamespaces 可选参数:表示策略豁免生效的命名空间,在该列表中的命名空间不会生效此条策略。
不填该字段或者字段取值为空时,表示没有豁免的命名空间。
支持前缀匹配,例如 excludedNamespaces: ["kube-*"] 匹配 "kube-system" 和 "kube-public"。
exemptInitContainers 自定义参数:布尔值。含义:是否允许 initContainer 使用特权容器。
部分业务的 initContainer 以特权容器的方式运行,执行类似 iptables 规则下发等操作。
创建策略实例时,默认会允许 initContainer 使用特权容器。
策略实例 YAML:
apiVersion: constraints.gatekeeper.sh/v1beta1kind: K8sPSPPrivilegedContainermetadata:name: psp-privileged-containerspec:match:kinds:- apiGroups: [""]kinds: ["Pod"]namespaces: []excludedNamespaces: ["kube-system"]parameters:exemptInitContainers: true
测试策略是否生效的 Pod YAML 如下,直接 apply YAML,会被策略拦截,则表明策略已生效。
apiVersion: v1kind: Podmetadata:name: privileged-podspec:containers:- name: privileged-containerimage: nginxsecurityContext:privileged: trueinitContainers:- name: privileged-init-containerimage: busyboxcommand: ['sh', '-c', 'echo Hello, Kubernetes!']securityContext:privileged: true
创建一个特权容器的 Pod,预期输出:
Error from server (Forbidden): error when creating "pod.yaml": admission webhook "validation.gatekeeper.sh" denied the request: [psp-privileged-container] Privileged container is not allowed: privileged-container, securityContext: {"privileged": true}, Pod name: privileged-pod