如何在需要文件时让非root用户使用Docker Compose Secrets
Docker Compose Secrets权限问题及解决方案探讨
问题背景:Compose文档的错误表述
截至2024年7月,Docker Compose文档错误地宣称使用docker secrets时可通过长语法定义挂载文件的名称、UID、GID及权限模式,示例代码如下:
services: frontend: image: example/webapp secrets: - source: server-certificate target: server.cert uid: "103" gid: "103" mode: 0440 secrets: server-certificate: file: ./server.cert
该配置仅在Docker Swarm中生效,在Compose环境下无任何作用。相关问题已在社区讨论但文档未修正,导致Compose中挂载的secret文件(路径为/run/secrets/<foobar>)始终为root:root权限(0:0)、权限模式400,且/run/secrets/目录为只读文件系统。
场景示例:非Root用户镜像无法访问Secret
当使用自带非root用户的镜像时,会出现无法访问secret文件的问题,例如nginx非特权镜像的配置:
services: nginx: image: nginxinc/nginx-unprivileged:1.27-alpine ports: - "8080:8080" secrets: - FOO_BAR_SECRET secrets: FOO_BAR_SECRET: file: .foo.bar
此场景下,容器内的非root用户(如nginx用户)因权限不足,无法读取/run/secrets/FOO_BAR_SECRET文件。
现有方案与疑问
目前常见的解决方案是通过自定义Dockerfile切换回root用户,编写入口脚本复制secret并修改权限后,再切换回非root用户执行原程序,示例如下:
自定义Dockerfile
FROM nginxinc/nginx-unprivileged:1.27-alpine # 后续在自定义入口脚本中切换回nginx用户 USER root # 可选使用预装的runuser或安装gosu,此处选择su-exec RUN apk update && apk add su-exec # 替换原有入口脚本,保留原脚本逻辑 RUN mv /docker-entrypoint.sh /docker-entrypoint-original.sh COPY docker-entrypoint-wrapper.sh /docker-entrypoint.sh RUN chmod ug+x /docker-entrypoint.sh
配套入口脚本(docker-entrypoint-wrapper.sh)
#!/usr/bin/env sh set -e mkdir /run/secrets_ \ && cp -r /run/secrets/* /run/secrets_ \ && chown -R nginx:nginx /run/secrets_ # 可替换为gosu或runuser执行原入口脚本 exec su-exec nginx /docker-entrypoint-original.sh "${@}"
除上述方案外,是否存在更优的解决方式?
另一种可选方案是将secret内容导出为环境变量,但该方案存在明显安全隐患(环境变量可能通过进程列表等方式泄露),示例脚本如下:
#!/bin/sh # 遍历所有挂载的secret文件 for i in $(ls -1 /run/secrets) do # 将secret内容导出为同名环境变量 export "${i}"="$(cat /run/secrets/${i})" done # 执行原命令 exec "$@"
需求限制
- 需支持Windows和Linux主机的通用解决方案
- 同一FOO_BAR_SECRET(如通配符TLS证书)需适配多个不同UID的服务
内容的提问来源于stack exchange,提问作者bjoern-nowak
相关产品推荐
相关产品推荐

