1. 概述
在本教程中,我们将深入探讨 Hashicorp 的 Vault —— 一个在现代应用架构中广泛用于安全地管理敏感信息的工具。
我们将涵盖以下几个主要话题:
- Vault 解决了什么问题
- Vault 的架构和核心概念
- 搭建一个简单的测试环境
- 使用命令行工具与 Vault 进行交互
2. 敏感信息的管理难题
在深入了解 Vault 之前,我们先来理解它所要解决的核心问题:敏感信息的管理。
大多数应用程序都需要访问一些敏感数据才能正常运行。例如,一个电商应用可能需要配置数据库的用户名和密码;也可能需要集成支付网关、物流系统等第三方服务的 API Key。
数据库凭证和 API Key 是典型的敏感信息,我们需要以一种安全的方式存储并提供给应用程序使用。
一种常见的做法是将这些凭据存储在配置文件中,在启动时读取。但这种做法的问题显而易见:任何能够访问该文件的人都拥有与应用相同的数据库权限,通常这意味着可以访问所有数据。
我们可以尝试加密这些文件,但这并不能显著提升安全性,因为应用程序必须持有解密密钥。这种加密只是提供了一种“虚假的安全感”。
在现代云原生和微服务架构中,情况变得更加复杂:分布式服务、多个数据库、消息系统等,使得敏感信息遍布各处,大大增加了安全风险。
那么,我们该怎么办?交给 Vault 来处理吧!
3. 什么是 Vault?
Hashicorp Vault 专注于解决敏感信息(在 Vault 中称为 secret)的管理问题。这里的“管理”包括:生成、存储、使用和撤销整个生命周期。
Hashicorp 提供了两个版本的 Vault:
- 开源版本(本文使用):免费,可用于商业环境
- 企业版:提供技术支持和额外功能,如 HSM(硬件安全模块)支持
3.1. 架构与核心特性
Vault 的架构看起来简单,但非常强大。主要组件包括:
- 持久化后端:用于存储所有 secrets
- API 服务:处理客户端请求,执行操作
- Secret Engines:每种 secret 类型对应一个引擎
通过将所有敏感信息的处理交给 Vault,我们可以缓解多个安全问题:
✅ 应用不再需要存储敏感信息,只需在需要时向 Vault 请求并使用后丢弃
✅ 可以使用短期有效的 secrets,从而缩小攻击窗口
Vault 在将数据写入存储前会先使用加密密钥进行加密。这个加密密钥本身又由主密钥加密,而主密钥仅在启动时使用。
⚠️ 重要:Vault 不会在服务器上存储主密钥。这意味着,Vault 启动后也无法访问已保存的数据,此时 Vault 处于“sealed”状态。
稍后我们会介绍如何生成主密钥并“unseal” Vault 实例。
一旦 Vault 被 unseal,它就可以接受 API 请求。当然,这些请求需要进行身份认证。
3.2. 身份认证
客户端要访问 Vault 中的 secrets,必须通过支持的认证方式进行认证。最简单的方式是使用 Token,即每次 API 请求中通过一个特殊的 HTTP Header 发送。
安装后,Vault 会自动生成一个“root token”。这个 token 相当于 Linux 系统中的 root 用户,因此应尽量少用。最佳实践是使用 root token 创建权限更小的 token,然后撤销 root token。不过不用担心,我们可以用 unseal keys 重新生成 root token。
Vault 还支持其他认证方式,如 LDAP、JWT、TLS 证书等。这些方式最终都会生成一个 token,用于后续 API 请求。
Token 的一些关键属性包括:
- 关联的 策略(Policies)
- 生存时间(TTL)
- 是否可续期
- 最大使用次数
默认情况下,Vault 创建的 token 之间会形成父子关系。子 token 的权限不能超过父 token。
⚠️ 关键点:当一个 token 被撤销时,其所有子 token 及后代也会被一并撤销。
3.3. 策略(Policies)
策略定义了客户端可以访问哪些 secrets,以及可以执行哪些操作。下面是一个简单的策略示例:
path "secret/accounting" {
capabilities = [ "read" ]
}
我们使用 HCL(Hashicorp Configuration Language)定义策略。Vault 也支持 JSON,但 HCL 更易读。
Vault 的策略是“默认拒绝”的。上述策略只允许访问 secret/accounting
路径下的 secrets,其他路径一律拒绝。
一个 token 可以绑定多个策略,这样我们可以组合策略来实现更细粒度的权限控制。
另一个重要特性是策略支持懒加载:一旦策略更新,所有绑定该策略的 token 会立即生效。
Vault 中的策略类型:
- ACL Policies:访问控制列表策略(默认)
- EGP / RGP Policies:仅企业版支持,结合 Sentinel 实现更复杂的策略控制(如时间、网络、多因子等)
更多策略语法细节请参考 Vault 官方文档。
4. Secret 类型
Vault 支持多种 secret 类型,适用于不同场景:
- Key-Value:静态键值对
- 动态生成的凭证:由 Vault 按需生成
- 加密密钥:用于加密、解密、签名等操作
每种 secret 类型都有以下属性:
- 挂载点(mount point):定义其 REST API 前缀
- 支持的操作:如读、写、删除等
- 配置参数
每个 secret 实例通过一个类似文件系统路径的字符串访问。路径的第一部分即为该 secret 类型的挂载点。
例如:secret/my-application
表示在 secret
挂载点下,存储 my-application
相关的键值对。
4.1. Key-Value Secrets
Key-Value secrets 就是简单的键值对,存储在指定路径下。
例如,可以在 secret/my-application
下存储 foo=bar
。
Vault 支持三种 Key-Value 类型:
- 非版本化键值对:更新时直接覆盖
- 版本化键值对:保留多个旧版本(可配置)
- Cubbyhole:特殊类型,其值与特定 token 绑定
这类 secrets 是静态的,没有自动过期机制,适用于存储外部系统凭证,如 API Key。
4.2. 动态生成的 Secrets
动态 secrets 是由 Vault 在客户端请求时即时生成的。支持的类型包括:
- 数据库凭证
- SSH 密钥对
- X.509 证书
- AWS 凭证
- Google Cloud 服务账户
- Active Directory 账户
使用流程如下:
- 配置 secret engine,提供连接服务所需的凭证
- 定义一个或多个 roles,描述如何创建 secret
以数据库为例:
- 首先配置 Vault,提供连接数据库的管理员凭证
- 然后定义 Vault role,包含创建数据库用户的 SQL 语句(如
CREATE USER
和GRANT
)
✅ 当客户端请求时,Vault 会执行 SQL 创建临时用户,并返回其凭证。凭证的有效期由 TTL 决定,到期后自动撤销。
4.3. 加密密钥
这类 secret engine 用于执行加密、解密、签名等操作。所有操作都使用 Vault 内部生成和存储的加密密钥。
目前唯一的加密密钥引擎是 Transit,支持 RSA、ECDSA 等算法,还支持 Convergent Encryption(相同明文加密后结果一致),适用于如信用卡号加密等场景。
5. Vault 环境搭建
本节我们搭建一个本地测试环境,验证 Vault 的功能。
Vault 部署非常简单:只需 下载对应操作系统的包,将可执行文件(vault
或 vault.exe
)加入 PATH。
⚠️ Vault 的 development mode 适合快速测试,但不适合生产:数据重启后丢失,且使用 HTTP。
我们使用文件存储 + HTTPS 来模拟真实环境。
5.1. 启动 Vault 服务
Vault 使用 HCL 或 JSON 格式的配置文件。以下是一个使用文件存储和自签名证书的配置示例:
storage "file" {
path = "./vault-data"
}
listener "tcp" {
address = "127.0.0.1:8200"
tls_cert_file = "./src/test/vault-config/localhost.cert"
tls_key_file = "./src/test/vault-config/localhost.key"
}
启动命令:
$ vault server -config ./vault-test.hcl
5.2. 初始化 Vault
首次运行需要初始化,生成主密钥和 root token:
$ export VAULT_ADDR=https://localhost:8200
$ export VAULT_CACERT=./src/test/vault-config/localhost.cert
$ vault operator init
输出示例:
Unseal Key 1: <key share 1 value>
Unseal Key 2: <key share 2 value>
...
Initial Root Token: <root token value>
⚠️ 这些 unseal keys 和 root token 只在初始化时显示一次,务必保存好!
保存 root token:
$ export VAULT_TOKEN=<root token value>
查看状态:
$ vault status
Sealed true
Unseal Progress 0/3
5.3. 解封 Vault
需要提供任意 3 个 unseal keys:
$ vault operator unseal <key share 1 value>
$ vault operator unseal <key share 2 value>
$ vault operator unseal <key share 3 value>
解封成功后:
Sealed false
6. 测试 Vault
6.1. 使用 Key/Value Secrets
存储键值对:
$ vault kv put secret/fakebank api_key=abc1234 api_secret=1a2b3c4d
读取:
$ vault kv get secret/fakebank
=======
Key Value
--- -----
api_key abc1234
api_secret 1a2b3c4d
6.2. 创建新 Token
创建一个 1 分钟后过期的 token:
$ vault token create -ttl 1m
使用该 token 读取数据:
$ export VAULT_TOKEN=<token value>
$ vault kv get secret/fakebank
1 分钟后再次尝试会失败:
Error making API request.
Code: 403. Errors:
* permission denied
6.3. 测试策略
创建一个只读策略:
$ cat > sample-policy.hcl <<EOF
path "secret/fakebank" {
capabilities = ["read"]
}
EOF
$ vault policy write fakebank-ro ./sample-policy.hcl
创建绑定该策略的 token:
$ vault token create -policy=fakebank-ro
尝试写入会失败:
$ vault kv put secret/fakebank api_key=foo api_secret=bar
Error writing data to secret/fakebank: Error making API request.
Code: 403. Errors:
* permission denied
6.4. 使用动态数据库凭证
启用数据库引擎:
$ vault secrets enable database
配置数据库连接:
$ vault write database/config/mysql-fakebank \
plugin_name=mysql-legacy-database-plugin \
connection_url="{{username}}:{{password}}@tcp(127.0.0.1:3306)/fakebank" \
allowed_roles="*" \
username="fakebank-admin" \
password="Sup&rSecre7!"
创建角色:
$ vault write database/roles/fakebank-accounts-ro \
db_name=mysql-fakebank \
creation_statements="CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';GRANT SELECT ON fakebank.* TO '{{name}}'@'%';"
生成动态凭证:
$ vault read database/creds/fakebank-accounts-ro
Key Value
--- -----
username <username>
password <password>
使用凭证连接数据库:
$ mysql -h 127.0.0.1 -u <username> -p fakebank
MySQL [fakebank]> select * from account;
MySQL [fakebank]> delete from account;
ERROR 1142 (42000): DELETE command denied
1 小时后凭证自动失效。
7. 总结
本文介绍了 Hashicorp Vault 的基本概念、架构和使用方法,包括:
✅ 敏感信息管理的痛点
✅ Vault 的核心组件与功能
✅ 如何搭建测试环境
✅ 如何使用 Key/Value 和动态数据库凭证
✅ 如何使用策略和 token 控制权限
后续文章将介绍如何在 Spring Boot 项目中集成 Vault,敬请期待!