机密凭据管理中心

secrets-vault-manager
分类通用
作者Alireza Rezvani
许可MIT
评分4.20/5
使用10.4K

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) 认证。

hcl
# 启用 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 原生认证。

hcl
vault write auth/kubernetes/role/api-server \
  bound_service_account_names=api-server \
  bound_service_account_namespaces=production \
  policies=api-server-secrets \
  ttl=1h

OIDC —— 通过 SSO 提供商(Okta, Azure AD, Google Workspace)的人工操作员访问。

hcl
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 |

策略设计

遵循基于路径粒度的最小权限原则:

hcl
# 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 获取密钥 —— 绝不要将其硬编码在镜像或配置文件中。

python
# 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"])

python
# 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")

python
# 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_aapp_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)

hcl
# 配置数据库引擎
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 并行运行,处理身份验证和密钥渲染:

yaml
# 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 的团队:

yaml
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: key

GitHub Actions OIDC

通过使用 OIDC 联邦消除 CI 中的长期密钥:

yaml
- 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 秘密管理