摘要:梳理准入插件、Pod Security Admission、动态 Webhook 与 CEL 策略,理解准入变更与校验、Pod 安全标准以及策略落地的适用边界。
例如:
某个开发人员拥有创建 Pod 的权限,但他提交了这样的配置:
apiVersion: v1kind: Podmetadata: name: dangerous-podspec: containers: - name: nginx image: nginx securityContext: privileged: true volumeMounts: - name: host-root mountPath: /host volumes: - name: host-root hostPath: path: /这个 Pod:
- 使用了特权容器。
- 挂载了宿主机根目录。
- 可能获得非常高的宿主机访问能力。
即使用户拥有创建 Pod 的权限,我们也不希望它被直接创建。
这时候就需要 Admission Control。
1. Admission Control 是什么?
Admission Control 中文叫准入控制。
它是 Kubernetes API Server 请求处理流程中的一个重要环节。
主要作用:
在资源对象被持久化到 etcd 之前,对请求进行额外的修改、检查或拒绝。
例如:
- 禁止创建特权容器。
- 限制 Pod 使用 hostPath。
- 强制容器设置资源限制。
- 自动注入 Sidecar。
- 强制使用指定镜像仓库。
- 检查资源是否符合企业安全规范。
1.1 API Server 的请求处理流程
先看完整流程:
flowchart TB
C["客户端 kubectl / API Client"] --> A["Authentication<br/>验证请求者身份"]
A --> R["Authorization<br/>检查 RBAC 等授权规则"]
subgraph AD["Admission 与对象校验"]
M["Mutating Admission<br/>修改资源对象"] --> V["对象校验"]
V --> P["Validating Admission<br/>验证资源是否符合策略"]
end
R --> M
P --> E["通过后保存到 etcd"]
注意:这是便于理解的逻辑示意。实际 API Server 内部还包括请求解码、默认值处理、对象校验、准入插件执行、存储前处理等阶段,具体顺序依赖请求类型和 Kubernetes 实现。
1.2 三个安全环节的区别
| 环节 | 解决的问题 | 示例 |
|---|---|---|
| Authentication | 你是谁? | Alice 身份认证成功 |
| Authorization | 你能做什么? | Alice 可以创建 Pod |
| Admission | 这个请求能否被接受? | 拒绝特权容器 |
举一个完整例子:
Alice 执行:
kubectl apply -f privileged-pod.yaml处理过程:
- API Server 验证 Alice 的客户端证书。
- RBAC 判断 Alice 是否拥有创建 Pod 的权限。
- Admission Control 检查 Pod 是否使用了不允许的配置。
- 如果触发安全策略,拒绝创建。
- 如果全部通过,继续完成资源持久化。
RBAC 负责控制操作权限,Admission Control 负责控制资源内容及请求是否符合策略。
2. Admission Control 的两种核心机制
Admission Control 最重要的两种机制:
- Mutating Admission:变更准入。
- Validating Admission:验证准入。
它们可以通过内置准入插件实现,也可以通过 Admission Webhook 扩展。
2.1 Mutating Admission:修改资源
Mutating Admission 的主要作用是:
在资源创建或更新过程中,自动修改资源对象。
例如,用户提交:
apiVersion: v1kind: Podmetadata: name: nginxspec: containers: - name: nginx image: nginx企业要求所有 Pod 必须设置 CPU 和内存请求值。
那么 Mutating Admission 可以自动添加:
resources: requests: cpu: 100m memory: 128Mi最终实际提交给后续处理阶段的对象就包含这些字段。
常见应用:
- 自动注入 Sidecar。
- 自动添加 Label。
- 自动设置默认值。
- 自动注入环境变量。
- 自动设置资源请求和限制。
2.2 Validating Admission:验证资源
Validating Admission 的主要作用是:
检查资源对象是否符合安全策略和业务规则,不符合则拒绝请求。
例如:
securityContext: privileged: true企业禁止所有业务容器使用特权模式。
Validating Admission 就可以拒绝这个 Pod。
常见应用:
- 禁止特权容器。
- 禁止使用 latest 镜像标签。
- 限制镜像仓库。
- 限制 HostPath。
- 强制使用指定标签。
- 检查资源配额和业务规则。
2.3 两者有什么区别?
| 比较 | Mutating | Validating |
|---|---|---|
| 中文 | 变更准入 | 验证准入 |
| 主要作用 | 修改对象 | 检查对象 |
| 能否修改对象 | 可以 | 不可以 |
| 能否拒绝请求 | 可以 | 可以 |
| 典型场景 | 自动注入 Sidecar | 禁止特权容器 |
例如:
假设企业有以下要求:
- 所有 Pod 自动添加
company=demo标签。 - 禁止 Pod 使用特权容器。
可以分别使用:
- Mutating:自动添加标签。
- Validating:检查是否使用特权容器。
两者组合后,就形成了一套准入策略。
3. Kubernetes 内置 Admission Controllers
前面讲的是准入控制的基本原理。实际上,Kubernetes 已经内置了很多 Admission Controller,不需要我们自己开发 Webhook。
它们直接集成在 API Server 中。
3.1 常见内置准入控制器
| Admission Controller | 主要作用 |
|---|---|
| NamespaceLifecycle | 防止在不存在或正在删除的 Namespace 中创建资源 |
| LimitRanger | 限制资源使用,并可设置默认 requests/limits |
| ResourceQuota | 限制 Namespace 的资源总量 |
| ServiceAccount | 自动化处理 ServiceAccount 相关配置 |
| DefaultStorageClass | 为未指定 StorageClass 的 PVC 设置默认存储类 |
| DefaultIngressClass | 为未指定 IngressClass 的 Ingress 设置默认类别 |
| PodSecurity | 执行 Pod 安全标准检查 |
| RuntimeClass | 处理 RuntimeClass 和 Pod Overhead |
| MutatingAdmissionWebhook | 调用变更型 Webhook |
| ValidatingAdmissionWebhook | 调用验证型 Webhook |
这些控制器分别负责不同的安全和资源管理任务。
官方文档:Admission Controllers 官方说明。
3.2 NamespaceLifecycle
这个控制器负责 Namespace 生命周期相关的保护。
例如:
kubectl create namespace testkubectl delete namespace test当 Namespace 进入 Terminating 状态时,不允许继续在其中创建新的普通资源。
它还会防止删除一些系统保留 Namespace,例如:
defaultkube-systemkube-public这可以避免误操作破坏集群基础环境。
3.3 LimitRanger
LimitRanger 负责限制 Namespace 内资源的使用,并且能够为没有设置资源请求的容器提供默认值。
如果用户设置的资源超过最大值,则会被拒绝。
注意:LimitRange 定义约束,LimitRanger 准入插件负责执行这些约束。
3.4 ResourceQuota
ResourceQuota 负责限制 Namespace 的资源总量。
如果用户继续创建 Pod,导致资源总量超过配额,准入阶段就会拒绝请求。
这里要区分:
- ResourceQuota:定义资源配额。
- LimitRange:定义单个对象或容器的资源限制及默认值,由 LimitRanger 准入插件执行。
它们经常结合使用。
4. Pod Security Admission(PSA):Pod 安全准入
4.1 为什么需要 PSA?
假设开发人员有创建 Pod 的权限。
他可能创建:
securityContext: privileged: true或者:
volumes: - name: host hostPath: path: /这些配置可能让容器获得宿主机敏感资源的访问能力。
如果只依赖 RBAC,就很难针对 Pod 的具体安全字段进行精细约束。
Kubernetes 因此提供了 Pod Security Admission(PSA)。
它根据 Pod Security Standards(PSS)定义的安全标准,检查 Pod 是否符合要求。
PSA 自 Kubernetes 1.25 起稳定提供。
官方文档:Pod Security Admission。
4.2 三种安全级别
Pod Security Standards 定义了三个安全级别:
Privileged
最低限制
几乎不施加 PSS 安全限制,适用于需要特殊系统权限的可信工作负载。
Baseline
基础安全
防止已知的权限提升和常见危险配置,适用于一般业务工作负载。
Restricted
严格限制
执行更严格的安全约束,要求容器遵循更完善的安全配置。
三个级别的限制关系:
flowchart TB
P["Privileged<br/>最低限制"] -->|"约束增加"| B["Baseline<br/>基础安全"]
B -->|"约束增加"| R["Restricted<br/>严格限制"]
从上到下,安全约束逐渐严格。
4.3 PSA 的三种模式
PSA 还提供三种执行模式:
| 模式 | 作用 |
|---|---|
| enforce | 违反策略的 Pod 直接拒绝创建 |
| audit | 允许创建,但记录违规信息到审计事件 |
| warn | 允许创建,同时向客户端返回警告 |
注意:audit 模式记录的是 Kubernetes 审计事件相关信息,不代表一定会自动保存完整审计日志;还需要配置审计策略和日志后端。
三种模式可以同时使用。
例如:
apiVersion: v1kind: Namespacemetadata: name: dev labels: pod-security.kubernetes.io/enforce: baseline pod-security.kubernetes.io/audit: restricted pod-security.kubernetes.io/warn: restricted这段配置表示:
- enforce:必须符合 Baseline。
- audit:记录不符合 Restricted 的情况。
- warn:向用户提示不符合 Restricted 的情况。
这种配置非常适合生产环境的渐进式安全改造。
4.4 PSA 常见安全约束
Restricted 模式会涉及很多安全要求,例如:
| 安全配置 | 主要要求 |
|---|---|
| privileged | 不允许特权容器 |
| allowPrivilegeEscalation | 必须设置为 false |
| capabilities | 必须 drop: ALL,只允许添加 NET_BIND_SERVICE |
| runAsNonRoot | 必须以非 root 用户运行 |
| seccompProfile | 使用 RuntimeDefault 或 Localhost |
| hostNetwork | 不允许使用 HostNetwork |
| hostPID | 不允许使用 HostPID |
| hostIPC | 不允许使用 HostIPC |
| hostPath | Restricted 不允许使用 HostPath 卷 |
注意:Baseline 与 Restricted 的具体规则不同。不能把所有安全限制都简单归到 Baseline。部分限制与 Pod 操作系统及所选 PSS 版本有关。
4.5 PSA 与旧版 PodSecurityPolicy
早期 Kubernetes 使用 PodSecurityPolicy(PSP)实现 Pod 安全限制。
但 PSP 已在 Kubernetes 1.25 移除。
现在主要使用:
- Pod Security Admission。
- ValidatingAdmissionPolicy。
- Admission Webhook。
5. Admission Webhook:动态准入控制
前面介绍的 PSA 和内置 Admission Controller 能解决很多问题。
但企业可能有更复杂的需求。
例如:
- 所有镜像必须来自公司私有镜像仓库。
- Deployment 必须设置指定业务标签。
- 禁止使用未经批准的镜像版本。
- 创建 Pod 时自动注入安全代理。
- 根据业务系统的配置判断资源是否合法。
内置插件无法覆盖所有业务场景。
因此 Kubernetes 提供了 Admission Webhook。
5.1 Webhook 是什么?
Webhook 可以理解为:
API Server 在处理资源请求时,向外部 HTTPS 服务发送请求,让外部程序决定是否修改或允许这个资源。
例如:
用户提交一个 Pod:
apiVersion: v1kind: Podmetadata: name: nginxspec: containers: - name: nginx image: nginxAPI Server 将请求发送给 Webhook 服务。
Webhook 可以:
- 修改 Pod。
- 检查 Pod。
- 拒绝 Pod。
整个流程:
flowchart TB
C["kubectl apply<br/>提交 Pod YAML"] --> A["Kubernetes API Server<br/>认证、授权及准入处理"]
A -->|"HTTPS AdmissionReview 请求"| W["外部 Webhook Server<br/>执行自定义业务逻辑"]
W -->|"返回 AdmissionReview 响应"| D{"准入决定"}
D -->|"允许 / 修改"| P["API Server 继续处理"]
D -->|"拒绝"| E["返回错误"]
Webhook 需要遵循 Kubernetes 定义的 AdmissionReview 请求和响应格式。
5.2 两种 Webhook
Kubernetes 有两种主要的 Webhook 配置对象:
| Webhook 类型 | 配置对象 | 作用 |
|---|---|---|
| Mutating | MutatingWebhookConfiguration | 修改资源 |
| Validating | ValidatingWebhookConfiguration | 验证资源 |
例如:
假设公司要求所有 Pod 自动添加:
metadata: labels: company: demo可以开发 Mutating Webhook。
假设公司要求禁止使用:
image: nginx:latest可以开发 Validating Webhook。
5.3 Webhook 如何匹配请求?
Webhook 并不是接收所有 API 请求。
管理员可以指定匹配条件:
rules: - operations: - CREATE - UPDATE apiGroups: - "" apiVersions: - v1 resources: - pods scope: Namespaced含义:
- operations:匹配创建和更新。
- apiGroups:核心 API 组。
- apiVersions:v1。
- resources:Pod。
- scope:只匹配 Namespace 资源。
这样,Webhook 就只会接收符合条件的请求。
5.4 Validating Webhook 配置示例
下面展示一个简化的配置结构:
apiVersion: admissionregistration.k8s.io/v1kind: ValidatingWebhookConfigurationmetadata: name: pod-policywebhooks: - name: pod-policy.example.com admissionReviewVersions: - v1 sideEffects: None failurePolicy: Fail clientConfig: service: namespace: security name: policy-webhook path: /validate port: 443 caBundle: BASE64_CA_CERT rules: - operations: - CREATE - UPDATE apiGroups: - "" apiVersions: - v1 resources: - pods scope: Namespaced重点理解以下字段:
| 字段 | 作用 |
|---|---|
| name | Webhook 名称 |
| admissionReviewVersions | 支持的请求版本 |
| sideEffects | 声明是否产生副作用 |
| failurePolicy | Webhook 调用失败时如何处理 |
| clientConfig | Webhook 服务地址与 CA |
| rules | 匹配哪些 API 请求 |
5.5 failurePolicy:非常重要
这个参数直接影响集群可用性。
有两个主要选项:
Fail
如果 Webhook 无法正常调用,API 请求失败。
failurePolicy: Fail例如:
Webhook 服务宕机,用户创建 Pod 就可能失败。
Ignore
如果 Webhook 无法正常调用,API Server 忽略这次调用失败,继续处理请求。
failurePolicy: Ignore例如:
Webhook 服务宕机,Pod 仍可能被创建。
两者区别:
| 配置 | Webhook 不可用时 | 安全性与可用性 |
|---|---|---|
| Fail | 拒绝请求 | 策略强制性更高,但可能影响可用性 |
| Ignore | 跳过该 Webhook | 可用性较高,但可能绕过策略 |
failurePolicy 处理调用错误或超时。Webhook 明确返回拒绝时,Ignore 不会将该拒绝改为允许。
生产环境需要根据策略的重要程度选择。
例如:
- 强制执行的安全策略,通常考虑 Fail。
- 非关键的辅助校验,可以考虑 Ignore。
但不能简单认为 Fail 永远更安全,因为 Webhook 服务自身如果没有高可用设计,可能导致整个集群无法创建或更新相关资源。
5.6 Webhook 为什么需要 TLS?
API Server 调用 Webhook 时通常使用 HTTPS。
因此需要配置:
clientConfig: service: namespace: security name: policy-webhook path: /validate port: 443 caBundle: BASE64_CA_CERT其中:
- service:Webhook 的 Kubernetes Service。
- caBundle:用于验证 Webhook 服务端证书的 CA。
注意:客户端验证 API Server、API Server 验证客户端证书,以及 API Server 验证 Webhook 服务,是不同方向的信任关系。这里的 caBundle 用于 API Server 验证 Webhook 服务端证书。
5.7 Webhook 的生产环境注意事项
Webhook 运行在 API Server 的关键请求链路上,设计不当会影响整个集群。
需要特别注意:
- Webhook 服务必须具备高可用能力。
- 设置合理的
timeoutSeconds。 - 只匹配需要检查的 API 请求,避免拦截所有资源。
- 使用
namespaceSelector、objectSelector缩小范围。 - 对修改操作保证幂等性。
- 避免 Webhook 调用 API Server 产生循环依赖。
- 谨慎设计
failurePolicy。
特别是循环依赖:
例如 Webhook 服务自身运行在 Kubernetes 中,而 Webhook 服务 Pod 的创建又必须调用该 Webhook。
如果 Webhook 服务还没有启动,就可能出现:
flowchart TB
P["创建 Webhook Pod"] --> A["API Server 调用 Webhook"]
A --> W["Webhook 服务尚未启动"]
W --> F["Pod 创建失败"]
F --> U["Webhook 服务无法启动"]
U -.->|"后续调用仍然失败"| A
这可能造成集群中的工作负载无法正常创建。
因此生产部署通常需要设置合理的排除规则和启动策略。
参考:Dynamic Admission Control、Admission Webhook Good Practices。
6. ValidatingAdmissionPolicy:使用 CEL 实现准入策略
这里介绍一个比传统 Webhook 更轻量的方式。
在 Kubernetes 中,很多准入规则其实并不复杂。
例如:
- 禁止使用
latest镜像标签。 - 要求必须包含某个 Label。
- 限制 Deployment 的副本数量。
- 限制容器的某些安全配置。
如果每个规则都开发一个 Webhook 服务,会增加很多运维成本。
Kubernetes 提供了:
ValidatingAdmissionPolicy(VAP)
它使用 CEL(Common Expression Language)表达式,直接在 API Server 内部执行资源验证。
6.1 CEL 是什么?
CEL 是一种轻量级表达式语言。
例如:
object.metadata.name == "nginx"意思是:
资源名称必须为 nginx。
再看:
object.spec.replicas <= 5意思是:
Deployment 的副本数量不能超过 5。
CEL 常用于:
- 条件判断。
- 字段检查。
- 数组遍历。
- 资源内容校验。
6.2 创建 ValidatingAdmissionPolicy
假设我们规定:
所有 Deployment 的副本数量不能超过 5。
创建:
apiVersion: admissionregistration.k8s.io/v1kind: ValidatingAdmissionPolicymetadata: name: deployment-replica-limitspec: failurePolicy: Fail matchConstraints: resourceRules: - apiGroups: ["apps"] apiVersions: ["v1"] operations: ["CREATE", "UPDATE"] resources: ["deployments"] validations: - expression: "object.spec.replicas <= 5" message: "Deployment replicas cannot exceed 5"这里:
- matchConstraints:决定哪些请求需要检查。
- validations:定义 CEL 验证表达式。
- message:验证失败时显示的信息。
6.3 创建 Binding
仅创建 Policy 还不够。
还需要通过 Binding 将策略关联到实际请求范围,并指定执行动作。
apiVersion: admissionregistration.k8s.io/v1kind: ValidatingAdmissionPolicyBindingmetadata: name: deployment-replica-limit-bindingspec: policyName: deployment-replica-limit validationActions: - Deny matchResources: namespaceSelector: matchLabels: environment: production现在只有带有:
environment: production标签的 Namespace 才会应用这条策略。
6.4 ValidatingAdmissionPolicy 与 Webhook 区别
| 比较 | ValidatingAdmissionPolicy | Validating Webhook |
|---|---|---|
| 实现方式 | CEL 表达式 | 外部 HTTP 服务 |
| 是否需要部署服务 | 不需要 | 需要 |
| 复杂业务逻辑 | 适合简单规则 | 适合复杂规则 |
| 外部系统调用 | 不支持任意外部调用 | 可以自行实现 |
| 运维复杂度 | 较低 | 相对较高 |
| 执行位置 | API Server 内部 | 外部 Webhook 服务 |
在较新的 Kubernetes 版本中,MutatingAdmissionPolicy 也提供了基于 CEL 的声明式修改能力。
它与 ValidatingAdmissionPolicy 相对应:
- ValidatingAdmissionPolicy:检查资源。
- MutatingAdmissionPolicy:修改资源。
版本方面要特别注意:
- ValidatingAdmissionPolicy 从 Kubernetes 1.30 起稳定提供。
- MutatingAdmissionPolicy 在 Kubernetes 1.36 起进入稳定阶段。
具体是否可用,应以目标集群版本和 API 发现结果为准。官方参考:Kubernetes Admission Policies 教程。
7. Admission Controller 如何启用和查看?
现在理解一下 Admission Controller 在 API Server 中是如何工作的。
7.1 查看 API Server 配置
在 kubeadm 集群中:
cat /etc/kubernetes/manifests/kube-apiserver.yaml查找:
- --enable-admission-plugins=NodeRestriction,PodSecurity,...这个参数用于指定启用的内置准入插件。
也可以指定:
- --disable-admission-plugins=SomePlugin禁用指定插件。
注意:不要随意禁用系统关键插件,例如 ServiceAccount、NamespaceLifecycle、ResourceQuota 等,否则可能破坏集群预期功能。
7.2 查看当前集群的准入插件
可以查看 API Server 的帮助信息:
kube-apiserver -h | grep enable-admission-plugins不过,这只能看到当前二进制支持的插件及相关参数说明,并不能直接反映运行中集群实际启用了哪些插件。
实际启用情况还需要结合:
kubectl get pods -n kube-system以及 API Server 静态 Pod 配置进行判断。
7.3 查看 Webhook 配置
查看变更型 Webhook:
kubectl get mutatingwebhookconfigurations查看验证型 Webhook:
kubectl get validatingwebhookconfigurations查看某个 Webhook:
kubectl describe validatingwebhookconfiguration pod-policy7.4 查看 Admission Policy
查看验证型策略:
kubectl get validatingadmissionpolicies查看绑定:
kubectl get validatingadmissionpolicybindings查看变更型策略(目标集群支持时):
kubectl get mutatingadmissionpolicies8. Admission Control 的适用边界
这一部分非常重要,避免把准入控制理解成万能安全机制。
8.1 Admission 不负责普通读取请求
例如:
kubectl get podskubectl get serviceskubectl get nodes这些读取操作通常不会经过 Admission Control。
Admission 主要处理创建、修改、删除等请求,以及某些连接类操作。
因此:
- RBAC 控制谁能读取 Pod。
- Admission 控制符合条件的创建、修改等请求。
例如,一个用户没有读取 Secret 的权限,应该由 RBAC 拒绝,而不是依赖 Admission。
8.2 Admission 不能替代 RBAC
假设:
用户 Alice 没有创建 Pod 的权限。
即使 Pod 完全符合安全策略,也不能创建成功。
因为请求已经在 Authorization 阶段被拒绝。
反过来:
用户 Bob 有创建 Pod 的权限,但 Pod 使用了特权模式。
如果 PSA 或其他准入策略禁止特权模式,请求仍然会被拒绝。
因此,两者必须结合。
8.3 Admission 不能替代运行时安全
假设 Pod 创建时符合所有安全策略。
但应用程序运行之后,可能出现:
- 容器进程被攻击。
- 应用程序发生内存漏洞。
- 恶意程序执行异常操作。
- 容器访问不应该访问的网络服务。
这些问题不属于单纯的准入控制范围。
还需要结合:
- Linux Namespace。
- Linux Capabilities。
- Seccomp。
- AppArmor。
- SELinux。
- NetworkPolicy。
- 容器运行时安全监控。
这也解释了为什么 Kubernetes 安全不是只靠 RBAC 或 Admission 就能完成的。
参考资料: