机密凭据管理中心
Secrets Vault Manager (密钥库管理器)
级别: POWERFUL
类别: Engineering
领域: Security / Infrastructure / DevOps
---
概述
为运行 HashiCorp Vault、云原生密钥存储或混合架构的团队提供生产级密钥基础设施管理。该技能涵盖策略编写、认证方法配置、自动化轮转、动态密钥、审计日志和事件响应。
与 env-secrets-manager 的区别: 后者处理本地 .env 文件的规范化和泄漏检测。本技能运行在基础设施层 —— 包括 Vault 集群、云 KMS、证书颁发机构 (CA) 以及 CI/CD 密钥注入。
使用场景
- 搭建新的 Vault 集群或迁移至托管密钥存储
- 为服务、CI Runner 和人工操作员设计认证方法
- 实现凭据自动化轮转(数据库、API 密钥、证书)
- 为合规性(SOC 2, ISO 27001, HIPAA)审计密钥访问模式
- 响应密钥泄漏并执行大规模吊销
- 将密钥集成到 Kubernetes 工作负载或 CI/CD 流水线中
---
HashiCorp Vault 模式
架构决策
| 决策项 | 推荐方案 | 理由 |
|----------|---------------|-----------|
| 部署模式 | 基于 Raft 存储的高可用 (HA) 模式 | 无外部依赖,内置领导者选举 |
| 自动解封 | 云 KMS (AWS KMS / Azure Key Vault / GCP KMS) | 消除手动解封,支持自动化重启 |
| 命名空间 (Namespaces) | 每个环境一个 (dev/staging/prod) | 隔离故障半径,独立策略管理 |
| 审计设备 | 文件 + syslog (双重) | 若所有审计设备失效,Vault 将拒绝请求 —— 双重配置可防止停机 |
认证方法
AppRole —— 用于服务和批处理任务的机器对机器 (M2M) 认证。
# 启用 AppRole
path "auth/approle/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
特定应用程序的角色
vault write auth/approle/role/payment-service \
token_ttl=1h \
token_max_ttl=4h \
secret_id_num_uses=1 \
secret_id_ttl=10m \
token_policies="payment-service-read"Kubernetes —— 通过服务账户 (Service Account) 令牌实现的 Pod 原生认证。
vault write auth/kubernetes/role/api-server \
bound_service_account_names=api-server \
bound_service_account_namespaces=production \
policies=api-server-secrets \
ttl=1hOIDC —— 通过 SSO 提供商(Okta, Azure AD, Google Workspace)的人工操作员访问。
vault write auth/oidc/role/engineering \
bound_audiences="vault" \
allowed_redirect_uris="https://vault.example.com/ui/vault/auth/oidc/oidc/callback" \
user_claim="email" \
oidc_scopes="openid,profile,email" \
policies="engineering-read" \
ttl=8h密钥引擎 (Secret Engines)
| 引擎 | 使用场景 | TTL 策略 |
|--------|----------|-------------|
| KV v2 | 静态密钥 (API keys, 配置) | 版本化,手动轮转 |
| Database | 动态数据库凭据 | 默认 1h,最大 24h |
| PKI | TLS 证书 | 叶证书 90d,中间 CA 5y |
| Transit | 加密即服务 (EaaS) | 每 90d 轮转一次密钥 |
| SSH | 签名 SSH 证书 | 交互式 30m,自动化 8h |
策略设计
遵循基于路径粒度的最小权限原则:
# payment-service-read 策略
path "secret/data/production/payment/*" {
capabilities = ["read"]
}
path "database/creds/payment-readonly" {
capabilities = ["read"]
}
显式拒绝访问管理路径
path "sys/*" {
capabilities = ["deny"]
}策略命名规范: {service}-{access-level}(例如 payment-service-read, api-gateway-admin)。
---
云端密钥存储集成
对比矩阵
| 特性 | AWS Secrets Manager | Azure Key Vault | GCP Secret Manager |
|---------|--------------------|-----------------|--------------------|
| 轮转 | 内置 Lambda | 通过 Functions 实现自定义逻辑 | Cloud Functions |
| 版本控制 | 自动 | 手动或自动 | 自动 |
| 加密 | AWS KMS (默认或 CMK) | HSM 支撑 | Google 管理或 CMEK |
| 访问控制 | IAM 策略 + 资源策略 | RBAC + 访问策略 | IAM 绑定 |
| 跨区域 | 支持复制 | 默认地理冗余 | 支持复制 |
| 审计 | CloudTrail | Azure Monitor + 诊断日志 | Cloud Audit Logs |
| 计费模式 | 按密钥数量 + 按 API 调用次数 | 按操作次数 + 按密钥数量 | 按密钥版本 + 按访问次数 |
如何选择
- AWS Secrets Manager:开箱即用的 RDS/Aurora 凭据轮转。最适合全量部署在 AWS 的场景。
- Azure Key Vault:证书管理能力强。Azure AD 集成工作负载的必需选择。
- GCP Secret Manager:API 界面最简洁。最适合使用 Workload Identity 的 GKE 原生工作负载。
- HashiCorp Vault:多云支持、动态密钥、PKI、传输加密。最适合复杂或混合云环境。
SDK 访问模式
原则: 始终在启动时或通过 sidecar 获取密钥 —— 绝不要将其硬编码在镜像或配置文件中。
# AWS Secrets Manager 模式
import boto3, json
def get_secret(secret_name, region="us-east-1"):
client = boto3.client("secretsmanager", region_name=region)
response = client.get_secret_value(SecretId=secret_name)
return json.loads(response["SecretString"])
# GCP Secret Manager 模式
from google.cloud import secretmanager
def get_secret(project_id, secret_id, version="latest"):
client = secretmanager.SecretManagerServiceClient()
name = f"projects/{project_id}/secrets/{secret_id}/versions/{version}"
response = client.access_secret_version(request={"name": name})
return response.payload.data.decode("UTF-8")
# Azure Key Vault 模式
from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient
def get_secret(vault_url, secret_name):
credential = DefaultAzureCredential()
client = SecretClient(vault_url=vault_url, credential=credential)
return client.get_secret(secret_name).value
---
密钥轮转工作流
按密钥类型的轮转策略
| 密钥类型 | 轮转频率 | 方法 | 停机风险 |
|-------------|-------------------|--------|---------------|
| 数据库密码 | 30 天 | 双账号切换 | 零 (A/B 轮转) |
| API 密钥 | 90 天 | 生成新密钥,弃用旧密钥 | 零 (重叠窗口期) |
| TLS 证书 | 过期前 60 天 | ACME 或 Vault PKI | 零 (平滑重载) |
| SSH 密钥 | 90 天 | Vault 签名证书 | 零 (基于 CA) |
| 服务令牌 | 24 小时 | 动态生成 | 零 (短生命周期) |
| 加密密钥 | 90 天 | 密钥版本化 (重新封装) | 零 (版本共存) |
数据库凭据轮转 (双账号模式)
1. 存在两个数据库账号...
1. 准备两个用户:app_user_a 和 app_user_b
2. 应用程序当前使用 app_user_a
3. 轮转机制更新 app_user_b 的密码并更新密钥存储
4. 应用程序在下次获取凭据时切换到 app_user_b
5. 宽限期结束后,轮转 app_user_a 的密码
6. 循环往复
API 密钥轮转(重叠窗口)
1. 向提供商申请生成新 API 密钥
2. 将新密钥在密钥存储中标记为 current,将旧密钥移至 previous
3. 部署应用程序 —— 程序读取 current 密钥
4. 所有实例重启(或 TTL 过期)后,撤销 previous 密钥
5. 在撤销前,通过监控确认旧密钥已无使用记录
---
动态密钥
动态密钥按需生成且自动过期。只要可行,应优先使用动态密钥而非静态凭据。
数据库动态凭据 (Vault)
# 配置数据库引擎
vault write database/config/postgres \
plugin_name=postgresql-database-plugin \
connection_url="postgresql://{{username}}:{{password}}@db.example.com:5432/app" \
allowed_roles="app-readonly,app-readwrite" \
username="vault_admin" \
password="<admin-password>"
创建带有 TTL 的角色
vault write database/roles/app-readonly \
db_name=postgres \
creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
default_ttl=1h \
max_ttl=24h云 IAM 动态凭据
Vault 可以生成短期的 AWS IAM 凭据、Azure 服务主体密码或 GCP 服务账号密钥 —— 从根本上消除长期有效的云凭据。
SSH 证书颁发机构 (CA)
用 Vault 签名的证书模型取代 SSH 密钥分发:
1. Vault 作为 SSH CA
2. 用户/机器请求短期 TTL(30 分钟)的签名证书
3. SSH 服务器信任 CA 公钥 —— 无需管理 authorized_keys
4. 证书自动过期 —— 常规操作无需手动撤销
---
审计日志
日志记录内容
| 事件 | 优先级 | 保留期限 |
|-------|----------|-----------|
| 密钥读取访问 | 高 | 最少 1 年 |
| 密钥创建/更新 | 高 | 最少 1 年 |
| 认证方法登录 | 中 | 90 天 |
| 策略变更 | 极高 | 2 年(合规要求) |
| 访问尝试失败 | 极高 | 1 年 |
| 令牌创建/撤销 | 中 | 90 天 |
| 密封/解封操作 | 极高 | 永久 |
异常检测信号
- 密钥被来自新 IP/CIDR 段的请求访问
- 访问量激增(路径访问量 > 基准值的 3 倍)
- 人员认证方法在非工作时间访问
- 服务访问超出其策略范围的密钥(被拒绝的请求)
- 单一来源多次认证失败
- 创建的令牌 TTL 异常过长
合规报告
定期生成包含以下内容的报告:
1. 访问清单 —— 哪些身份在何时访问了哪些密钥
2. 轮转合规性 —— 过期未轮转的密钥
3. 策略漂移 —— 自上次审查以来被修改的策略
4. 孤立密钥 —— 长期无访问记录(>90 天)的密钥
使用 audit_log_analyzer.py 解析 Vault 或云审计日志以提取这些信号。
---
应急预案
密钥泄露响应(立即执行)
时间目标:在检测后 15 分钟内完成遏制。
1. 确定范围 —— 哪些密钥泄露,泄露位置(代码库、日志、错误消息、第三方)
2. 立即撤销 —— 在源头(提供商 API、Vault、云 SM)轮转受损凭据
3. 使令牌失效 —— 撤销
撤销所有访问过泄露密钥的 Vault token
4. 审计影响范围 — 查询审计日志,核查在泄露时间窗内该受损密钥的使用情况
5. 通知相关方 — 安全团队、受影响的服务所有者、合规部门(若涉及 PII/监管数据)
6. 事后分析 — 记录根本原因,更新控制措施以防止再次发生
Vault 密封操作 (Seal Operations)
密封时机: 影响 Vault 基础设施的活动安全事件,或怀疑密钥被泄露。
密封 (Sealing) 会停止所有 Vault 操作。仅在万不得已时使用。
解封流程:
1. 召集达到法定人数的解封密钥持有者(Shamir 阈值)
2. 或确认自动解封 (auto-unseal) 的 KMS 密钥可访问
3. 通过 vault operator unseal 解封,或通过自动解封重启
4. 验证审计设备已重新连接
5. 检查活动租约和 token 有效性
完整剧本请参阅 references/emergency_procedures.md。
---
CI/CD 集成
Vault Agent Sidecar (Kubernetes)
Vault Agent 与应用程序 Pod 并行运行,处理身份验证和密钥渲染:
# Vault Agent Injector 的 Pod 注解
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "api-server"
vault.hashicorp.com/agent-inject-secret-db: "database/creds/app-readonly"
vault.hashicorp.com/agent-inject-template-db: |
{{- with secret "database/creds/app-readonly" -}}
postgresql://{{ .Data.username }}:{{ .Data.password }}@db:5432/app
{{- end }}External Secrets Operator (Kubernetes)
适用于倾向于声明式 GitOps 而非 Agent Sidecar 的团队:
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: api-credentials
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-backend
kind: ClusterSecretStore
target:
name: api-credentials
data:
- secretKey: api-key
remoteRef:
key: secret/data/production/api
property: keyGitHub Actions OIDC
通过使用 OIDC 联邦消除 CI 中的长期密钥:
- name: Authenticate to Vault
uses: hashicorp/vault-action@v2
with:
url: https://vault.example.com
method: jwt
role: github-ci
jwtGithubAudience: https://vault.example.com
secrets: |
secret/data/ci/deploy api_key | DEPLOY_API_KEY ;
secret/data/ci/deploy db_password | DB_PASSWORD---
反模式 (Anti-Patterns)
| 反模式 | 风险 | 正确做法 |
|-------------|------|-----------------|
| 源代码中硬编码密钥 | 通过仓库、日志、错误输出泄露 | 运行时从密钥存储中获取 |
| 长期静态 token (>30 天) | 凭据过期,缺乏可追溯性 | 动态密钥或短 TTL + 轮转 |
| 共享服务账户 | 每个消费者缺乏审计轨迹 | 为每个服务分配具有唯一凭据的身份 |
| 无轮转策略 | 受损凭据无限期有效 | 按计划自动轮转 |
| CI 环境中使用环境变量存储密钥 | 在构建日志、进程表中可见 | 使用 Vault Agent 或基于 OIDC 的注入 |
| 单一解封密钥持有者 | 单点故障 (Bus factor of 1),恢复受阻 | Shamir 分片 (3-of-5) 或自动解封 |
| 未配置审计设备 | 访问可见度为零 | 配置双审计设备 (文件 + syslog) |
| 通配符策略 (path "*") | 权限过大,违反最小权限原则 | 为每个服务定义明确的基于路径的策略 |
---
工具
| 脚本 | 用途 |
|--------|---------|
| vault_config_generator.py | 根据应用程序需求生成 Vault 策略和认证配置 |
| rotation_planner.py | 创建...
从秘密库存文件中生成轮换计划 |
| audit_log_analyzer.py | 分析审计日志以发现异常和合规漏洞 |
---
交叉引用
- env-secrets-manager — 本地
.env文件清理、泄漏检测、漂移感知
- senior-secops — 安全运营、事件响应、威胁建模
- ci-cd-pipeline-builder — 消费秘密的流水线设计
- docker-development — 容器秘密注入模式
- helm-chart-builder — Helm Chart 中的 Kubernetes 秘密管理