Compose Secret 设置 uid、gid、mode 后权限仍未改变
文件型 Compose Secret 使用绑定挂载,不应用 uid、gid、mode 重映射。按来源选择环境变量型 Secret 或专用源文件权限,并核对实际身份、轮换和回退。
Compose 给 Secret 配了 uid、gid 和 mode: 0400,容器里的文件却仍是宿主机的 1000:1000、0644。应用可能因此读不到文件,也可能因为私钥权限过宽而拒绝启动。继续更换 YAML 中的数字通常没有效果。
先看顶层 Secret 的来源。如果写的是 file:,当前 Docker Compose 会用只读绑定挂载提供文件,不实现这三个属性的重映射。它们在文件型 Secret 上会被忽略;environment: 来源的 Secret 则支持这些属性。两种来源不能按同一种方式判断。
以下针对 Docker Compose 的 Linux 容器,不是 docker stack deploy、Kubernetes Secret 或构建阶段的 BuildKit Secret。宿主机调整权限的分支还要求本机 Linux Engine,且没有 rootless、userns-remap 或桌面文件共享造成的身份映射。
确认是文件来源,检查实际数字权限
例如下面的配置不会把宿主机文件自动变成 1005:1005、0400:
services:
app:
image: example/app:version
secrets:
- source: app_key
target: app_key
uid: "1005"
gid: "1005"
mode: 0o400
secrets:
app_key:
file: ./app.key
镜像、用户和路径都是示例。先核对最终使用的 Compose 文件、覆盖文件和服务名,再检查源文件与容器中的目标。下面的 stat 语法要求相应环境提供 GNU stat:
stat -Lc 'mode=%a uid=%u gid=%g' ./app.key
docker compose exec app stat -Lc 'mode=%a uid=%u gid=%g' /run/secrets/app_key
docker compose exec app id
这些检查不输出凭据内容。入口脚本如果会切换用户,exec 的默认身份不一定是应用进程的身份,还需结合实际启动配置确认。容器已经退出时,不要为了运行检查把服务改成特权或 root;应在隔离环境复用相同挂载和用户配置诊断。
如果两端文件模式和数字属主相同,且 YAML 确实采用 file 来源,就符合这个限制。只读挂载限制写入,不会自动收紧原文件的读取位。反过来,文件模式正确而应用仍被拒绝时,还要查实际运行身份、父目录访问和 SELinux 等机制,不能继续归因于这三个字段。
需要由 Compose 指定权限时,使用环境变量来源
如果现有凭据管理流程能把值安全注入运行 Compose 的进程环境,可以改用 environment 来源。下面保留应用原来的镜像和启动方式,只更换 Secret 的取值方式:
services:
app:
image: example/app:version
secrets:
- source: app_key
target: app_key
uid: "1005"
gid: "1005"
mode: 0o400
secrets:
app_key:
environment: APP_KEY_SECRET
这里的 APP_KEY_SECRET 是宿主机运行 Compose 时可见的变量名。它没有写进服务级的 environment,也不要求应用通过环境变量读取凭据;应用仍读取 /run/secrets/app_key。1005 必须替换为应用实际需要的 UID、GID。不要仅为了配合示例去更改应用用户。
值应由已有的凭据管理工具或受控发布环境提供,不要把真实值写进 Compose 文件、终端历史或构建参数。环境变量来源也有自己的泄露面,诊断时不要打印整个进程环境或展开后的配置。这条路径不适合必须原样保留任意二进制内容的凭据,也不能直接搬到 docker stack deploy。
先在隔离环境验证当前 Compose 版本对该来源的支持,并检查生成文件的数字权限。若变量未注入、值为空或应用实际身份不同,改来源本身不能解决问题。不要用 Dockerfile COPY 把私钥写入镜像来绕过挂载限制。
继续使用 file 时,在专用源文件上落实权限
必须保留文件来源时,应让源文件本身满足应用的要求。不要修改被其他服务共用的私钥或系统配置;先准备仅供该服务使用的受保护副本,并保存原文件的属主、模式和部署配置。
例如已经确认 /srv/example-app-secrets/app.key 是专用副本,应用使用 UID、GID 1005,宿主机与容器没有用户命名空间映射,而且服务要求仅属主可读,才可以采用:
sudo chown 1005:1005 /srv/example-app-secrets/app.key
sudo chmod 0400 /srv/example-app-secrets/app.key
sudo stat -Lc 'mode=%a uid=%u gid=%g' /srv/example-app-secrets/app.key
随后将顶层 file 指向这个专用路径,移除无效的 uid、gid、mode 字段,减少配置造成的误判。保存副本的目录也应限制访问,并确保 Compose 与 Engine 能按各自身份访问所需路径。相同数字 UID 在宿主机上也代表访问主体,不能忽视同机其他用户或服务。
0400 只适合这里的只读、单一属主需求。若应用有不同约束,应按它的文件访问契约设置,不要统一放宽成 0644 或 0777。Windows、Docker Desktop、远程 Engine、rootless 和 userns-remap 场景不能直接照搬这些宿主机数字;应先确认真实文件所在主机和身份映射,再选择适用的交付方式。
重建后验证,并把凭据轮换纳入发布
改变 Secret 来源或源路径后,在维护窗口按原部署流程重新创建受影响的服务,保留此前的镜像和配置。对于变量来源,也要让新建容器取得正确的凭据版本,不能只改宿主机变量就期待运行中的文件自动更新。
验收至少包括:目标路径正确;文件的 UID、GID、模式符合预期;应用按原来的非特权身份启动;所需认证成功;日志没有输出凭据。只看 Compose 命令退出成功,不足以确认文件权限或应用认证已经恢复。
回退时恢复先前的来源配置与受保护文件,再按原流程重建服务。若修改过源文件属性,要依据事先记录恢复,而不是猜测一个宽松模式。凭据已经轮换或撤销时,配置回退不会让旧凭据重新有效,需与认证端保持一致。


