admissionreview解析失败主因是字段无json tag或未用指针传参;响应需设response非nil、uid匹配、allowed设布尔值并填message;tls证书san须覆盖访问地址;校验前必判空且捕获反序列化错误。

为什么 AdmissionReview 解析失败总返回空对象
Go 里解析 K8s 准入请求时,AdmissionReview 结构体字段没被正确反序列化,最常见原因是没用指针接收或没加 json tag。K8s 发送的 JSON 字段名全小写(如 request、response),而 Go struct 默认导出字段首字母大写,若不显式标注 tag,json.Unmarshal 就会跳过所有字段。
- 必须为每个字段加上
json:"field_name",且值与 K8s API 文档完全一致(比如Request字段对应 JSON 中的request) -
AdmissionReview是顶层容器,它内部的Request和Response都是指针类型,解析时传入的必须是&review,不是review - 别漏掉
apiVersion和kind字段——虽然校验逻辑通常不依赖它们,但缺失会导致整个结构体解析失败
如何让 Webhook 正确响应 Allowed 或 Forbidden
响应体写错一个字段,K8s 就直接拒绝该请求并报 admission webhook "xxx" denied the request,但不会告诉你哪错了。核心是:你只能改 AdmissionReview.Response,不能动 AdmissionReview.Request;且 Response 必须非 nil,否则 apiserver 当作内部错误处理。
-
Response.UID必须设为Request.UID的拷贝,否则 K8s 认为响应不匹配原始请求 -
Response.Allowed = true表示放行;设为false时,必须同时填Response.Result.Message,否则报错no error message provided - 不要试图在
Response里塞Patch或PatchType——那是 Mutating Webhook 的事,Validating Webhook 只能允许或拒绝
serverTLS 配置不对导致 kube-apiserver 连不上你的服务
K8s 不接受自签名证书的裸域名或 IP 地址,哪怕你在 caBundle 里填了证书,如果服务端证书的 Subject Alternative Name (SAN) 没覆盖 Webhook 服务的访问地址(比如 https://my-webhook.default.svc:443),连接就会被拒绝,日志只显示 tls: failed to verify certificate。
- 生成证书时,
openssl的 config 必须包含DNS.1 = my-webhook.default.svc、DNS.2 = my-webhook.default.svc.cluster.local,IP 地址除非真用 NodePort + IP 访问,否则不用加 -
caBundle要填 base64 编码后的 CA 证书内容(不含-----BEGIN CERTIFICATE-----等头尾),不是私钥,也不是服务端证书 - Webhook server 启动时,
tls.Listen的地址要和证书 SAN 完全一致,比如监听:443,就别用localhost:8443测试
资源校验逻辑里最容易忽略的边界条件
你以为校验 Pod.Spec.Containers[0].Image 就够了?实际 K8s 允许 Pod 没有容器(比如 init container 全失败)、允许镜像为空字符串、甚至允许 Containers 是 nil 切片。这些情况不判空,你的 Webhook 会 panic 并返回 500,导致整个集群创建卡住。
立即学习“go语言免费学习笔记(深入)”;
- 所有嵌套字段访问前先做非空检查:
if req.Object.Raw != nil、if pod.Spec.Containers != nil - 用
json.Unmarshal(req.Object.Raw, &pod)解出具体资源时,必须捕获 error;不要假设req.Kind.Kind == "Pod"就一定是个合法 Pod - 校验 ConfigMap/Secret 引用时,注意
envFrom和volumes是两套独立路径,容易漏掉其中一种引用方式
真正的难点不在写逻辑,而在预判 K8s 会以什么奇怪方式调用你——比如带 dryRun: true 的请求、带 fieldManager 的 Server-side Apply、或者被 kubectl edit 触发的 PATCH 请求。这些场景下 req.Object.Raw 可能不完整,得靠 req.OldObject.Raw 做对比校验。










