Secret 设置 0400 却变成 0440,JMX 拒绝密码文件:核对 fsGroup
Secret 密码文件从 0400 变为 0440 时,检查 fsGroup 与实际属主,按 JMX 限制准备应用私有文件,并处理启动失败和密码轮换。
Pod 的 Secret 卷配置了 defaultMode: 0400,Java 启动仍提示 Password file read access must be restricted。进入容器检查,密码文件实际是 0440,属主为 root,组与 Pod 的 fsGroup 一致。这组现象应先检查卷权限处理与 JMX 的密码文件要求,而不是继续降低探针频率。
以下针对 Linux 上 Kubernetes 内置 Secret 卷,以及 JDK 自带远程 JMX 的密码文件认证。CSI Secret 驱动、Windows 卷或自定义认证器需要核对自己的规则,不能直接套用内置卷的处理方式。
检查链接目标的权限和应用身份
Secret 卷里的键常表现为指向 ..data 的符号链接。ls -l 显示链接自身的 777,不表示实际密码文件对所有人可读。要检查链接最终指向的文件,同时核对运行 Java 的用户。
在目标容器内可使用这样的只读检查,路径是示例,不能把其他容器的结果当作应用环境:
id
ls -l /etc/jmx-secret/jmxremote.password
stat -L -c '%a %u:%g' /etc/jmx-secret/jmxremote.password
这个 stat 写法适用于提供 GNU stat 的 Linux 镜像;精简镜像需使用对应工具。不要为排查读取并输出密码内容。交互终端的 id 也需要与 Java 的实际运行身份对照,入口脚本可能切换用户。
若目标文件存在、Java 能读、权限是 0440,并且 Pod 设置了 fsGroup,现象符合内置 Secret 卷的组访问处理。若报错是文件不存在或不可读,先核对路径、挂载与用户权限,不能把另一种错误也归到 JMX 的权限限制。
defaultMode 不是后续权限处理的上限
内置 Secret 卷写入文件后会应用 fsGroup 的卷权限处理。只读卷会把 0440 的权限位加入现有模式,因此原先的 0400 可以变成 0440,并将组改成 fsGroup。readOnly: true 限制容器写入卷,不等于只允许文件属主读取。
runAsUser 或 runAsGroup 控制进程身份,不会自动把 Secret 文件属主变成该用户。也不能靠 fsGroupChangePolicy: OnRootMismatch 绕过这一步,这个策略对 Secret 等临时卷类型没有作用。
JMX 密码文件要求组和其他用户不能读取;0440 中的组读取位会触发拒绝。access 文件中的 readonly 是 JMX 角色权限,与文件系统的只读挂载、0400 模式是三件事。
只删 fsGroup 也可能产生新故障:文件如果仍归 root 所有且为 0400,非 root 的 Java 用户就无法读取。先同时满足文件属主、读权限与密码文件的限制,不要把移除一个字段当作所有非 root 容器的完整解法。
将密码交给应用拥有的私有文件
普通 Secret 卷没有可直接指定文件 UID 的配置项。如果现有非 root 用户依靠 fsGroup 读取 Secret,又需要 JMX 只允许属主读取,可以在启动阶段把所需密码文件写入应用拥有的私有位置,再让 JMX 使用这个路径。
一种实现是在 Pod 中准备单独的 emptyDir,由应用用户在启动 Java 前创建私有目录和文件。也可由受控 init container 完成,但必须最终交给实际 Java 用户,而不是留下 root:root 的 0400 文件。不能只复制而不校验身份与权限。
下面是启动逻辑片段,假定应用用户能够读取源 Secret,/run/jmx 是本 Pod 的可写 emptyDir,目录只用于本应用,镜像提供相应工具:
set -eu
umask 077
mkdir -p /run/jmx/private
cp /etc/jmx-secret/jmxremote.password /run/jmx/private/jmxremote.password
chmod 700 /run/jmx/private
chmod 600 /run/jmx/private/jmxremote.password
应把它整合到现有入口脚本,任一步失败就停止启动;不要在日志中打印复制内容。前提还包括已有目标目录和文件确实属于应用用户,不是别的任务或 root 留下的对象。示例使用 0600,让属主可读写、组和其他用户没有权限;它不是“0400 必须变成 0600”这条普遍规则。
随后把 com.sun.management.jmxremote.password.file 指向 /run/jmx/private/jmxremote.password,并保留实际需要的 access 文件、TLS 与认证配置。不要用关闭认证来绕过密码文件检查。
私有卷只挂到需要它的容器,避免让其他容器共享凭据。使用 memory 类型 emptyDir 可以让文件放在内存文件系统,但会计入相应容器内存使用;Pod 删除时文件丢失,容器在同一 Pod 中重启则仍可能保留。部署逻辑必须处理这两种生命周期。
密码轮换不能只修改 Secret 后等待
复制出来的文件不是 Secret 的自动投影,更新 Secret 不会自动覆盖它。需要制定重建 Pod 或受控重新复制、重新加载的轮换流程,并核对 JMX 客户端使用的凭据。文件复制方案不提供即时轮换保证。
变更前保存原 Pod 模板与启动配置,先在隔离环境核对实际用户、私有文件权限和认证连接。成功标准是 Java 不再因密码文件权限退出,授权的客户端能连接,错误凭据仍被拒绝,其他容器没有得到不必要的文件访问权限。
入口脚本和路径修改通常需要替换 Pod,会影响服务与监控连续性,应按现有发布策略安排。回退时恢复模板并核对凭据版本,不能误删共享业务目录;Pod 内临时副本按自己的生命周期清理,密码轮换本身也不会因代码回退自动恢复。


