强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Podman 完全指南 / 10 - 密钥管理

第 10 章 — 密钥管理

10.1 为什么需要密钥管理?

容器中经常需要使用敏感信息:数据库密码、API Token、TLS 证书等。错误的密钥管理会导致严重安全风险。

❌ 反面教材

# 直接在命令行传递密码(会出现在 ps 和 history 中)
podman run -e POSTGRES_PASSWORD=mysecret postgres

# 在 Dockerfile 中硬编码(会被提交到镜像层)
# ENV API_KEY=sk-1234567890

# 使用环境变量文件(明文存储在代码仓库中)
# .env 中写:DB_PASSWORD=secret123

✅ 正确方式

# 使用 Podman Secrets(加密存储,按需注入)
echo "mysecret" | podman secret create db-password -
podman run --secret db-password,type=env,target=POSTGRES_PASSWORD postgres

10.2 Podman Secrets

10.2.1 基本操作

# 创建 Secret(从标准输入)
echo "my-secret-password" | podman secret create db-password -

# 创建 Secret(从文件)
podman secret create tls-cert /path/to/cert.pem

# 创建 Secret(从字符串)
podman secret create api-key --env API_KEY

# 列出 Secrets
podman secret ls

# 查看 Secret 详情(不显示值)
podman secret inspect db-password

# 删除 Secret
podman secret rm db-password

# 清理所有未使用的 Secret
podman secret prune

10.2.2 在容器中使用 Secret

# 以文件形式挂载(默认挂载到 /run/secrets/<name>)
podman run -d --name db \
    --secret db-password \
    postgres:16-alpine

# 在容器中读取 Secret 文件
podman exec db cat /run/secrets/db-password
# my-secret-password

# 以环境变量形式注入
podman run -d --name db \
    --secret db-password,type=env,target=POSTGRES_PASSWORD \
    postgres:16-alpine

# 自定义挂载路径
podman run -d --name app \
    --secret db-password,target=password.txt \
    myapp:latest

# 使用多个 Secrets
podman run -d --name app \
    --secret db-password \
    --secret api-key \
    --secret tls-cert,target=/app/certs/tls.pem \
    myapp:latest

10.2.3 Secret 挂载方式对比

参数 效果
--secret name 挂载到 /run/secrets/name(文件)
--secret name,type=env,target=KEY 注入为环境变量 KEY
--secret name,target=/path/file 挂载到自定义路径

10.3 Quadlet 集成

10.3.1 在 .container 文件中使用 Secret

# ~/.config/containers/systemd/app.container
[Unit]
Description=My App

[Container]
Image=registry.example.com/app:v2.0
Secret=app-db-password,type=env,target=DATABASE_PASSWORD
Secret=app-api-key,target=/run/secrets/api-key
Volume=app-data.volume:/data:Z

[Service]
Restart=always

[Install]
WantedBy=default.target

10.4 环境变量管理

10.4.1 环境变量注入方式

# 方式一:-e 参数
podman run -e DB_HOST=localhost -e DB_PORT=5432 myapp

# 方式二:--env-file
cat > .env << 'EOF'
DB_HOST=localhost
DB_PORT=5432
DB_USER=appuser
DB_PASSWORD=secret123
API_KEY=sk-abcdef123456
EOF

podman run --env-file .env myapp

# 方式三:从宿主机环境变量传递
export DB_HOST=localhost
export DB_PASSWORD=secret
podman run -e DB_HOST -e DB_PASSWORD myapp

# 方式四:从 Secret 注入(推荐敏感信息)
podman run --secret db-password,type=env,target=DB_PASSWORD myapp

10.4.2 环境变量 vs Secrets

维度 环境变量 Podman Secrets
存储方式 明文 加密存储
可见性 podman inspect 可见 不可见
历史记录 可能出现在 shell history 不会泄露
更新 需要重建容器 可独立更新
适用场景 非敏感配置 密码、Token、证书

10.5 外部密钥管理集成

10.5.1 HashiCorp Vault

# 从 Vault 获取 Secret 并注入容器
VAULT_TOKEN=$(vault token lookup -format=json | jq -r '.data.id')
DB_PASS=$(vault kv get -field=password secret/myapp/db)

# 创建 Podman Secret
echo "$DB_PASS" | podman secret create db-password -

# 使用
podman run --secret db-password,type=env,target=DB_PASSWORD myapp

10.5.2 AWS Secrets Manager

# 从 AWS Secrets Manager 获取
DB_PASS=$(aws secretsmanager get-secret-value \
    --secret-id prod/myapp/db-password \
    --query 'SecretString' \
    --output text | jq -r '.password')

# 创建 Podman Secret
echo "$DB_PASS" | podman secret create db-password -

# 使用
podman run --secret db-password,type=env,target=POSTGRES_PASSWORD postgres:16

10.5.3 CI/CD 环境中的 Secret 管理

# GitLab CI — 从 CI 变量创建 Secret
# .gitlab-ci.yml
deploy:
  script:
    - echo "$DB_PASSWORD" | podman secret create db-password -
    - podman run -d --secret db-password,type=env,target=POSTGRES_PASSWORD postgres
    - podman secret rm db-password  # 清理

# GitHub Actions
# - name: Deploy
#   run: |
#     echo "${{ secrets.DB_PASSWORD }}" | podman secret create db-password -
#     podman run -d --secret db-password,type=env,target=POSTGRES_PASSWORD postgres

10.6 生产场景

场景一:数据库密码管理

#!/bin/bash
# 安全地部署数据库

# 1. 生成随机密码
DB_PASS=$(openssl rand -base64 32)

# 2. 创建 Secret
echo "$DB_PASS" | podman secret create db-production-password -

# 3. 部署数据库
podman run -d --name postgres-prod \
    --secret db-production-password,type=env,target=POSTGRES_PASSWORD \
    -e POSTGRES_USER=appuser \
    -e POSTGRES_DB=appdb \
    -v pgdata:/var/lib/postgresql/data:Z \
    postgres:16-alpine

# 4. 应用使用 Secret
podman run -d --name app-prod \
    --secret db-production-password,type=env,target=DB_PASSWORD \
    -e DB_HOST=postgres-prod \
    -e DB_USER=appuser \
    -e DB_NAME=appdb \
    myapp:v2.0

echo "数据库密码已安全创建,不会出现在 ps 或 history 中"

场景二:TLS 证书管理

# 创建 TLS 证书 Secret
podman secret create tls-cert /etc/ssl/certs/server.crt
podman secret create tls-key /etc/ssl/private/server.key

# 在 Nginx 中使用
podman run -d --name nginx-tls \
    --secret tls-cert,target=/etc/nginx/certs/server.crt \
    --secret tls-key,target=/etc/nginx/certs/server.key \
    -p 443:443 \
    nginx:1.27-alpine

场景三:API Key 轮换

#!/bin/bash
# API Key 轮换脚本

NEW_KEY=$(curl -s https://api.example.com/rotate-key)

# 删除旧 Secret
podman secret rm api-key 2>/dev/null

# 创建新 Secret
echo "$NEW_KEY" | podman secret create api-key -

# 重启使用该 Secret 的容器
podman restart app-using-api

10.7 安全最佳实践

✅ Do’s

# 1. 使用 Secrets 存储所有敏感信息
echo "$password" | podman secret create db-pass -

# 2. 使用完后及时清理临时 Secret
podman secret rm temp-secret

# 3. 使用 --password-stdin 登录仓库
echo "$REGISTRY_TOKEN" | podman login registry.example.com --username user --password-stdin

# 4. 定期轮换密钥

# 5. 使用 .gitignore 排除敏感文件
# .gitignore 中添加:
# .env
# *.pem
# *.key

❌ Don’ts

# 1. 不要在 Dockerfile 中硬编码密码
# ENV PASSWORD=secret  ❌

# 2. 不要在命令行传递敏感信息
podman run -e PASSWORD=mysecret ...  # ❌ 会出现在 ps 中

# 3. 不要在镜像中存储密钥
# COPY secret.pem /app/secret.pem  ❌ 会永久保留在镜像层

# 4. 不要在代码仓库中提交 .env 文件(包含密码的)

# 5. 不要使用 --privileged(会绕过所有安全限制)

10.8 本章小结

知识点 要点
创建 Secret podman secret create (stdin/文件)
使用 Secret --secret name(文件)或 type=env,target=KEY
存储位置 加密存储,不可通过 inspect 查看
环境变量 非敏感配置使用,敏感信息用 Secrets
外部集成 Vault、AWS Secrets Manager、CI/CD 变量
最佳实践 Secret > 环境变量 > 硬编码

下一步


扩展阅读