如何让Kubernetes ValidatingWebhook跳过对控制器内部请求的拦截?
当然可行!这是配置验证Webhook时非常常见的需求,毕竟没人想让Kubernetes内部组件的正常运作被自定义验证逻辑打断。下面分享两种最实用的实现方式:
方法一:通过请求用户身份(UserInfo)精准过滤
Kubernetes内部控制器的请求,其发起身份都带有明显特征:要么是system:开头的系统用户(比如system:kube-controller-manager、system:scheduler),要么是system:serviceaccount:kube-system:开头的系统服务账号。
你可以在Webhook的服务端处理逻辑中,检查AdmissionReview请求对象里的request.userInfo字段,直接放行这类系统身份的请求:
// 以Go语言的Webhook处理逻辑为例 func (handler *MyValidationHandler) Validate(ctx context.Context, req *admissionv1.AdmissionRequest) *admissionv1.AdmissionResponse { // 跳过所有系统内部身份发起的请求 if strings.HasPrefix(req.UserInfo.Username, "system:") { return &admissionv1.AdmissionResponse{ Allowed: true, } } // 执行你的自定义验证逻辑... // 比如检查Pod的镜像标签、资源限制等 return validateResource(req) }
如果不想一刀切放行所有system:开头的身份,也可以精准匹配特定的系统用户或服务账号,比如只放行system:kube-controller-manager和system:serviceaccount:kube-system:replicaset-controller这类已知的内部控制器身份。
方法二:通过命名空间选择器排除系统命名空间
如果你的Kubernetes内部控制器几乎都运行在kube-system、kube-public这类系统默认命名空间里,也可以直接在ValidatingWebhookConfiguration的配置中,用namespaceSelector排除这些命名空间的请求,不需要修改Webhook服务端代码:
apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: name: my-app-validator webhooks: - name: validator.my-app.com rules: - apiGroups: ["apps"] apiVersions: ["v1"] operations: ["CREATE", "UPDATE"] resources: ["deployments", "statefulsets"] scope: "Namespaced" # 只对非系统命名空间的资源生效 namespaceSelector: matchExpressions: - key: kubernetes.io/metadata.name operator: NotIn values: ["kube-system", "kube-public", "kube-node-lease"] clientConfig: service: name: my-validator-service namespace: my-app-namespace path: "/validate" admissionReviewVersions: ["v1"] sideEffects: None
这种方式的优点是配置简单,但要注意:如果有内部控制器运行在自定义命名空间中,这种方法就会漏掉,无法过滤这类请求。
补充:结合User-Agent做更细致的过滤
部分Kubernetes内部组件的请求会带有特定的User-Agent头,比如kube-controller-manager的请求头会包含kube-controller-manager/v1.27.x这类标识。你也可以在Webhook服务端检查请求的User-Agent字段,进一步精准识别并放行内部请求。
注意事项
如果使用方法一,建议不要直接放行所有system:开头的身份,最好根据实际业务需求,只放行明确需要跳过的内部控制器身份,避免误放行其他系统级的请求(比如某些集群管理员的系统身份操作)。
内容的提问来源于stack exchange,提问作者tomikos

