深色模式
密钥与凭据管理:Vault 与集中式密钥中心
摘要:凭据泄露是运维最常见的事故源。本文给出"先发现明文凭据 → 再集中托管 → 最后轮换与审计"的落地路径,包含 Vault 的最小可用部署与动态数据库凭据实践。
适用环境
bash
cat /etc/os-release
command -v vault && vault version
command -v docker && docker --version
command -v aws && aws --version # 云上可改用 KMS/Secrets Manager1
2
3
4
2
3
4
操作步骤
1. 先找出散落在各处的明文凭据
bash
grep -rInE '(password|passwd|secret|token|api[_-]?key)\s*[:=]' \
--exclude-dir={.git,node_modules,vendor} /opt /srv /etc 2>/dev/null | head -30
# 环境变量里也常有
systemctl show nginx -p Environment 2>/dev/null
docker inspect <container> --format '{{json .Config.Env}}' 2>/dev/null1
2
3
4
5
2
3
4
5
把命中项登记成清单:位置、用途、负责人、能否立即轮换。
2. 最小可用地跑起 Vault(演示用 dev 模式,生产请用正式存储后端)
bash
# 演示/学习:dev 模式,重启即丢数据
vault server -dev -dev-root-token-id=root -dev-listen-address=127.0.0.1:8200 &
export VAULT_ADDR=http://127.0.0.1:8200
export VAULT_TOKEN=root
vault status1
2
3
4
5
2
3
4
5
dev 模式仅用于本地练习
生产必须用 file/raft/consul 等持久存储、启用 TLS、配置自动 unseal 与审计设备。
3. 存静态密钥并带版本号
bash
vault kv enable-versioning secret
vault kv put secret/app/db password='S3cr3t-Initial' username='appuser'
vault kv get secret/app/db
vault kv put secret/app/db password='S3cr3t-Rotated' username='appuser'
vault kv get -version=1 secret/app/db # 历史版本可回滚1
2
3
4
5
2
3
4
5
4. 用策略限制谁能读什么
bash
cat >app-policy.hcl <<'EOF'
path "secret/data/app/*" {
capabilities = ["read", "list"]
}
EOF
vault policy write app-policy app-policy.hcl
vault token create -policy=app-policy -ttl=24h -format=json \
| jq -r '.auth.client_token'1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
5. 动态数据库凭据:用完即毁,不落库
bash
vault secrets enable database
vault write database/config/prod-mysql \
plugin_name=mysql-database-plugin \
connection_url="{{username}}:{{password}}@tcp(127.0.0.1:3306)/" \
allowed_roles="app-readonly" \
username="vaultadmin" password="VaultAdminPass"
vault write database/roles/app-readonly \
db_name=prod-mysql \
creation_statements="CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}'; GRANT SELECT ON appdb.* TO '{{name}}'@'%';" \
default_ttl="1h" max_ttl="24h"
vault read database/creds/app-readonly # 每次返回一套临时账号1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
6. 应用侧取凭据:注入而非硬编码
bash
# 方式一:启动前由 agent 渲染模板
vault agent -config=agent.hcl &
# 方式二:容器以 sidecar 注入环境变量(K8s 用 Vault Agent Injector)
kubectl get pods -n app -o wide1
2
3
4
2
3
4
7. 开启审计设备:谁读了什么必须有记录
bash
vault audit enable file file_path=/var/log/vault-audit.log
tail -f /var/log/vault-audit.log | jq '.request.path, .auth.display_name'1
2
2
8. 云上替代方案对照
| 场景 | 自建 | 云托管 |
|---|---|---|
| 静态密钥 | Vault KV | AWS Secrets Manager / 阿里云 KMS 凭据管家 |
| 数据加密 | Vault Transit | AWS KMS / GCP KMS |
| 临时身份 | Vault 动态凭据 | AWS STS / 云 RAM 角色 |
验证
bash
vault status | grep -E 'Sealed|Version'
vault token lookup | grep -E 'policies|ttl'
vault read database/creds/app-readonly # 两次结果应不同
mysql -h127.0.0.1 -u"$U" -p"$P" -e 'select 1' # 临时账号可用
vault lease revoke -prefix database/creds/app-readonly1
2
3
4
5
2
3
4
5
判定标准:配置中无明文凭据;每个应用只持有最小策略的 token;凭据读取全部出现在审计日志。
常见坑
把 Vault root token 写进 CI 或镜像
root token 等于全库权限。应使用受限策略 token + 短 TTL,并启用 AppRole 等机器身份认证。
轮换做了,但旧凭据没失效
改了 Vault 里的值不等于数据库/第三方 API 的旧密码失效。轮换必须同步到真实系统并验证旧凭据已被拒绝。
动态凭据 TTL 过长
TTL 设置成几个月就退化成静态凭据了。建议默认 1h,上限 24h,并配合短连接或重取机制。
只加密不明文,却不审计
没有审计设备的密钥中心无法回答"谁在何时读了哪个密钥",合规与事后追溯都会缺一环。
把密钥写进 Git 后再删除就以为安全
Git 历史永久保留。必须轮换密钥,而不是删文件。