权能收敛别漏掉初始化容器

1 人参与

我踩过一次特别安静的坑。主容器老老实实 drop: ["ALL"] 再只加回 NET_BIND_SERVICE,一读 /proc/1/status 里的 CapEff,干净得让人感动。结果把整个 Pod 的 securityContext 逐条翻了一遍才发现:那个负责等数据库就绪的 initContainer,还原封不动地挂着运行时默认的那一整套权能。

这种事难被发现,是因为它太安静了。securityContext 是容器级字段,写在 spec.containers 里的配置不会自动被 spec.initContainers 继承。初始化容器没写就是没写,运行时该给的默认能力一个不少。而恰恰是 initContainer 最容易多拿权限:改挂载目录属主的可能伸手要 CHOWN,下载配置的会写文件系统,做网络探活的则可能顺手要 NET_RAW。它们跑几十秒就退出,日志刷过去没人盯,等真出事的时候早就找不到痕迹了。

漏在哪,怎么补

我现在改这类配置的习惯,是先把整个 Pod 的容器清单拉出来数一遍:主容器、initContainers、sidecar、ephemeralContainers,一个都不能少。收敛出问题,往往不是主容器写错,而是边车或初始化容器还留着默认配置。

写法上没什么花活,每个容器单独写一份,先 drop 掉全部,再按需 add。麻烦的是判断 initContainer 到底要不要某项权能。我的做法是看它实际做了什么,而不是看它以前能不能跑通。只是等一个端口通,那就什么都别留;确实要改文件属主,就只留 CHOWN。宁可先不写,等它报 EPERM 再补。报错反而是好事,说明边界真的收住了。

验证别只看主进程

这里还有个坑:initContainer 早就退出了,你 exec 进去读 /proc/1/status,读到的是主容器 PID 1 的权能位图,跟初始化阶段毫无关系。想确认它,只能趁它还在跑的时候看,或者干脆回到 YAML 上逐条核对。

所以我的检查顺序改成了三步:先读 YAML 数容器,再读 CapEff 对主容器,最后跑一遍关键业务路径确认没被卡住。三样都过了,我才敢说这次收敛是收干净的。

现在这条已经写进我自己的变更模板:动 capabilities 之前,先问一句,这 Pod 里还有几个容器?答不上来就先别改。

参与讨论

1 条评论
  • 暗夜裁决

    initContainer 真的很容易漏,我也中过招