Kubernetes API 扩展与安全:别让谁都能对集群“下手”
副标题:Admission Controller / Webhook,是真·门禁,不是装饰品
很多人玩 Kubernetes,关注点都在:
- Pod 怎么调度
- Service 怎么暴露
- HPA 怎么弹
但真到了线上事故那一刻,问题往往不是“怎么跑”,而是:
“是谁让它跑起来的?”
“为什么这种配置也能进集群?”
这时候,你才会意识到:
Kubernetes API 本身,就是一条高危通道。
一、一个扎心事实:K8s 最大的安全洞,往往是“默认允许”
我们先说一句大实话。
Kubernetes 的设计哲学是:
“API 是中立的,不负责替你做决定。”
也就是说,只要你有权限:
- 你可以起特权 Pod
- 你可以挂宿主机目录
- 你可以用
latest镜像 - 你甚至可以把整个节点掀了
API Server 不会拦你。
所以真正的问题是:
“谁来替集群说一句:这个不行。”
答案就是今天的主角:
👉 Admission Controller & Webhook
二、Kubernetes API 的“安检流程”长啥样?
很多人对 Admission 的理解非常模糊,我给你画一条人话版链路:
kubectl apply
↓
Authentication(你是谁)
↓
Authorization(你能不能)
↓
Admission(你这样行不行)
↓
ETCD(真的写进集群)
注意一句:
Admission 是“最后一道闸门”
前面只管“身份”和“权限”,
这里只有“行为是否合理”。
三、Admission Controller 分两类:内置的 & Webhook
1️⃣ 内置 Admission Controller:官方送的“基础安检”
常见的比如:
NamespaceLifecycleResourceQuotaLimitRangerPodSecurity(新一代)
这些特点就一句话:
稳、通用、但不懂你的业务。
比如 LimitRanger:
apiVersion: v1
kind: LimitRange
metadata:
name: mem-limit
spec:
limits:
- default:
memory: 512Mi
type: Container
它能保证你不会起一个无限内存的 Pod,
但它不知道:
- 哪个 Namespace 是生产
- 哪个应用不能用特权模式
- 哪个镜像仓库是“野的”
2️⃣ Webhook:真正的“自定义规则引擎”
Webhook 才是 K8s API 扩展的灵魂。
一句话总结它的定位:
“API Server 在关键时刻,把判断权交给你写的服务。”
分两种:
- ValidatingWebhook:只管“行不行”
- MutatingWebhook:还能“顺手改一把”
四、先说 ValidatingWebhook:专治“作死配置”
1️⃣ 一个非常真实的需求
生产环境禁止使用
latest镜像
靠规范?
靠群公告?
靠人盯?
都不靠谱。
Webhook 一次解决。
2️⃣ 校验逻辑(伪代码)
def validate_pod(pod):
for c in pod.spec.containers:
if c.image.endswith(":latest"):
return reject("生产环境禁止使用 latest 镜像")
return allow()
3️⃣ Webhook 配置示例
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
webhooks:
- name: image-policy.example.com
rules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE"]
resources: ["pods"]
clientConfig:
service:
name: image-policy
namespace: kube-system
path: /validate
从此以后,谁 kubectl apply 谁心里有数。
不是我不让你发,是集群不答应。
五、MutatingWebhook:不拦你,但“偷偷帮你改好”
很多人对 MutatingWebhook 有偏见,觉得“魔法太多”。
但说句实在的:
用得好,它是效率神器;
用不好,它是线上惊悚片。
1️⃣ 一个我很常用的场景
自动给 Pod 注入统一的安全上下文
比如:
runAsNonRoot: truereadOnlyRootFilesystem: true
2️⃣ 注入逻辑示例
def mutate_pod(pod):
pod.spec.securityContext = {
"runAsNonRoot": True
}
return patch(pod)
好处很明显:
- 开发不用每次写
- 运维统一兜底
- 安全基线不靠自觉
但注意一句话:
Mutating 一定要“可预期、可回放、可解释”
六、Webhook 的三个“翻车重灾区”
❌ 1. Webhook 挂了,集群直接“瘫”
如果你这样配:
failurePolicy: Fail
然后 Webhook 服务挂了……
所有创建请求都会卡死。
我的建议:
- 非核心校验:
Ignore - 核心安全策略:
Fail + 高可用
❌ 2. Webhook 逻辑太复杂
我见过有人在 Webhook 里:
- 查 CMDB
- 查数据库
- 查外部 HTTP 接口
结果 API Server TPS 直接被拖死。
记住一句:
Admission 阶段,只能做“快判断”。
❌ 3. 没有审计 & 日志
Webhook 拒绝了一个请求,如果你只返回:
{
"allowed": false}
那排障时就是灾难。
一定要:
- 打结构化日志
- 带 request UID
- 能反查原因
七、API 扩展 ≠ 想怎么拦就怎么拦
我最后说一点个人体会。
Admission Controller 的正确姿势是:
“限制下限,而不是限制上限。”
也就是说:
- 防止明显错误
- 防止高风险行为
- 防止破坏性操作
但不要:
- 把业务规则全塞进去
- 把开发当敌人
- 把灵活性掐死
否则最后一定是:
“大家绕开 Kubernetes 用。”
八、一句大白话总结
- RBAC 决定你能不能进门
- Admission 决定你能不能乱来
- Webhook 决定集群有没有“脑子”
Kubernetes 的安全,从来不是防黑客开始的,
而是:
防自己人一不小心把集群送走。