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

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 本章小结

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

下一步


扩展阅读