敏感信息 Secret 管理

敏感信息 Secret 管理

为什么需要 Secret 管理

在容器化应用中,敏感信息无处不在:数据库密码、API 密钥、TLS 证书、OAuth token 等。将它们硬编码在 Dockerfile、环境变量或源代码中是常见的安全漏洞。

不安全的做法

在 Dockerfile 中硬编码

# ❌ 绝对不要这样做
FROM node:18-alpine
ENV DB_PASSWORD=supersecret123
ENV API_KEY=sk-123456789
COPY . /app
CMD ["node", "app.js"]

密码会被包含在镜像层中,任何人都可以查看。

在 docker-compose.yml 中硬编码

# ❌ 不安全
services:
  app:
    image: myapp
    environment:
      - DB_PASSWORD=supersecret123

安全的 Secret 管理方式

方案一:使用环境变量文件(.env)

# .env(不要提交到 git)
DB_PASSWORD=supersecret123
API_KEY=sk-abcdefgh
JWT_SECRET=my-jwt-secret-2023
services:
  app:
    image: myapp
    env_file:
      - .env

方案二:使用 Docker Secrets(Swarm 模式)

# 创建 secret
echo "supersecret123" | docker secret create db_password -

# 在服务中使用
docker service create \
  --name app \
  --secret db_password \
  myapp

Compose 中的 Secret 配置:

services:
  app:
    image: myapp
    secrets:
      - db_password
      - api_key

secrets:
  db_password:
    external: true    # 已经创建好的 secret
  api_key:
    file: ./api_key.txt  # 从文件创建

容器内 secret 文件的默认路径:/run/secrets/

# 在应用代码中读取
cat /run/secrets/db_password

方案三:使用文件挂载

services:
  app:
    image: myapp
    volumes:
      - ./secrets/db_password.txt:/run/secrets/db_password:ro
      - ./secrets/api_key.txt:/run/secrets/api_key:ro

方案四:运行时注入

# 使用环境变量(确保不保存在任何文件中)
export DB_PASSWORD=$(aws secretsmanager get-secret-value --secret-id db/password --query SecretString --output text)
docker compose up -d

方案五:使用专用密钥管理服务

# HashiCorp Vault
vault kv put secret/myapp db_password=supersecret123

# AWS Secrets Manager
aws secretsmanager create-secret --name db/password --secret-string supersecret123

# Azure Key Vault
az keyvault secret set --vault-name myvault --name db-password --value supersecret123

各语言读取 Secrets

Node.js

const fs = require('fs');
const dbPassword = fs.readFileSync('/run/secrets/db_password', 'utf8').trim();

Python

with open('/run/secrets/db_password', 'r') as f:
    db_password = f.read().strip()

Java

import java.nio.file.*;

String dbPassword = Files.readString(Paths.get("/run/secrets/db_password")).trim();

Shell

DB_PASSWORD=$(cat /run/secrets/db_password)

生产中推荐方案:外部 Secret 管理

Vault Agent 注入

services:
  app:
    image: myapp
    environment:
      - VAULT_ADDR=http://vault:8200
    volumes:
      - vault-token:/home/appuser/.vault-token

  vault-agent:
    image: vault:latest
    volumes:
      - ./vault-agent-config.hcl:/etc/vault/agent.hcl
      - vault-token:/home/vault/.vault-token
    command: agent -config=/etc/vault/agent.hcl

Kubernetes External Secrets

apiVersion: 'kubernetes-client.io/v1'
kind: ExternalSecret
metadata:
  name: db-password
spec:
  backendType: secretsManager
  data:
    - key: db/password
      name: db_password

BuildKit 的 Secret 支持

在 Dockerfile 构建过程中安全使用 secret:

# syntax=docker/dockerfile:1.4
FROM node:18-alpine

# 构建时注入 secret(不会留在镜像层中)
RUN --mount=type=secret,id=npmrc \
  cat /run/secrets/npmrc > ~/.npmrc && \
  npm ci && \
  rm ~/.npmrc

COPY . .
CMD ["node", "app.js"]
# 构建时传递 secret
DOCKER_BUILDKIT=1 docker build --secret id=npmrc,src=.npmrc -t myapp .

.dockerignore 保护

# 确保敏感文件不会被复制到镜像中
.env
.env.*
secrets/
*.pem
*.key
**/credentials

最佳实践总结

场景 推荐做法
开发环境 .env 文件(不提交 git)
单机部署 Docker Secrets(Swarm)或文件挂载
多机部署 外部密钥管理(Vault/AWS/等)
CI/CD CI 系统的 secrets 管理功能
Build 阶段 BuildKit 的 –secret 参数

安全 checklist

  • [ ] Dockerfile 中无硬编码 secret
  • [ ] .env 文件在 .gitignore 中
  • [ ] 使用 Docker Secrets 或外部密钥管理
  • [ ] Secret 文件权限设置(chmod 600)
  • [ ] 构建镜像时不包含 secret
  • [ ] 定期轮换 secret
  • [ ] Secret 访问有审计日志

敏感信息管理是容器安全的重要环节。正确的 secret 管理方案可以有效防止密码泄露、API 密钥被盗等安全事件。

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容