Vault 架构核心:一个密封盒子的哲学

说实话,我第一次看 Vault 架构时,第一反应是:这东西怎么这么绕? 又是密封又是解封的,搞这么复杂干嘛?

后来线上出了次事故,我才明白。嗯,这个设计太聪明了。

Vault 本质上就是一个加密的钥匙盒。但它跟普通密码管理器最大的区别在于:它把“存储密钥”和“管理密钥”两件事彻底分开了。你想想看,如果这些密钥明文保存在磁盘上,攻击者拿到磁盘就等于拿到了所有秘密。

所以 Vault 的设计哲学是:默认谁都不信,包括它自己。

状态机:从 Seal 到 Unseal

Vault 只有两种状态:密封(Sealed) 和 解封(Unsealed)。

  • Sealed 状态:Vault 进程活着,但拒绝一切读写请求。就好像一个保险柜锁着,你只知道密码也没用,得先开锁。
  • Unsealed 状态:正常服务,读写秘密、签发令牌、动态生成凭证。

我刚上手时犯过一个错:觉得 Vault 启动后就能直接用。结果 client 连上去一直报 503,排查了半天……原来是忘了解封。

核心观点:Sealed 状态下,Vault 无法访问存储后端的数据加密密钥。只有提供足够数量的解封密钥分片,Vault 才能在内存中重建主密钥,完成解封。

存储后端:Vault 自己是不存数据的

这个点很多人误解。Vault 实例本身是无状态的。所有的秘密数据、策略、令牌信息,全都保存在存储后端(Storage Backend) 里。

Vault 支持多种后端,我整理了一个常用对比表:

后端类型 适用场景 高可用 我踩过的坑
Raft(集成) 小团队、测试环境、不想额外搭基础设施 是(内建共识) 磁盘 IO 压力大时,Leader 选举会频繁触发
Consul 生产环境、已有 Consul 集群 是(强一致) 网络分区时 Raft 脑裂,很长时间不可用
MySQL/PostgreSQL 需要复用现有数据库的团队 取决于数据库 HA 数据库连接数打满,Vault 直接挂掉
文件系统 开发、本地实验 否 千万不要用于生产!重启后数据丢了别怪我

重要提醒:存储后端不加密数据——它们保存的是 Vault 加密后的密文。但如果你觉得“反正存进去也是加密的”,就不管后端安全了,那会出大事。我在项目中遇到过:一个团队用公有云对象存储做后端,结果桶权限配置错误,攻击者虽然拿不到明文,但能删除所有数据。恢复起来简直噩梦。

解封机制:为什么不能一把钥匙开锁?

Vault 采用的是 Shamir 密钥分片算法。简单说:一个完整的主密钥被切割成 N 份,你需要至少 K 份才能还原它(这叫做 K/N 阈值策略)。

举个具体的例子:

# 初始化 Vault,生成 5 个密钥分片,解封需要至少 3 个
vault operator init -key-shares=5 -key-threshold=3

# 解封命令(需要执行至少 3 次,每次用不同分片)
vault operator unseal

为什么要这样设计?说白了就是为了防止单点风险。

你想想看:

  • 一把钥匙:一个人带着钥匙跑了,或者被黑客偷了,全完蛋。
  • 多把钥匙+阈值:安全管理员、运维负责人、架构师各保存一份。即使丢了一两份,系统照样能工作。

我见过一个团队,解封密钥只交给了一个负责人。结果这个负责人去旅游失联了……Vault 彻底起不来,所有服务下线两天。嗯,这就是血的教训。

单机部署实践:从零搭一个能用的 Vault

虽然生产环境必须集群化,但本地实验用单机就够了。我个人习惯先搭个单实例验证思路。

步骤很简单,就三件事:

  1. 下载并启动
  2. 初始化并获取密钥分片
  3. 解封后开始使用

配置示例:

# 最简单的配置,用文件存储
storage "file" {
  path = "/tmp/vault/data"
}

listener "tcp" {
  address     = "127.0.0.1:8200"
  tls_disable = true
}

api_addr = "http://127.0.0.1:8200"

个人经验:初次初始化会打印 5 个密钥分片。请务必拆开存储,甚至可以用物理介质分开保存。我习惯把 1 个放本地保险箱,2 个给团队核心成员,另外 2 个加密后上传到不同云存储(不同厂商)。这招虽然麻烦,但真出事时能救命。

启动后执行:

# 启动 Vault(不加参数默认加载当前目录的 config.hcl)
vault server -config=config.hcl

# 另一个终端执行初始化
export VAULT_ADDR=http://127.0.0.1:8200
vault operator init

# 会输出类似这样的内容:
# Unseal Key 1: abc123...
# Unseal Key 2: def456...
# Initial Root : s.xyz789...

用 root 登录后,就可以创建秘密引擎、写策略、存秘密了。但我强烈建议:root 只在初始化和解封时用,平常日常操作全部用子令牌或 AppRole 认证。

避坑指南:我曾经在生产环境看到有人没配置 tls 就直接开放了 8200 端口给公网。结果不出 3 小时,Vault 就被暴力破解了。记住:tls_disable = true 只允许在本地调试时用,线上必须配证书。

一句话总结架构

如果你只能记住 Vault 的一个核心架构概念,那就是:存储后端保存加密数据,解封机制保护加密密钥,Vault 实例本身只是无状态的计算节点。

这三层彼此独立,任何一层被攻破都无法直接拿到秘密。攻击者得同时搞定存储后端(拿到密文)+ 收集足够的解封密钥分片。成本极高。这才是高可用的安全设计。

Vault 核心架构图 客户端 Vault API Seal / Unseal 存储后端 解封密钥分片 核心逻辑:客户端请求 → Vault 检查密封状态 → 未密封则从存储后端读写加密数据

这张图我画得比较直接。你顺着箭头看:客户端发起请求,Vault 先看自己是不是密封状态。如果是,你只能干瞪眼。解封之后,Vault 用内存中的主密钥加密/解密数据,跟后端交互存读取。嗯,就这么个闭环。