生产环境密钥严禁明文存储,应采用docker secrets、sops+age/pgp、vault/aws secrets manager或构建阶段secrets四种方案分层防护,确保密钥不落地、不入镜像、不进git,仅运行时受控注入。

生产环境的密钥绝不能明文写在 docker-compose.yml 或 .env 里。真正安全的做法是让密钥不落地、不入镜像、不进 Git,只在容器运行时以受控方式注入。下面这几种方案,按安全等级和适用场景分层说明,可直接落地。
用 Docker Secrets(Swarm 模式或 Compose 3.1+)
这是 Docker 官方推荐的轻量级密钥管理机制,适合中小规模部署,无需额外依赖。
- 密钥以加密形式存储在 Docker daemon 内部,不会出现在容器环境变量、
docker inspect输出或镜像层中 - 容器只能通过挂载文件(默认路径
/run/secrets/<name></name>)读取,且仅对声明了该 secret 的服务可见 - 支持从文件、环境变量或外部 secret 创建,例如:
docker-compose.yml
version: "3.8"
services:
app:
image: myapp:prod
secrets:
- db_password
environment:
DB_PASSWORD_FILE: /run/secrets/db_password
<p>secrets:
db_password:
file: ./secrets/db_password.txt
</p>
注意:./secrets/db_password.txt 必须设为权限 600,且列入 .gitignore;该方式不适用于纯本地 docker compose up(需启用 Swarm 或使用 Docker Desktop 的 Compose V2 Secrets 支持)。
用 SOPS + age/PGP 加密配置文件
适合 Git 管理配置、多环境协同、CI/CD 流水线集成的团队,密钥加密后仍可版本控制,但内容不可读。
- 用
age(推荐,简单安全)或PGP生成密钥对,SOPS 加密 YAML/ENV 文件中的敏感字段(键名保留,值加密) - CI/CD 中用解密密钥自动解密,再传给
docker compose up;开发机本地用私钥手动解密 - 示例:加密后的
docker-compose.secrets.yaml可提交 Git,内容类似:
environment: DB_PASSWORD: ENC[AES256_GCM,data:...,iv:...,tag:...]
搭配 env_file 使用:env_file: [sops-decrypt docker-compose.secrets.yaml > .env](需在启动前执行)。
用外部密钥管理服务(Vault / AWS Secrets Manager)
适合中大型生产环境,要求审计、轮换、细粒度权限与多租户隔离。
- 密钥存在 Vault 或云服务商 KMS,容器启动前通过 CLI/API 获取,临时注入环境变量或文件
- 避免密钥持久化:不写文件、不存镜像、不进日志(需应用代码主动屏蔽敏感字段打印)
- 典型流程:
DB_PASSWORD=$(vault kv get -field=password secret/prod/db) \ docker compose up -d
也可在 entrypoint 脚本中动态拉取,配合 Vault Agent 实现自动续期。
构建阶段密钥隔离(Build-time Secrets)
防止密钥意外进入镜像——尤其当构建过程需要访问私有仓库、证书或 API 密钥时。
- 用
docker compose build --secret传入,Dockerfile 中通过RUN --mount=type=secret安全使用 - 构建完成后,secret 内容不会保留在镜像任何层中,彻底规避“镜像泄露密钥”风险
- 示例 Dockerfile 片段:
RUN --mount=type=secret,id=mykey,target=/tmp/key \
cp /tmp/key /etc/ssl/private/my.key && \
chmod 400 /etc/ssl/private/my.key
对应 docker-compose.yml 中定义 secret 来源,并在 build: 下声明 secrets:。











