Kubernetes 准入控制基础:Admission Webhook 原理与配置
在 Kubernetes 集群中,准入控制(Admission Control)是 API 请求到达 etcd 持久化之前的最后一道内置防线。对于多集群门禁场景,原生内置的准入插件(如 PodSecurity、ResourceQuota)无法满足自定义策略的灵活性和动态性,因此 Admission Webhook 成为扩展准入逻辑的核心机制。本章将深入剖析 Webhook 的工作原理、两种类型(Mutating vs Validating)的差异,并给出可直接复用的配置示例。
2.1 Admission Webhook 工作原理
Admission Webhook 本质上是一个由集群外部 HTTP 回调服务(通常部署在集群内)处理的准入插件。当用户通过 kubectl、API 或控制器发起资源变更请求时,Kubernetes API Server 会按照以下流程执行准入控制:
- 认证与授权:验证请求者身份和权限。
- Mutating Admission:依次执行所有 Mutating Webhook,允许修改请求对象(如注入 Sidecar、设置默认值)。
- 对象验证:对修改后的对象进行 Schema 校验。
- Validating Admission:依次执行所有 Validating Webhook,检查对象是否符合业务策略(如禁止特权容器、检查镜像来源)。
- 持久化:通过所有准入检查后,对象写入 etcd。
关键时序点:Mutating Webhook 在对象 Schema 校验之前执行,因此可以修改请求内容;Validating Webhook 在 Schema 校验之后执行,只能读取最终对象并决定接受或拒绝。
2.2 Mutating 与 Validating Webhook 区别
两种 Webhook 在职责、执行顺序和副作用控制上有本质区别。下表从多个维度进行对比:
| 对比维度 | Mutating Webhook | Validating Webhook |
|---|---|---|
| 执行顺序 | 先执行(在 Schema 校验前) | 后执行(在 Schema 校验后) |
| 核心能力 | 修改请求对象(注入、默认值、补丁) | 只读检查,拒绝不符合策略的请求 |
| 副作用风险 | 高:多个 Mutating Webhook 可能冲突 | 低:不修改对象,仅返回 allow/deny |
| 典型场景 | Sidecar 注入、资源标签标准化、默认资源限制 | 安全策略检查、镜像来源白名单、合规审计 |
| 失败策略 | failurePolicy: Fail 或 Ignore |
通常设为 Fail 防止绕过策略 |
| 超时控制 | 默认 30 秒,建议 ≤10 秒 | 默认 30 秒,建议 ≤5 秒 |
最佳实践:在多集群门禁场景中,Validating Webhook 更适合覆盖高风险变更(如删除 Namespace、修改集群角色绑定),因为其只读特性不会引入副作用;Mutating Webhook 则用于自动修复不合规配置(如为未设置资源限制的 Pod 注入默认值)。
2.3 Webhook 配置示例
以下是一个完整的 Validating Webhook 配置示例,用于拒绝创建特权容器(SecurityContext.Privileged=true)。该配置可直接应用于多集群门禁场景,作为高风险变更的拦截层。
2.3.1 部署 Webhook 服务(Deployment + Service)
apiVersion: apps/v1
kind: Deployment
metadata:
name: policy-webhook
namespace: kube-system
spec:
replicas: 2
selector:
matchLabels:
app: policy-webhook
template:
metadata:
labels:
app: policy-webhook
spec:
containers:
- name: webhook
image: registry.example.com/policy-webhook:v1.0.0
ports:
- containerPort: 8443
volumeMounts:
- name: tls-certs
mountPath: /etc/webhook/certs
readOnly: true
volumes:
- name: tls-certs
secret:
secretName: webhook-tls
---
apiVersion: v1
kind: Service
metadata:
name: policy-webhook
namespace: kube-system
spec:
ports:
- port: 443
targetPort: 8443
selector:
app: policy-webhook
2.3.2 创建 ValidatingWebhookConfiguration
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: deny-privileged-pods
webhooks:
- name: deny-privileged.policy.example.com
clientConfig:
service:
name: policy-webhook
namespace: kube-system
path: /validate
caBundle: <base64-encoded-ca-cert>
rules:
- operations: ["CREATE", "UPDATE"]
apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
scope: "Namespaced"
failurePolicy: Fail
matchPolicy: Equivalent
timeoutSeconds: 5
sideEffects: None
admissionReviewVersions: ["v1"]
objectSelector:
matchExpressions:
- key: security-tier
operator: NotIn
values:
- system-critical
关键配置说明:
failurePolicy: Fail:当 Webhook 服务不可用时,拒绝所有请求,防止策略绕过。timeoutSeconds: 5:超时时间设为 5 秒,避免 API Server 等待过久。sideEffects: None:声明 Webhook 无副作用,允许 API Server 在 dry-run 模式下调用。objectSelector:通过标签选择器排除系统关键命名空间,避免误拦截。
2.3.3 Webhook 服务端核心逻辑(伪代码)
// 处理 AdmissionReview 请求
func handleValidate(w http.ResponseWriter, r *http.Request) {
var review admissionv1.AdmissionReview
json.NewDecoder(r.Body).Decode(&review)
pod := &corev1.Pod{}
json.Unmarshal(review.Request.Object.Raw, pod)
allowed := true
message := ""
// 检查特权容器
for _, container := range pod.Spec.Containers {
if container.SecurityContext != nil &&
container.SecurityContext.Privileged != nil &&
*container.SecurityContext.Privileged {
allowed = false
message = "Privileged containers are not allowed"
break
}
}
review.Response = &admissionv1.AdmissionResponse{
UID: review.Request.UID,
Allowed: allowed,
Result: &metav1.Status{Message: message},
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(review)
}
2.4 多集群门禁场景下的 Webhook 设计要点
- 集中式 Webhook 服务:在管理集群部署 Webhook 服务,通过
ValidatingWebhookConfiguration的namespaceSelector或objectSelector控制生效范围,避免每个集群重复部署。 - 高可用与容灾:Webhook 服务至少 2 副本,配置
failurePolicy: Fail时需确保服务 SLA ≥ 99.9%,否则建议使用Ignore并配合审计日志。 - TLS 证书管理:使用 cert-manager 自动签发证书,CA 证书注入到
ValidatingWebhookConfiguration的caBundle字段。 - 性能优化:Webhook 处理逻辑应轻量,避免调用外部数据库;设置合理的
timeoutSeconds(建议 5-10 秒),并启用matchPolicy: Equivalent减少重复调用。
多集群门禁核心原则:Validating Webhook 应作为“断路器”拦截高风险变更(如删除集群角色、修改网络策略),而 Mutating Webhook 作为“自动修复器”处理低风险合规问题。两者配合使用,形成分层防御体系。