第 13 章 安全模型:认证 / RBAC / NetworkPolicy / Pod 安全

墨:老哥,安全这章咱们分两层讲——第 4 章讲过”你能不能调 API”(认证+RBAC+准入),这章补”Pod 运行时能碰什么、网络能通到哪、容器能以啥权限跑”。一句话:K8s 安全是分层的,任何一层漏了都完蛋,但任何一层都救不了其他层的漏。 先记这句。


13.1 安全的四层(先画全景)

把前面和本章串起来,K8s 安全是四道门,由外到内:

  1. 认证(Authentication):你是谁(第 4.3)。非法身份直接门外;
  2. 鉴权(Authorization / RBAC):你被允许调哪些 API(第 4.4);
  3. 准入(Admission):请求内容合不合规、要不要改(第 4.5,含 Pod Security);
  4. 运行时隔离 + 网络隔离:Pod 跑起来后,它能以什么权限跑(capabilities/root)、能访问谁(NetworkPolicy)。

墨:为什么不能只靠 RBAC? 因为 RBAC 只管”调 API”,不管”Pod 跑起来之后干啥”。一个合法用户(通过 RBAC)创建了 Pod,但这个 Pod 以 privileged: true 跑、能逃逸到宿主机——RBAC 拦不住,得靠运行时安全(Pod Security)和网络隔离(NetworkPolicy)管。四层各管一段,缺一不可。


13.2 认证与 SA:再深一点(接第 4.3)

第 4 章讲过 SA token 从永久走向短期投影(TokenRequest)。这里补一个常被忽略的点:默认 SA 的权限是”空”的,但默认 SA 是自动挂载的。

墨:每个 Pod 默认都挂了 SA token,这意味着 Pod 里的进程能调 K8s API。这危险吗?

看你给 SA 绑了什么权限。默认 SA 没绑任何 Role,所以它调 API 基本被拒(除了极个别匿名读)。但如果你图省事给 default SA 绑了 cluster-admin(新手常干),那这台机器上所有 Pod 都能以管理员身份调 API——一旦 Pod 被入侵(比如你的 web 服务有 RCE 漏洞),攻击者就拿到了集群管理员。这是生产最常见的安全事故链之一。

最佳实践: 每个需要调 API 的 Pod 用专用 SA(不用 default),且只绑最小必要权限;不需要调 API 的 Pod,设 automountServiceAccountToken: false,连 token 都不挂,从根上消除”Pod 能调 API”的面。


13.3 RBAC 实战陷阱(接第 4.4)

几个真实坑:

  • * 通配:resources: ["*"], verbs: ["*"] = 超管,宁可具体到资源;
  • ClusterRole 误绑给不该有的人:ClusterRoleBinding 是集群级,一旦绑错影响全局;
  • 忘记”读取 Secret 也算敏感权限”:很多人控了 create pod 却放行 get secret,攻击者读 secret 拿密码;
  • 聚合 ClusterRole(Aggregated ClusterRole):K8s 有个机制,多个 ClusterRole 可aggregationRule聚合成一个(如把”查看所有只读资源”聚合成一个 view)。好处是”权限模块化拼接”,但也要小心聚合出的权限超出预期。

墨:RBAC 的”最小权限”说着简单,为什么团队总做不好? 因为”最小”要你先想清楚每个 SA 到底要什么,这是认知成本。团队赶工期就给宽权限。代价是安全事故。所以很多团队用准入策略(如 OPA/Gatekeeper)强制”禁止给 default SA 绑 cluster-admin""禁止 Pod 设 automountToken 且不设只读”——把”该怎么做”用策略卡死,而不是靠人自觉(第 4.5 的 webhook 再立功)。


13.4 运行时安全:容器能以什么权限跑

墨:容器里的进程默认是 root 吗? 默认镜像常以 root 跑(很多 Dockerfile 没 USER)。容器里的 root 不是宿主机的 root(靠 namespace 隔离),但容器 root 仍拥有容器内大量权限,且若容器配置不当(如 privileged、hostPID),能逃逸到宿主机。所以运行时安全要限制容器能力。

13.4.1 关键安全上下文(securityContext)

Pod/容器可设 securityContext,常用硬核项:

  • runAsNonRoot: true:禁止以 root 跑。很多镜像强行 root,设了就拒绝启动(逼你改镜像);
  • readOnlyRootFilesystem: true:根文件系统只读,防恶意写文件、防篡改。需写的挂 emptyDir/volume;
  • allowPrivilegeEscalation: false:禁止提权(如 setuid);
  • capabilities.drop: ["ALL"]:默认丢掉所有 Linux capabilities,只加必要的(如 NET_BIND_SERVICE);
  • privileged: false(默认):privileged: true 给容器几乎宿主机全部权限,极度危险,等于开了逃逸后门,生产严禁;
  • seccompProfile:用 seccomp 限制容器能调用的系统调用(缩小内核攻击面)。

墨:为什么默认容器有那么多 capabilities? 历史兼容——Docker 默认给容器一套 capabilities(而非全无),方便老应用。但最小权限要求”默认全丢,按需加”。这是”默认宽松 vs 默认严格”的取舍,K8s 选了”让你显式声明严格”,而非”默认严格挡住老应用”。所以安全靠你主动设 securityContext,不靠默认。


13.5 Pod Security:PSP 的失败与 Pod Security Admission 的接班

这是本章最值得学的演化案例——一个”设计初衷好、落地全翻车”的标准故事。

13.5.1 PodSecurityPolicy(PSP):初心很好,死因很惨

PSP 是早期 K8s 的”Pod 安全准入”:你写一条策略(如”禁止 privileged、必须 runAsNonRoot”),Pod 创建时由 PSP 校验/改。听起来完美。

为什么被废弃(K8s 1.21 弃、1.25 移除)?

  • 太复杂且二值化:PSP 要么”允许”要么”拒绝”,没有中间档。想让”大多数 Pod 宽松、关键 Pod 严格”做不到平滑——要么全松(有风险)要么全严(老应用起不来);
  • 绑定混乱:PSP 靠”RBAC 绑定 PSP 给 SA/用户”生效,但授权机制绕——谁能创建 Pod 和用哪个 PSP 是两件事,运维常配错,导致”该严的没严、该松的卡死”;
  • 无法渐进(no gradual rollout):要么全开要么全关,没法”先审计(警告)再强制”,导致团队要么不敢开、要么开了崩一片;
  • 用户基础差:官方调研大量集群根本没正确配 PSP,等于裸奔,或配了过松形同虚设。

墨:PSP 的死因,抽象成一条设计教训是什么? “一个机制如果正确用很难、错误用很易、且失败了无提示,它就等于没有。” 安全机制必须”易正确、难错误、可渐进”,否则没人用对。PSP 三样全反。

13.5.2 Pod Security Admission(PSA):简单三档 + 标签驱动

演化(K8s 1.25 GA 取代 PSP): PSA 用标签给 namespace 设安全等级,三档:

  • Privileged:不限(给系统组件、CNI 插件等真需要特权的);
  • Baseline:禁已知危险项(如 privileged、hostPath 滥用),大部分普通应用能过;
  • Restricted:最严(强制 runAsNonRoot、丢全部 capabilities、只读根、seccomp 等),给高安全需求。

每个 namespace 打标签设”enforce / warn / audit”三种模式:

  • enforce:违反直接拒绝创建;
  • warn:放行但告警(给迁移过渡);
  • audit:放行且记审计(观察哪些会违规,先别拦)。

墨:看出 PSA 怎么解决 PSP 的死因了吗?

  • 三档而非二值:Baseline/Restricted 给”中间档”,普通应用用 Baseline 不过度限制,关键的用 Restricted;
  • 标签驱动、简单:给 namespace 打个标签就生效,不用绕 RBAC 绑定;
  • warn/audit 渐进:先 warn+audit 观察(不拦),确认没问题再 enforce 强制。这是 PSP 最缺的”渐进上线”能力;
  • 内置、无需额外组件:PSA 是 API Server 内置准入(可配),不依赖外部 webhook。

这又是一场”老方案因’难正确、不可渐进’被弃,新方案用’简单分档 + 渐进模式’接班”的演化。 你做安全系统设计时记住:策略要能”先观察后强制”,否则推行必受阻。

13.5.3 与 OPA/Gatekeeper 的关系

PSA 是”内置的、覆盖常见场景的”基础安全。要更复杂的策略(如”禁止镜像来自未授权仓库""必须带某 label”),用 OPA Gatekeeper / Kyverno(第 4.5 的 validating webhook 实现)。两者不冲突:PSA 管”Pod 运行时权限基线”,Kyverno 管”任意自定义策略”。分层:内置基线 + 可扩展高级策略。


13.6 NetworkPolicy:数据面隔离(接第 9.7)

第 9 章讲过 NetworkPolicy 是白名单、效果取决于 CNI。这里补安全视角:

墨:NetworkPolicy 和 RBAC 是重复的吗? 不重复,分工在”层”:

  • RBAC:控制面权限——“这个 SA 能调 K8s API 删 Pod 吗”;
  • NetworkPolicy:数据面隔离——“这个 Pod 能 TCP 连那个 Pod 的 3306 吗”。

即使 RBAC 完美,一个被入侵的 Pod(攻击者通过应用漏洞进去了)仍能用 Pod 的网络身份去连数据库——RBAC 管不到”Pod 之间的流量”。NetworkPolicy 补这道。典型最小暴露:数据库 Pod 只接受来自应用 Pod 的 3306,拒绝其他一切(配默认拒绝 + 白名单,第 9.3 提过)。


13.7 镜像安全:你跑的到底是什么

墨:你 kubectl apply 一个 Deployment,镜像 nginx:latest。你确定跑的是官方的 nginx 吗?

“latest 标签 + 不校验来源”是供应链风险:镜像可能被篡改、或你拼错名字拉到恶意镜像。镜像安全两条线:

  • 固定摘要(digest)而非 tag:nginx@sha256:xxx 锁定具体镜像内容,tag 可被覆盖(:latest 今天和明天可能不同镜像)。生产用 digest 或固定版本号;
  • 镜像签名 + 准入校验:用 cosign 给镜像签名,配合准入 webhook(如 Connaisseur / Kyverno)拒绝未签名/签名不合法的镜像。这把”镜像来源可信”在准入层卡死——又是 webhook 扩展能力的应用。

演化看点: 镜像供应链安全(Sigstore/cosign)是近年重点,K8s 本身不内置签名校验,但用”准入 webhook”把这能力交给生态(Sigstore)。又是”核心提供钩子、安全能力由生态补”的模式。


13.8 四层安全的一个攻击链串联(理解”缺一不可”)

场景: 攻击者通过一个 web 服务的 RCE 漏洞进了容器。

  • 若 RBAC 过松(default SA 是 cluster-admin):攻击者用挂载的 SA token 调 API,删所有 Pod、读所有 Secret → 全集群沦陷;
  • 若 运行时不设 securityContext(容器 root + 有 capabilities):攻击者尝试提权/挂载宿主机,可能逃逸到节点;
  • 若 NetworkPolicy 全通:攻击者从被控 Pod 横向扫全场,连数据库、Redis 拖数据;
  • 若 准入不严(用了 :latest 且未签名校验):你甚至不知道镜像本身是否被动过。

墨:你看出安全的本质了吗? 安全是纵深防御(defense in depth)——任何一层失守,其他层还能挡。你不能靠”RBAC 配好就安全”,因为漏洞可能在应用层、可能在运行时、可能在网络。K8s 把安全做成四层,正是逼你”每层都设防”,而非赌某一层万无一失。系统设计里,凡涉及安全,永远假设某一层会被破,用多层兜底。


13.9 本章演化线小结

  • 安全四层:认证 → RBAC → 准入(含 Pod Security) → 运行时/网络隔离,各管一段、缺一不可;
  • SA 默认空权限但默认挂载,给 default SA 绑 cluster-admin 是事故链起点;最佳实践专用 SA + 最小权限 + 不必要不挂 token;
  • 运行时 securityContext:runAsNonRoot / 只读根 / 丢 capabilities / 禁 privileged / seccomp,缩小攻击面;
  • PSP 因”二值化、绑定乱、不可渐进、易错难对”被废弃;PSA 用三档(Privileged/Baseline/Restricted)+ 标签(enforce/warn/audit) 渐进接班;
  • NetworkPolicy(RBAC 互补,数据面) + 镜像签名校验(准入 webhook) 补全;
  • 纵深防御:任何一层破,其他层兜底。

13.10 本章思考题

🔧 思考题 1

某团队给 default ServiceAccount 绑了 cluster-admin(因为”省事,不然各种权限报错”)。请沿攻击链描述:一个只有 RCE 漏洞的 web Pod,如何一步步拿到集群控制权?并指出在哪一层挡住能断链。

【参考答案】 攻击链:(1) 攻击者通过 web 应用 RCE 进容器,在容器里执行命令;(2) 容器默认挂了 default SA 的 token(在 /var/run/secrets/…/token);(3) 攻击者用这 token 调 K8s API(如 kubectl --token=...),因 default SA 是 cluster-admin,可对任意资源做任意操作;(4) 攻击者列所有 Secret(get secrets -A)拿到数据库密码、其他服务 token;(5) 删/篡改关键 Deployment 造成破坏,或建后门 Pod(如挂载宿主机目录的特权 Pod)进一步控节点。断链点:(a) RBAC 层:别给 default SA cluster-admin,用专用 SA+最小权限,攻击者在容器内拿到的 token 就没大权限,最多读自己 namespace 少量资源;(b) SA 挂载层:不需要调 API 的 Pod 设 automountServiceAccountToken: false,攻击者连 token 都拿不到;(c) 运行时层:即使拿到普通 token,若 Pod 配了受限 securityContext,攻击者难逃逸。最有效断链是 (a)+(b):从根上让”进容器的攻击者”拿不到高权限凭证。这题考纵深防御——单点(应用漏洞)被破后,靠 RBAC/SA 收紧止血。

🔧 思考题 2

PSP 被废弃,PSA 接班。如果从”安全机制必须易正确、难错误、可渐进”三条标准评价,PSA 的 enforce/warn/audit 三模式分别解决了 PSP 的什么死因?请一一对应。

【参考答案】 (1) 可渐进(audit→warn→enforce):PSP 只能全开/全关,没过渡,团队不敢开或开了崩。PSA 的三模式让你可以先 audit(只记录哪些 Pod 会违规,不拦,摸清现状)→ warn(放行但告警,让开发适应)→ enforce(真正拒绝)。这解决了 PSP”不可渐进、推行必受阻”的死因。(2) 易正确(标签驱动、简单三档):PSP 靠 RBAC 绑定 PSP,授权和策略绕在一起易配错。PSA 直接给 namespace 打标签(pod-security.kubernetes.io/enforce: restricted)即生效,心智简单、不易错,解决 PSP”绑定混乱、易配错”。(3) 难错误(Baseline/Restricted 分档覆盖常见场景,且内置默认档):PSP 是二值(允许/拒绝),老应用要么被卡要么全松,易走向”配过松形同虚设”。PSA 的 Baseline(挡已知危险)对普通应用友好、Restricted 给高安全,中间有档,不易因”怕卡应用”而配成全松。总结:PSA 用”标签化(易正确) + 三档(难错误) + 渐进三模式(可渐进)“精确对症 PSP 三大死因。这题教你的设计课:评价一个安全/策略机制,就看它是否满足”易正确、难错误、可渐进”——不满足就会被弃。

🔧 思考题 3

你要求所有 Pod 必须 runAsNonRoot,但团队有个老镜像强制 root 启动(改镜像成本高)。PSA 设 Restricted 会拒绝它。你该怎么”既要安全又要不阻塞业务”地过渡?

【参考答案】 用 PSA 的渐进模式:(1) 先对多数 namespace 设 enforce: baseline(挡 privileged/危险项但不强制 non-root),让老 root 镜像能跑,同时挡住最危险配置;(2) 只对新/高安全 namespace 设 enforce: restricted 强制 non-root,树立标杆;(3) 全局开 audit: restricted + warn: restricted:观察哪些 Pod 违反 Restricted(审计日志+告警),列出”必须改镜像”的清单,排期推动镜像改造(加 USER、改启动逻辑);(4) 对实在改不了的极少数老镜像,用 ** exemptions(PSA 支持对特定 SA/namespace 豁免)** 或放 baseline namespace 隔离,而非全员降档;(5) 同时用 Kyverno 这类高级策略做”新创建的 Pod 必须 non-root”的渐进卡点,老 Pod 容错、新 Pod 强制。核心:不要一刀切 enforce 全员 Restricted(会崩业务),用 audit/warn 摸清、用 baseline 兜底、用 exemptions 救极少数、用排期推动根治。这正是 PSA 设计的”渐进”价值——安全是旅程不是开关。

🔧 思考题 4(进阶)

OPA Gatekeeper / Kyverno 用 validating webhook 做”自定义安全策略”(如”禁止 :latest 镜像""必须带 cost-center 标签”)。这比 PSA 强在哪、弱在哪?什么策略该用 PSA、什么该用 Gatekeeper?画出决策边界。

【参考答案】 PSA 强在:内置、零额外组件、覆盖 Pod 运行时安全基线(non-root/capabilities/特权)、简单标签驱动、性能开销低、官方维护。弱在:策略固定为三档 Pod 安全,不能表达任意业务规则(如”镜像必须来自 harbor.example.com""必须带 owner 标签""resources 必须有 requests”)。Gatekeeper/Kyverno 强在:任意自定义策略(基于 Rego/Cel)、可跨资源类型、可做 mutate(自动补字段)、有违规报告。弱在:引入额外组件(高可用要求,故障可能卡写入,第 4.5 提过)、性能(每个创建请求多一跳 webhook)、策略要自己写维护。决策边界:(1) Pod 运行时安全基线→ 用 PSA(内置够用、零运维);(2) 组织/业务合规规则(镜像来源、标签强制、资源必填、命名规范)→ 用 Gatekeeper/Kyverno(PSA 表达不了);(3) mutate 类(自动注入 sidecar、自动补 defaults)→ 只能 webhook(PSA 只 validate 不 mutate)。原则:能用内置 PSA 覆盖的别上 webhook(减复杂度),PSA 够不着的再用 webhook。这是”优先用平台内置能力、必要时才扩展”的通用工程取舍。


13.11 小结

  • 安全四层(认证/RBAC/准入运行时/网络隔离)各管一段,纵深防御缺一不可;
  • default SA 绑 cluster-admin + 默认挂载 token 是典型事故链,用专用 SA+最小权限+必要时不挂 token 断链;
  • securityContext 缩小运行时攻击面:non-root/只读根/丢 capabilities/禁 privileged/seccomp;
  • PSP 因二值化/绑定乱/不可渐进被弃;PSA 三档+标签(enforce/warn/audit)渐进接班,示范”易正确难错误可渐进”;
  • NetworkPolicy(RBAC 互补) + 镜像签名校验(准入 webhook) 补全数据面与供应链;
  • 评价安全机制看”易正确、难错误、可渐进”三条,不满足就被弃。

下一章讲 K8s 最让老哥你这种”想自己造工具”的人兴奋的一块——可扩展机制:CRD / Operator / Admission。前面我们反复说”K8s 把核心能力开放给用户”,这章把”你自己怎么扩展 K8s”彻底讲透。你来真的能写一个。