Vault的架构
Vault是由多个松耦合的部件组成的系统,总体来说它由以下几个部件组成:
- 后端存储(Storage Backend):后端存储负责将密文数据存储到可靠的持久存储上。Vault 并不假设后端存储上的数据不会被盗取,而只是假设该存储是持久、可靠的。Vault 只会向后端存储写入加密过的数据。后端存储应在 Vault 服务启动前被妥善配置。
- 屏障(Barrier):屏障是由加密算法所组成的钢筋混凝土防护工事。所有在 Vault 服务与后端存储之间流动的数据都会经过屏障处理。屏障确保了 Vault 写入后端存储的一切数据都是加密的,而从后端存储读取的数据都会经由屏障解密交由 Vault 服务使用。由于屏障的存在,Vault 服务启动后,必须进行“解封”(Unseal)处理,获得与后端存储数据相应的主密钥(Master Key)后才能正常工作。
- 机密引擎(Secret Engine):机密引擎负责管理各种机密数据。比如“KV“引擎,就是一种简单的保存静态机密数据的机密引擎。某些机密引擎可提供被查询时动态创建机密的动态机密功能,这使得 Vault 可以提供细颗粒度权限配置的一次一密的临时机密。例如为运维与开发配置不同的策略,并对应不同的 AWS 权限,相关人员每次读取相关机密时,由 Vault 动态创建一组拥有有限有效期和预设 AWS 权限的 Access Key 和 Secret Key,并确保在有效期过后由 Vault 在 AWS 上自动删除该Key。
- 审计设备(Audit Device):审计设备负责管理审计日志。进出 Vault 的每一个请求和响应都会被记录在预设的审计设备上。该部件为 Vault 与多种不同的审计日志存储的集成提供了一种简单的方式。
- 身份验证方法(Auth Method):身份验证方法被用来认证连接到 Vault 服务的用户或是应用程序的身份信息。一旦验证通过,身份验证组件会返回一组当前身份适用的策略信息。Vault 接受一个通过认证的用户,并返回一个可供将来使用的客户端令牌。举个例子,使用
userpass
认证方式,用户通过提供用户名与密码来进行认证。如果使用github
认证方式,用户通过 Github 令牌来通过 Vault 的认证。 - 客户端令牌(Client Token):一个客户端令牌(又称“Vault Token“)类似于网站的会话 Cookie。一旦用户通过认证,Vault 返回一个客户端令牌。该令牌可以被 Vault 用来识别客户端身份并使用相应的访问控制权限约束客户端权限。该令牌通过 HTTP Header 传递。
- 机密(Secret):机密指的是所有由 Vault 返回的包含机密信息或者密码学原材料(Cryptographic Material)的信息。并不是所有由 Vault 返回的信息都是机密,例如系统配置、服务状态信息、策略配置等就不属于机密范畴。机密都有对应的租约(Lease),这代表客户端不可以假设机密可以无限期地被使用。Vault 会在租约到期后吊销相关机密,Vault 管理员也可以在租约到期之前人工吊销机密。Vault 服务与客户端之间的这种契约是至关重要的,它允许实现全自动的机密凭据和策略的改变。
- 服务器(Server):Vault 依赖于一个长期运行服务实例的服务器。Vault 服务器对外提供了一组 API 用以与客户端互动,以及管理与各种机密引擎的互动,访问控制权限体系的执行,以及机密租约管理和吊销。服务器的架构设计解除了客户端与机密信息、权限策略的耦合,使得管理员可以轻松实现对审计日志的中央化管控。
架构全览
可以看到,只有后端存储以及 HTTP API 两部分位于屏障外部,其余所有部件都位于屏障内部。
Vault 不信任后端存储,所以只会向后端存储写入加密后的密文数据。当 Vault 服务启动时,必须配置一个后端存储,使得 Vault 重启后仍然可以读取到数据。HTTP API 同样也必须在 Vault 服务启动时被启动,才能使得客户端可以与 Vault 服务交互。
当 Vault 启动后,Vault 处于“封印(Sealed)”状态。在执行任意操作之前,首先要对 Vault 执行“解封(Unseal)”操作。当 Vault 服务初始化时会生成一个加密密钥,所有写入后端存储的数据都会用该密钥加密。该密钥由一个主密钥(Master Key)保护。默认情况下,Vault 使用 Shamir 算法将主密钥拆分成5份,需要至少 3 份才能重建主密钥:
主密钥拆分的份数以及解封要求的最低份数都可以被配置。我们也可以不使用 Shamir 算法,直接用主密钥解封。一旦 Vault 获得了加密密钥,就可以解密后端存储上的数据,服务进入解封状态。一旦解封,Vault 就会加载所有审计设备、认证方式以及机密引擎的配置信息。
当 Vault 解封,发往 Vault 的请求就可以通过 HTTP API 被转往核心(Core)进行处理。核心管理系统接收到的请求,强制执行访问控制权限,以及确保审计信息的成功写入。
当客户端首次与 Vault 连接,它需要经过身份认证。Vault 提供了多种身份认证方式。对人类用户比较友好的有 userpass
、github
等,应用程序可以使用证书或是 Token 认证。一个身份认证请求会经由核心抵达相应的认证方式,由认证方式判定认证是否通过,然后返回一组相关的策略。
策略(Policies)是一个命名的访问控制规则,比如说,root
策略是一个内建策略,它允许访问任意资源。你可以创建任意多个命名的策略,在相关路径上定义细致的权限控制。Vault 采用白名单的模式,意为除非策略明确允许某项操作,否则所有操作都是被禁止的。如果一个用户拥有多个策略,对于某项操作,只要任意策略允许就可以执行。策略由内部的策略存储(Policy Store)存储和管理。这个内部的策略存储通过系统后端(System Backend)控制,挂载路径总是为 sys/
。
一旦身份认证通过,并且身份认证方式返回一组适用的策略,Token 存储(Token Store)会生成并管理一个新的客户端 Token。该 Token 会被返回给客户端,用来作为后续操作的认证信息,这很像网站在用户登录后通过返回给用户的 Cookie 传递会话信息的机制。根据身份认证方式的配置,该客户端 Token 可能还会关联一个租约。这意味着客户端 Token 可能需要定期续约来避免过期。
一旦身份认证通过,后续请求都要附加客户端 Token。客户端 Token 被用来确认客户端有权加载相关策略。策略被用来验证客户请求的权限。通过验证的请求被路由到相关机密引擎,由机密引擎进行处理。如果机密引擎返回一个机密,核心会将其注册到过期管理器(Expiration Manager)并附加一个租约 ID。租约 ID 可用来续约租约或是吊销相关机密。如果客户端任由租约过期,过期管理器会自动吊销相关机密。
核心还负责将请求与响应的日志写入审计中介(Audit Broker),由审计中介负责将日志写入所有预设的审计设备。除了处理客户端发送的请求,核心还会负责特定的后台活动。租约管理是至关重要的,它允许自动吊销过期的客户端 Token 以及机密信息。另外, Vault 使用预写日志(Write Ahead Logging)和回滚管理器处理特定的失败场景。这些是由核心透明地执行的,对用户不可见。