© 2016-2021 原作者。
本文档的副本可以供您自己使用和分发给其他人,前提是您不对此类副本收取任何费用,并且进一步前提是每份副本都包含本版权声明,无论是印刷版还是电子版。 |
前言
Spring Vault 项目将核心 Spring 概念应用于使用 HashiCorp Vault 开发解决方案。我们提供“模板”作为存储和查询文档的高级抽象。您会注意到与 Spring Framework 中的 REST 支持的相似之处。
本文档是 Spring Vault 的参考指南。它解释了 Vault 的概念和语义以及语法。
这部分参考文档解释了 Spring Vault 提供的核心功能。
Vault 支持引入了 Vault 模块功能集。
1. 文件结构
本节提供 Spring 和 Vault 的基本介绍。它包含有关后续开发以及如何获得支持的详细信息。
文档的其余部分涉及 Spring Vault 功能,并假设用户熟悉HashiCorp Vault 以及 Spring 概念。
2.认识Spring
Spring Vault 使用 Spring 框架的核心功能,例如IoC容器。虽然了解 Spring API 并不重要,但了解它们背后的概念才是重要的。对于您选择使用的任何 IoC 容器,至少应该熟悉 IoC 背后的理念。
Vault 支持的核心功能可以直接使用,无需调用 Spring Container 的 IoC 服务。这很像RestTemplate
可以在没有任何其他 Spring 容器服务的情况下“独立”使用。要利用 Spring Vault 文档的所有功能,例如会话支持,您需要使用 Spring 配置库的某些部分。
要了解有关 Spring 的更多信息,您可以参考详细解释 Spring 框架的全面(有时是解除武装)文档。有很多关于这个问题的文章、博客条目和书籍——请查看 Spring 框架主页以获取更多信息。
3.认识保险柜
安全性和使用机密是每个使用数据库、用户凭证或 API 密钥的开发人员关心的问题。Vault 通过提供与访问控制、撤销、密钥滚动和审计相结合的安全存储来介入。简而言之:Vault 是一种用于安全访问和存储机密的服务。机密是您想要严格控制访问的任何内容,例如 API 密钥、密码、证书等。
了解 Vault 的起点是www.vaultproject.io。以下是有用资源的列表:
-
该手册介绍了 Vault 并包含指向入门指南、参考文档和教程的链接。
-
在线 shell 结合在线教程提供了一种与 Vault 实例交互的便捷方式。
Spring Vault 为访问、存储和撤销机密提供客户端支持。使用HashiCorp 的 Vault,您可以集中管理所有环境中应用程序的外部机密数据。Vault 可以管理静态和动态机密,例如应用程序数据、远程应用程序/资源的用户名/密码,并为 MySQL、PostgreSQL、Apache Cassandra、Consul、AWS 等外部服务提供凭证。
4. 要求
Spring Vault 2.x 二进制文件需要 JDK 级别 8.0 及以上,以及Spring Framework 5.3.4 及以上。
就Vault而言,Vault至少0.6。
5. 其他帮助资源
学习一个新的框架并不总是直截了当的。在本节中,我们尝试提供我们认为易于遵循的 Spring Vault 模块入门指南。但是,如果您遇到问题或只是寻求建议,请随时使用以下链接之一:
5.1。支持
有几个可用的支持选项:
5.1.1。社区论坛
在Stackoverflow上发布有关 Spring Vault 的问题,以共享信息并互相帮助。请注意,仅发布时需要注册。
5.1.2. 专业支持
Spring Vault 和 Spring 背后的公司Pivotal Software, Inc.提供专业的源代码支持和有保证的响应时间。
5.2. 跟随发展
有关 Spring Vault 源代码存储库、夜间构建和快照工件的信息,请参阅Spring Vault 主页。您可以通过Stackoverflow上的社区与开发人员互动,帮助 Spring Vault 更好地满足 Spring 社区的需求。如果您遇到错误或想提出改进建议,请在 Spring Vault 问题跟踪器上创建票证。要及时了解 Spring 生态系统中的最新消息和公告,请订阅 Spring 社区门户。最后,您可以在 Twitter ( SpringCentral )上关注 Spring博客或项目团队。
6.新的和值得注意的
6.1。Spring Vault 2.3 中的新增功能
-
支持用于密钥库和信任库的 PEM 编码证书。
-
ReactiveVaultEndpointProvider
用于非阻塞查找VaultEndpoint
. -
VaultKeyValueMetadataOperations
用于键值元数据交互。 -
支持
transform
后端(企业功能)。 -
每次登录尝试都会重新加载 Kubernetes 和 PCF 身份验证的登录凭据。
-
SecretLeaseContainer
发布SecretLeaseRotatedEvent
而不是成功SecretLeaseExpiredEvent
的SecretLeaseCreatedEvent
秘密轮换。 -
AbstractVaultConfiguration.threadPoolTaskScheduler()
bean 类型更改为TaskSchedulerWrapper
而不是ThreadPoolTaskScheduler
.
6.2. Spring Vault 2.2 中的新功能
-
通过
@VaultPropertySource
. -
SpEL 支持
@Secret
. -
添加对 Jetty 作为响应式 HttpClient 的支持。
-
LifecycleAwareSessionManager
现在ReactiveLifecycleAwareSessionManager
发出AuthenticationEvent
。 -
弃用
AppIdAuthentication
.AppRoleAuthentication
按照 HashiCorp Vault 的建议使用。 -
CubbyholeAuthentication
并且包装AppRoleAuthentication
现在sys/wrapping/unwrap
默认使用端点。 -
Kotlin 协程支持
ReactiveVaultOperations
.
6.4. Spring Vault 2.0 中的新功能
-
身份验证步骤 DSL组成身份验证流程。
-
通过
ReactiveVaultOperations
. _ -
基于 Spring Data KeyValue 的Vault 存储库支持。
-
中转批量加密和解密支持。
-
存储为 JSON 的策略的策略管理。
-
支持 CSR 签名、证书撤销和 CRL 检索。
-
用于AppRole 身份验证的 RoleId/SecretId 解包。
-
Spring Security与基于中转后端的集成
BytesKeyGenerator
和BytesEncryptor
.
6.5。Spring Vault 1.1.0 中的新增功能
-
配置传输密钥的加密/解密版本。
-
AppRole 身份验证的拉取模式。
-
中转批量加密和解密支持。
-
基于 TTL 的通用秘密轮换。
参考文档
7.保险库支持
Vault 支持包含广泛的功能,总结如下。
-
使用基于 Java 的 @Configuration 类的 Spring 配置支持
-
VaultTemplate
帮助程序类,可提高执行常见 Vault 操作的生产力。包括 Vault 响应和 POJO 之间的集成对象映射。
对于大多数任务,您会发现自己使用VaultTemplate
的是利用丰富的通信功能。VaultTemplate
是寻找访问功能的地方,例如从 Vault 读取数据或发出管理命令。VaultTemplate
还提供回调方法,以便您轻松掌握低级 API 工件,例如RestTemplate
直接与 Vault 通信。
7.1。依赖项
查找 Spring Vault 依赖项的兼容版本的最简单方法是依靠我们附带定义的兼容版本的 Spring Vault BOM。在 Maven 项目中,您将在以下
<dependencyManagement />
部分声明此依赖项pom.xml
:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.vault</groupId>
<artifactId>spring-vault-dependencies</artifactId>
<version>2.3.1</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
当前版本是2.3.1
. 版本名称遵循以下模式:${version}
用于 GA 和服务版本以及${version}-${release}
用于快照和里程碑。release
可以是以下之一:
-
SNAPSHOT
- 当前快照 -
M1
等M2
- 里程碑 -
RC1
等RC2
- 发布候选
<dependencies>
<dependency>
<groupId>org.springframework.vault</groupId>
<artifactId>spring-vault-core</artifactId>
</dependency>
</dependencies>
8. 入门
Spring Vault 支持需要 Vault 0.6 或更高版本以及 Java SE 6 或更高版本。引导设置工作环境的一种简单方法是在STS中创建一个基于 Spring 的项目。
首先,您需要设置一个正在运行的 Vault 服务器。有关如何启动 Vault 实例的说明,请参阅Vault。
要在 STS 中创建 Spring 项目,请转到 File → New → Spring Template Project → Simple Spring Utility Project → 在出现提示时按 Yes。然后输入一个项目和一个包名,例如org.spring.vault.example
.
然后将以下内容添加到pom.xml
依赖项部分。
<dependencies>
<!-- other dependency elements omitted -->
<dependency>
<groupId>org.springframework.vault</groupId>
<artifactId>spring-vault-core</artifactId>
<version>2.3.1</version>
</dependency>
</dependencies>
如果您使用的是里程碑或候选发布版本,您还需要将 Spring Milestone 存储库的位置添加到您的 Maven中,该位置与您的元素pom.xml
处于同一级别。<dependencies/>
<repositories>
<repository>
<id>spring-milestone</id>
<name>Spring Maven MILESTONE Repository</name>
<url>https://repo.spring.io/libs-milestone</url>
</repository>
</repositories>
该存储库也可在此处浏览。
如果您使用的是 SNAPSHOT,您还需要将 Spring Snapshot 存储库的位置添加到您的 maven中,该位置与您的元素pom.xml
处于同一级别。<dependencies/>
<repositories>
<repository>
<id>spring-snapshot</id>
<name>Spring Maven SNAPSHOT Repository</name>
<url>https://repo.spring.io/libs-snapshot</url>
</repository>
</repositories>
该存储库也可在此处浏览。
创建一个简单的Secrets
类来持久化:
package org.spring.vault.example;
public class Secrets {
String username;
String password;
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
}
以及要运行的主要应用程序
package org.springframework.vault.example;
import org.springframework.vault.authentication.TokenAuthentication;
import org.springframework.vault.client.VaultEndpoint;
import org.springframework.vault.core.VaultTemplate;
import org.springframework.vault.support.VaultResponseSupport;
public class VaultApp {
public static void main(String[] args) {
VaultTemplate vaultTemplate = new VaultTemplate(new VaultEndpoint(),
new TokenAuthentication("00000000-0000-0000-0000-000000000000"));
Secrets secrets = new Secrets();
secrets.username = "hello";
secrets.password = "world";
vaultTemplate.write("secret/myapp", secrets);
VaultResponseSupport<Secrets> response = vaultTemplate.read("secret/myapp", Secrets.class);
System.out.println(response.getData().getUsername());
vaultTemplate.delete("secret/myapp");
}
}
即使在这个简单的例子中,也没有什么需要注意的
-
您可以
VaultTemplate
使用org.springframework.vault.client.VaultEndpoint
对象和ClientAuthentication
. 您无需启动 Spring Context 即可使用 Spring Vault。 -
Vault 应配置
00000000-0000-0000-0000-000000000000
为运行此应用程序的根令牌。 -
映射器针对标准 POJO 对象工作,不需要任何额外的元数据(尽管您可以选择提供该信息)。
-
映射约定可以使用字段访问。请注意,
Secrets
该类只有吸气剂。 -
如果构造函数参数名称与存储文档的字段名称匹配,则它们将用于实例化对象。
9. VaultTemplate简介
VaultTemplate
位于 package中的类org.springframework.vault.core
是 Spring 的 Vault 支持的中心类,提供了与 Vault 交互的丰富功能集。该模板提供了在 Vault 中读取、写入和删除数据的便利操作,并提供了域对象和 Vault 数据之间的映射。
配置后,VaultTemplate 它是线程安全的,可以跨多个实例重用。
|
Vault 文档和域类之间的映射是通过委派给
RestTemplate
. Spring Web 支持提供了映射基础设施。
该类VaultTemplate
实现接口VaultOperations
。尽可能地VaultOperations
以 Vault API 上可用的方法命名方法,以使 API 为习惯于 API 和 CLI 的现有 Vault 开发人员所熟悉。例如,您会发现“write”、“delete”、“read”和“revoke”等方法。设计目标是尽可能轻松地在使用 Vault API 和VaultOperations
. 两个 API 之间的一个主要区别是VaultOperations
可以传递域对象而不是 JSON 键值对。
引用实例上的操作的首选方法VaultTemplate 是通过其接口VaultOperations 。
|
虽然有许多方便的方法VaultTemplate
可以帮助您轻松执行常见任务,但如果您需要直接访问 Vault API 以访问未明确公开的功能,VaultTemplate
您可以使用几种执行回调方法之一来访问底层 API。执行回调将为您提供对RestOperations
对象的引用。有关详细信息,请参阅执行回调部分。
现在让我们看一个如何在 Spring 容器的上下文中使用 Vault 的示例。
9.1。注册和配置 Spring Vault bean
使用 Spring Vault 不需要 Spring 上下文。VaultTemplate
但是,在托管上下文中注册的实例SessionManager
将参与
Spring IoC 容器提供的生命周期事件。这对于在应用程序关闭时处理活动的 Vault 会话很有用。您还可以从在您的应用程序中重用相同的VaultTemplate
实例中受益。
Spring Vault 带有一个支持配置类,它提供了在 Spring 上下文中使用的 bean 定义。应用程序配置类通常扩展自AbstractVaultConfiguration
并需要提供特定于环境的其他详细信息。
扩展AbstractVaultConfiguration
需要实现 `VaultEndpoint vaultEndpoint()` 和ClientAuthentication clientAuthentication()
方法。
@Configuration
public class AppConfig extends AbstractVaultConfiguration {
/**
* Specify an endpoint for connecting to Vault.
*/
@Override
public VaultEndpoint vaultEndpoint() {
return new VaultEndpoint(); (1)
}
/**
* Configure a client authentication.
* Please consider a more secure authentication method
* for production use.
*/
@Override
public ClientAuthentication clientAuthentication() {
return new TokenAuthentication("…"); (2)
}
}
1 | 创建一个新VaultEndpoint 的,默认指向https://localhost:8200 。 |
2 | 此示例用于TokenAuthentication 快速入门。有关支持的身份验证方法的详细信息,请参阅身份验证方法。 |
@Configuration
public class AppConfig extends AbstractVaultConfiguration {
@Value("${vault.uri}")
URI vaultUri;
/**
* Specify an endpoint that was injected as URI.
*/
@Override
public VaultEndpoint vaultEndpoint() {
return VaultEndpoint.from(vaultUri); (1)
}
/**
* Configure a Client Certificate authentication.
* {@link RestOperations} can be obtained from {@link #restOperations()}.
*/
@Override
public ClientAuthentication clientAuthentication() {
return new ClientCertificateAuthentication(restOperations()); (2)
}
}
1 | VaultEndpoint 可以使用各种工厂方法构造,例如
from(URI uri) 或VaultEndpoint.create(String host, int port) 。 |
2 | ClientAuthentication 可以从
AbstractVaultConfiguration 您的配置中获取或提供方法的依赖关系。 |
在某些情况下,创建自定义配置类可能很麻烦。看看EnvironmentVaultConfiguration 允许使用来自现有属性源和 Spring 的Environment . 在使用EnvironmentVaultConfiguration 中阅读更多内容。
|
9.2. 会话管理
Spring Vault 需要ClientAuthentication
登录和访问 Vault。有关身份验证的详细信息,请参阅身份验证方法。Vault 登录不应发生在每个经过身份验证的 Vault 交互上,但必须在整个会话中重复使用。此方面由
SessionManager
实现处理。ASessionManager
决定它获得令牌的频率,关于撤销和更新。Spring Vault 带有两个实现:
-
SimpleSessionManager
:仅从提供的令牌中获取令牌,ClientAuthentication
无需刷新和撤销 -
LifecycleAwareSessionManager
:SessionManager
如果令牌可更新并在处置时撤销登录令牌,这会安排令牌更新。续订计划使用AsyncTaskExecutor
.LifecycleAwareSessionManager
如果使用AbstractVaultConfiguration
.
9.3. 使用EnvironmentVaultConfiguration
Spring Vault 包括EnvironmentVaultConfiguration
从 Spring 配置 Vault 客户端Environment
和一组预定义的属性键。EnvironmentVaultConfiguration
支持常用配置。通过从最合适的配置类派生来支持其他配置。包括现有EnvironmentVaultConfiguration
的@Import(EnvironmentVaultConfiguration.class)
基于 Java 的配置类,并通过任何 Spring 的PropertySource
s 提供配置属性。
@PropertySource("vault.properties")
@Import(EnvironmentVaultConfiguration.class)
public class MyConfiguration{
}
vault.uri=https://localhost:8200
vault.token=00000000-0000-0000-0000-000000000000
属性键
-
保险柜 URI:
vault.uri
-
SSL 配置
-
密钥库资源:(
vault.ssl.key-store
可选) -
密钥库密码:(
vault.ssl.key-store-password
可选) -
密钥库类型:(
vault.ssl.key-store-type
可选,通常jks
,也支持pem
) -
信任库资源:(
vault.ssl.trust-store
可选) -
信任库密码:(
vault.ssl.trust-store-password
可选) -
信任库类型:(
vault.ssl.trust-store-type
可选,通常jks
,也支持pem
)
-
-
认证方式:(
vault.authentication
默认为TOKEN
,支持的认证方式有:TOKEN
,APPID
,APPROLE
,AWS_EC2
,AZURE
,CERT
,CUBBYHOLE
,KUBERNETES
)
特定于身份验证的属性键
-
保险柜令牌:
vault.token
-
AppId 路径:(
vault.app-id.app-id-path
默认为app-id
) -
应用编号:
vault.app-id.app-id
-
用户标识:
vault.app-id.user-id
。MAC_ADDRESS
和IP_ADDRESS
使用MacAddressUserId
,各自的IpAddressUserId
用户ID机制。任何其他值都与 一起使用StaticUserId
。
-
AppRole 路径:(
vault.app-role.app-role-path
默认为approle
) -
角色标识:
vault.app-role.role-id
-
SecretId:(
vault.app-role.secret-id
可选)
-
AWS EC2 路径:(
vault.aws-ec2.aws-ec2-path
默认为aws-ec2
) -
角色:
vault.aws-ec2.role
-
RoleId:(
vault.aws-ec2.role-id
已弃用:改用vault.aws-ec2.role
) -
身份证件 URL:(
vault.aws-ec2.identity-document
默认为http://169.254.169.254/latest/dynamic/instance-identity/pkcs7
)
-
Azure MSI 路径:(
vault.azure-msi.azure-path
默认为azure
) -
角色:
vault.azure-msi.role
-
元数据服务 URL:(
vault.azure-msi.metadata-service
默认为http://169.254.169.254/metadata/instance?api-version=2017-08-01
) -
身份令牌服务 URL:(
vault.azure-msi.identity-token-service
默认为http://169.254.169.254/metadata/identity/oauth2/token?resource=https://vault.hashicorp.com&api-version=2018-02-01
)
没有配置选项。
-
初始保险库令牌:
vault.token
-
Kubernetes 路径:(
vault.kubernetes.kubernetes-path
默认为kubernetes
) -
角色:
vault.kubernetes.role
-
服务帐户令牌文件的路径:(
vault.kubernetes.service-account-token-file
默认为/var/run/secrets/kubernetes.io/serviceaccount/token
)
9.4。执行回调
所有 Spring 模板类的一个共同设计特征是所有功能都路由到模板执行回调方法之一。这有助于确保异常和任何可能需要的资源管理执行的一致性。虽然这在 JDBC 和 JMS 的情况下比在 Vault 中更需要,但它仍然为访问和日志记录提供了一个单一的位置。因此,使用执行回调是访问 Vault API 以执行我们未作为方法公开的不常见操作的首选方式VaultTemplate
。
这是执行回调方法的列表。
-
<T> T
doWithVault(RestOperationsCallback<T> callback)
执行给定的 ,允许在不需要会话的情况下RestOperationsCallback
与 Vault 交互。RestOperations
-
<T> T
doWithSession(RestOperationsCallback<T> callback)
执行给定的RestOperationsCallback
,允许在经过身份验证的会话中与 Vault 交互。
下面是一个使用ClientCallback
来初始化 Vault 的示例:
vaultOperations.doWithVault(new RestOperationsCallback<VaultInitializationResponse>() {
@Override
public VaultInitializationResponse doWithRestOperations(RestOperations restOperations) {
ResponseEntity<VaultInitializationResponse> exchange = restOperations
.exchange("/sys/init", HttpMethod.PUT,
new HttpEntity<Object>(request),
VaultInitializationResponse.class);
return exchange.getBody();
}
});
10. 支持Vault的秘密引擎
Spring Vault 附带了几个扩展来支持 Vault 的各种秘密引擎。
具体来说,Spring Vault 附带以下扩展:
-
转换(企业功能)
-
系统后端
VaultTemplate
您可以通过直接 ( VaultTemplate.read(…)
, VaultTemplate.write(…)
)上的方法使用所有其他后端。
10.1。键值版本 1(“未版本化的秘密”)
秘密引擎用于在kv
为 Vault 配置的物理存储中存储任意秘密。
当kv
以非版本化方式运行秘密引擎时,仅保留最近写入的密钥值。非版本化 kv 的好处是减少了每个密钥的存储大小,因为没有存储额外的元数据或历史记录。此外,以这种方式配置的发送到后端的请求性能更高,因为存储调用更少,并且任何给定请求都没有锁定。
Spring Vault 附带一个专用的 Key-Value API 来封装各个 Key-Value API 实现之间的差异。
VaultKeyValueOperations
遵循 Vault CLI 设计。这是 Vault 的主要命令行工具,提供诸如 等vault kv get
命令vault kv put
。
通过指定版本和挂载路径,您可以将此 API 与 Key-Value 引擎版本一起使用。以下示例使用 Key-Value 版本 1:
VaultOperations operations = new VaultTemplate(new VaultEndpoint());
VaultKeyValueOperations keyValueOperations = operations.opsForKeyValue("secret",
VaultKeyValueOperationsSupport.KeyValueBackend.KV_1);
keyValueOperations.put("elvis", Collections.singletonMap("password", "409-52-2002"));
VaultResponse read = keyValueOperations.get("elvis");
read.getRequiredData().get("social-security-number");
VaultKeyValueOperations
支持所有 Key-Value 操作,例如put
, get
, delete
, list
.
或者,由于其直接映射和简单使用,可以通过 APIVaultTemplate
使用,因为键和响应直接映射到输入和输出键。以下示例说明了在 处写入和读取密钥mykey
。秘密kv
引擎安装在secret
:
VaultOperations operations = new VaultTemplate(new VaultEndpoint());
operations.write("secret/elvis", Collections.singletonMap("social-security-number", "409-52-2002"));
VaultResponse read = operations.read("secret/elvis");
read.getRequiredData().get("social-security-number");
您可以在 Vault 参考文档中找到有关Vault Key-Value 版本 1 API的更多详细信息。
10.2. 键值版本 2(“版本化机密”)
您可以kv
在两个版本之一中运行机密引擎。本节介绍如何使用版本 2。运行kv
后端的版本 2 时,密钥可以保留可配置数量的版本。您可以检索旧版本的元数据和数据。此外,您可以使用检查和设置操作来避免无意覆盖数据。
与Key-Value Version 1 (“unversioned secrets”)类似,Spring Vault 附带了一个专用的 Key-Value API 来封装各个 Key-Value API 实现之间的差异。Spring Vault 附带一个专用的 Key-Value API 来封装各个 Key-Value API 实现之间的差异。
VaultKeyValueOperations
遵循 Vault CLI 设计。这是 Vault 的主要命令行工具,提供诸如vault kv get
、等命令vault kv put
。
通过指定版本和挂载路径,您可以将此 API 与 Key-Value 引擎版本一起使用。以下示例使用 Key-Value 版本 2:
VaultOperations operations = new VaultTemplate(new VaultEndpoint());
VaultKeyValueOperations keyValueOperations = operations.opsForKeyValue("secret",
VaultKeyValueOperationsSupport.KeyValueBackend.KV_2);
keyValueOperations.put("elvis", Collections.singletonMap("social-security-number", "409-52-2002"));
VaultResponse read = keyValueOperations.get("elvis");
read.getRequiredData().get("social-security-number");
VaultKeyValueOperations
支持所有 Key-Value 操作,例如put
, get
, delete
, list
.
您还可以与版本化键值 API 的细节进行交互。如果您想获取特定机密或需要访问元数据,这将非常有用。
VaultOperations operations = new VaultTemplate(new VaultEndpoint());
VaultVersionedKeyValueOperations versionedOperations = operations.opsForVersionedKeyValue("secret");
Versioned.Metadata metadata = versionedOperations.put("elvis", (1)
Collections.singletonMap("social-security-number", "409-52-2002"));
Version version = metadata.getVersion(); (2)
Versioned<Object> ssn = versionedOperations.get("elvis", Version.from(42)); (3)
Versioned<SocialSecurityNumber> mappedSsn = versionedOperations.get("elvis", (4)
Version.from(42), SocialSecurityNumber.class);
Versioned<Map<String,String>> versioned = Versioned.create(Collections (5)
.singletonMap("social-security-number", "409-52-2002"),
Version.from(42));
versionedOperations.put("elvis", version);
1 | 将秘密存储在坐骑elvis 下方可用的位置。secret/ |
2 | 将数据存储在版本化后端会返回元数据,例如版本号。 |
3 | 版本化的键值 API 允许检索由版本号标识的特定版本。 |
4 | 版本化的键值秘密可以映射到值对象中。 |
5 | 使用 CAS 更新版本化机密时,输入必须引用先前获得的版本。 |
虽然可以使用kv
v2 机密引擎VaultTemplate
。这不是最方便的方法,因为 API 为上下文路径和输入/输出的表示方式提供了不同的方法。具体来说,与实际秘密的交互需要对数据部分进行包装和解包,并data/
在挂载和秘密密钥之间引入一个路径段。
VaultOperations operations = new VaultTemplate(new VaultEndpoint());
operations.write("secret/data/elvis", Collections.singletonMap("data",
Collections.singletonMap("social-security-number", "409-52-2002")));
VaultResponse read = operations.read("secret/data/ykey");
Map<String,String> data = (Map<String, String>) read.getRequiredData().get("data");
data.get("social-security-number");
您可以在 Vault 参考文档中找到有关Vault Key-Value 版本 2 API的更多详细信息。
10.3. PKI(公钥基础设施)
pki
秘密引擎通过实现证书颁发机构操作来代表证书的后端。
PKI 机密引擎生成动态 X.509 证书。使用这个秘密引擎,服务可以获得证书,而无需通过通常的手动过程来生成私钥和 CSR,提交给 CA,并等待验证和签名过程完成。Vault 的内置身份验证和授权机制提供了验证功能。
Spring Vault 支持通过VaultPkiOperations
. 所有其他 PKI 功能都可以通过VaultOperations
.
以下示例简要说明了如何颁发和撤销证书的使用:
VaultOperations operations = new VaultTemplate(new VaultEndpoint());
VaultPkiOperations pkiOperations = operations.opsForPki("pki");
VaultCertificateRequest request = VaultCertificateRequest.builder() (1)
.ttl(Duration.ofHours(48))
.altNames(Arrays.asList("prod.dc-1.example.com", "prod.dc-2.example.com"))
.withIpSubjectAltName("1.2.3.4")
.commonName("hello.example.com")
.build();
VaultCertificateResponse response = pkiOperations.issueCertificate("production", request); (2)
CertificateBundle certificateBundle = response.getRequiredData();
KeyStore keyStore = certificateBundle.createKeyStore("my-keystore"); (3)
KeySpec privateKey = certificateBundle.getPrivateKeySpec(); (4)
X509Certificate certificate = certificateBundle.getX509Certificate();
X509Certificate caCertificate = certificateBundle.getX509IssuerCertificate();
pkiOperations.revoke(certificateBundle.getSerialNumber()); (5)
1 | 使用构建器构造证书请求VaultCertificateRequest 。 |
2 | 从 Vault 请求证书。Vault 充当证书颁发机构,并使用签名的 X.509 证书进行响应。实际响应是CertificateBundle . |
3 | 您可以直接获取生成的证书作为包含公钥和私钥以及颁发者证书的 Java KeyStore。KeyStore 具有广泛的用途,这使得这种格式适合配置(例如 HTTP 客户端、数据库驱动程序或 SSL 安全的 HTTP 服务器)。 |
4 | CertificateBundle 允许直接通过 Java Cryptography Extension API 访问私钥以及公共证书和颁发者证书。 |
5 | 一旦证书不再使用(或被泄露),您可以通过其序列号撤销它。Vault 在其 CRL 中包含已撤销的证书。 |
您可以在 Vault 参考文档中找到有关Vault PKI 机密 API的更多详细信息。
10.4. 令牌认证后端
token
身份验证方法是内置的,可在/auth/token
. 它允许用户使用令牌进行身份验证,以及创建新令牌、通过令牌撤销机密等。
当任何其他 auth 方法返回一个身份时,Vault 核心调用 token 方法为该身份创建一个新的唯一令牌。
您还可以使用令牌存储绕过任何其他身份验证方法。您可以直接创建令牌,也可以对令牌执行各种其他操作,例如续订和撤销。
Spring Vault 使用这个后端来更新和撤销配置的身份验证方法提供的会话令牌。
以下示例展示了如何在应用程序中请求、更新和撤销 Vault 令牌:
VaultOperations operations = new VaultTemplate(new VaultEndpoint());
VaultTokenOperations tokenOperations = operations.opsForToken();
VaultTokenResponse tokenResponse = tokenOperations.create(); (1)
VaultToken justAToken = tokenResponse.getToken();
VaultTokenRequest tokenRequest = VaultTokenRequest.builder().withPolicy("policy-for-myapp")
.displayName("Access tokens for myapp")
.renewable()
.ttl(Duration.ofHours(1))
.build();
VaultTokenResponse appTokenResponse = tokenOperations.create(tokenRequest); (2)
VaultToken appToken = appTokenResponse.getToken();
tokenOperations.renew(appToken); (3)
tokenOperations.revoke(appToken); (4)
1 | 通过应用角色默认值来创建令牌。 |
2 | 使用构建器 API,您可以为要请求的令牌定义细粒度设置。请求一个令牌会返回一个VaultToken ,它被用作 Vault 令牌的值对象。 |
3 | 您可以通过令牌 API 更新令牌。通常,这是通过SessionManager 跟踪 Vault 会话令牌来完成的。 |
4 | 如果需要,可以通过令牌 API 撤销令牌。通常,这是通过SessionManager 跟踪 Vault 会话令牌来完成的。 |
您可以在 Vault 参考文档中找到有关Vault Token Auth Method API的更多详细信息。
10.5。中转后端
传输机密引擎处理传输中数据的加密功能。Vault 不存储发送到此机密引擎的数据。它也可以被视为“加密即服务”或“加密即服务”。传输秘密引擎还可以对数据进行签名和验证,生成数据的散列和 HMAC,并充当随机字节源。
传输的主要用例是加密来自应用程序的数据,同时仍将加密数据存储在一些主数据存储中。这减轻了应用程序开发人员正确加密和解密的负担,并将负担推到了 Vault 的运营商身上。
Spring Vault 支持广泛的 Transit 操作:
-
密钥创建
-
密钥重新配置
-
加密/解密/重新包装
-
HMAC 计算
-
签名和签名验证
里面的所有操作transit
都以键为中心。Transit 引擎支持密钥的版本控制和多种密钥类型。请注意,密钥类型可能会对可以使用的操作施加限制。
以下示例显示了如何创建密钥以及如何加密和解密数据:
VaultOperations operations = new VaultTemplate(new VaultEndpoint());
VaultTransitOperations transitOperations = operations.opsForTransit("transit");
transitOperations.createKey("my-aes-key", VaultTransitKeyCreationRequest.ofKeyType("aes128-gcm96")); (1)
String ciphertext = transitOperations.encrypt("my-aes-key", "plaintext to encrypt"); (2)
String plaintext = transitOperations.decrypt("my-aes-key", ciphertext); (3)
1 | 首先,我们需要一把钥匙。每个键都需要指定类型。aes128-gcm96 支持加密、解密、密钥推导和收敛加密,本例需要加密和解密。 |
2 | 接下来,我们加密一个String 包含应该加密的纯文本。输入String 使用默认值Charset 将字符串编码为其二进制表示。请求一个令牌会返回一个VaultToken ,它被用作 Vault 令牌的值对象。该encrypt 方法返回 Base64 编码的密文,通常以vault: . |
3 | 要将密文解密为纯文本,请调用该decrypt 方法。它解密密文并返回String 使用默认字符集解码的 a。 |
前面的示例使用简单的字符串进行加密操作。虽然这是一种简单的方法,但它存在字符集配置错误的风险,并且不是二进制安全的。当纯文本对图像、压缩数据或二进制数据结构等数据使用二进制表示时,需要二进制安全。
要加密和解密二进制数据,请使用可以保存二进制值的对象Plaintext
和Ciphertext
值对象:
byte [] plaintext = "plaintext to encrypt".getBytes();
Ciphertext ciphertext = transitOperations.encrypt("my-aes-key", Plaintext.of(plaintext)); (1)
Plaintext decrypttedPlaintext = transitOperations.decrypt("my-aes-key", ciphertext); (2)
1 | 假设密钥my-aes-key 已经到位,我们正在加密Plaintext 对象。作为回报,该encrypt 方法返回一个Ciphertext 对象。 |
2 | 该Ciphertext 对象可以直接用于解密并返回一个Plaintext 对象。 |
Plaintext
并Ciphertext
附带一个上下文对象,VaultTransitContext
. 它用于为收敛加密提供 nonce 值,并为使用密钥派生的上下文值提供。
Transit 允许签署纯文本并验证给定纯文本的签名。签名操作需要非对称密钥,通常使用椭圆曲线密码术或 RSA。
签名使用公钥/私钥拆分来确保真实性。 签名者使用其私钥创建签名。否则,任何人都可以以您的名义签署消息。验证者使用公钥部分来验证签名。实际签名通常是哈希值。 在内部,使用私钥计算和加密哈希以创建最终签名。验证解密签名消息,为纯文本计算自己的哈希,并比较两个哈希值以检查签名是否有效。 |
byte [] plaintext = "plaintext to sign".getBytes();
transitOperations.createKey("my-ed25519-key", VaultTransitKeyCreationRequest.ofKeyType("ed25519")); (1)
Signature signature = transitOperations.sign("my-ed25519-key", Plaintext.of(plaintext)); (2)
boolean valid = transitOperations.verify("my-ed25519-key", Plaintext.of(plaintext), signature); (3)
1 | 签名需要非对称密钥。您可以使用任何椭圆曲线密码术或 RSA 密钥类型。创建密钥后,您就具备了创建签名的所有先决条件。 |
2 | 为纯文本消息创建签名。返回Signature 的内容包含一个使用 Base64 字符的 ASCII 安全字符串。 |
3 | 要验证签名,验证需要一个 Signature 对象和纯文本消息。作为返回值,您可以获得签名是否有效。 |
您可以在 Vault 参考文档中找到有关Vault Transit Backend的更多详细信息。
11. ReactiveVaultTemplate 简介
本节介绍有关使用 Spring Vault 的反应式编程支持的基本信息。
11.1。什么是反应式编程?
简而言之,反应式编程是关于异步和事件驱动的非阻塞应用程序,并且需要少量线程来垂直扩展(即在 JVM 内)而不是水平扩展(即通过集群)。
反应式应用程序的一个关键方面是背压的概念,它是一种确保生产者不会压倒消费者的机制。例如,在从数据库扩展到 HTTP 响应的反应组件管道中,当 HTTP 连接太慢时,数据存储库也可能减慢或完全停止,直到网络容量释放。
11.2. 反应式 Vault 客户端
Spring Vault 的响应式客户端支持建立在可组合的身份验证步骤和 SpringWebClient
通过 Reactor Netty 或 Jetty 的功能之上,它们具有完全非阻塞、事件驱动的 HTTP 客户端。
VaultTokenSupplier
它作为提供者公开VaultToken
以验证 HTTP 请求并ReactiveVaultOperations
作为主要入口点。和SSLVaultEndpoint
的核心配置
在各种客户端实现中重复使用。ClientOptions
ReactiveVaultTemplate
位于 package中的类org.springframework.vault.core
是 Spring 反应式 Vault 支持的中心类,提供了与 Vault 交互的丰富功能集。该模板提供了在 Vault 中读取、写入和删除数据的便利操作,并提供了域对象和 Vault 数据之间的映射。
配置后,ReactiveVaultTemplate 它是线程安全的,可以跨多个实例重用。
|
Vault 文档和域类之间的映射是通过委托
WebClient
及其编解码器完成的。
该类ReactiveVaultTemplate
实现接口ReactiveVaultOperations
。尽可能地ReactiveVaultOperations
以 Vault API 上可用的方法命名方法,以使 API 为习惯于 API 和 CLI 的现有 Vault 开发人员所熟悉。例如,您会发现诸如“写入”、“删除”和“读取”之类的方法。设计目标是尽可能轻松地在使用 Vault API 和ReactiveVaultOperations
. 两个 API 之间的一个主要区别是ReactiveVaultOperations
可以传递域对象而不是 JSON 键值对。
引用实例上的操作的首选方法ReactiveVaultTemplate 是通过其接口ReactiveVaultOperations 。
|
ReactiveVaultTemplate
您可以使用几种执行回调方法之一来访问底层 API未明确公开的功能。执行回调将为您提供对WebClient
对象的引用。有关详细信息,请参阅执行回调部分。
现在让我们看一个如何在 Spring 容器的上下文中使用 Vault 的示例。
11.3. 注册和配置 Spring Vault bean
使用 Spring Vault 不需要 Spring 上下文。ReactiveVaultTemplate
但是,在托管上下文中注册的实例
VaultTokenSupplier
将参与
Spring IoC 容器提供的生命周期事件。这对于在应用程序关闭时处理活动的 Vault 会话很有用。您还可以从在您的应用程序中重用相同的ReactiveVaultTemplate
实例中受益。
Spring Vault 带有一个支持配置类,它提供了在 Spring 上下文中使用的 bean 定义。应用程序配置类通常扩展自AbstractVaultConfiguration
并需要提供特定于环境的其他详细信息。
扩展AbstractVaultConfiguration
需要实现 `VaultEndpoint vaultEndpoint()` 和ClientAuthentication clientAuthentication()
方法。
@Configuration
public class AppConfig extends AbstractReactiveVaultConfiguration {
/**
* Specify an endpoint for connecting to Vault.
*/
@Override
public VaultEndpoint vaultEndpoint() {
return new VaultEndpoint(); (1)
}
/**
* Configure a client authentication.
* Please consider a more secure authentication method
* for production use.
*/
@Override
public ClientAuthentication clientAuthentication() {
return new TokenAuthentication("…"); (2)
}
}
1 | 创建一个新VaultEndpoint 的,默认指向https://localhost:8200 。 |
2 | 此示例用于TokenAuthentication 快速入门。有关支持的身份验证方法的详细信息,请参阅身份验证方法。 |
11.5。执行回调
所有 Spring 模板类的一个共同设计特征是所有功能都路由到模板执行回调方法之一。这有助于确保异常和任何可能需要的资源管理执行的一致性。虽然这在 JDBC 和 JMS 的情况下比在 Vault 中更需要,但它仍然为访问和日志记录提供了一个单一的位置。因此,使用执行回调是访问 Vault API 以执行我们未作为方法公开的不常见操作的首选方式ReactiveVaultTemplate
。
这是执行回调方法的列表。
-
<T> T
doWithVault(Function<WebClient, ? extends T> clientCallback)
组成一个给定的反应序列WebClient
,允许在没有会话上下文的情况下与 Vault 交互。 -
<T> T
doWithSession(Function<WebClient, ? extends T> clientCallback)
组成一个给定的反应序列WebClient
,允许在经过身份验证的会话中与 Vault 交互。
这是一个使用回调初始化 Vault 的示例:
reactiveVaultOperations.doWithVault(webClient -> {
return webClient.put()
.uri("/sys/init")
.syncBody(request)
.retrieve()
.toEntity(VaultInitializationResponse.class);
});
12. Vault 属性源支持
保险柜可以以多种不同的方式使用。一个特定的用例是使用 Vault 来存储加密的属性。Spring Vault 支持 Vault 作为属性源,使用 Spring 的PropertySource 抽象来获取配置属性。
您可以在其他属性源中引用存储在 Vault 中的属性,或将值注入与@Value(…) . 在引导需要存储在 Vault 中的数据的 bean 时需要特别注意。AVaultPropertySource 必须在那时初始化才能从 Vault 中检索属性。
|
Spring Boot/Spring Cloud 用户可以受益于Spring Cloud Vault的配置集成,该集成在应用程序启动期间初始化各种属性源。 |
12.1. 注册VaultPropertySource
Spring Vault 提供了一个VaultPropertySource
与 Vault 一起使用来获取属性的方法。它使用嵌套data
元素来公开在 Vault 中存储和加密的属性。
ConfigurableApplicationContext ctx = new GenericApplicationContext();
MutablePropertySources sources = ctx.getEnvironment().getPropertySources();
sources.addFirst(new VaultPropertySource(vaultTemplate, "secret/my-application"));
在上面的代码中,VaultPropertySource
已在搜索中以最高优先级添加。如果它包含一个 'foo' 属性,它将foo
在任何 other 中的任何属性之前被检测并返回PropertySource
。
MutablePropertySources
公开了许多允许精确操作属性源集的方法。
12.2. @VaultPropertySource
@VaultPropertySource
注解提供了一种方便且声明性的机制,用于将 a 添加到PropertySource
SpringEnvironment
以与@Configuration
类一起使用。
@VaultPropertySource
采用 Vault 路径,例如secret/my-application
并公开存储在PropertySource
.
@VaultPropertySource
支持与租约相关的秘密的租约更新(即来自mysql
后端的凭据)和终端租约到期时的凭据轮换。默认情况下禁用续租。
{
// …
"data": {
"database": {
"password": ...
},
"user.name": ...,
}
// …
}
@VaultPropertySource
@Configuration
@VaultPropertySource("secret/my-application")
public class AppConfig {
@Autowired Environment env;
@Bean
public TestBean testBean() {
TestBean testBean = new TestBean();
testBean.setUser(env.getProperty("user.name"));
testBean.setPassword(env.getProperty("database.password"));
return testBean;
}
}
@VaultPropertySource
使用凭证轮换和前缀声明 a@Configuration
@VaultPropertySource(value = "aws/creds/s3-access",
propertyNamePrefix = "aws.",
renewal = Renewal.ROTATE)
public class AppConfig {
// provides aws.access_key and aws.secret_key properties
}
从generic 秘密后端获得的秘密与 TTL ( refresh_interval ) 相关联,但与租约 ID 无关。Spring VaultPropertySource 在达到其 TTL 时会轮换通用机密。
|
您可以使用@VaultPropertySource 从版本化的 Key-Value 后端获取最新的密钥版本。确保不在data/ 路径中包含该段。
|
路径中存在的任何${…}
占位符都会@VaultPropertySource
根据已针对环境注册的属性源集进行解析,如以下示例所示:
@VaultPropertySource
路径@Configuration
@VaultPropertySource(value = "aws/creds/${my.placeholder:fallback/value}",
propertyNamePrefix = "aws.",
renewal = Renewal.ROTATE)
public class AppConfig {
}
假设my.placeholder
存在于已注册的属性源之一(例如,系统属性或环境变量)中,则占位符被解析为相应的值。如果不是,则将fallback/value
其用作默认值。如果未指定默认值且无法解析属性,IllegalArgumentException
则抛出 an。
@VaultPropertySource
在某些情况下,在使用注释时严格控制属性源排序可能是不可能或不切实际的。例如,如果@Configuration
上面的类是通过组件扫描注册的,那么很难预测排序。在这种情况下 - 如果覆盖很重要 - 建议用户回退到使用程序化 PropertySource API。有关详细信息,请参见ConfigurableEnvironment
和
MutablePropertySources
。
13. 保险库存储库
使用VaultTemplate
和映射到 Java 类的响应允许基本的数据操作,如读取、写入和删除。Vault 存储库在 Vault 之上应用 Spring Data 的存储库概念。Vault 存储库公开了基本的 CRUD 功能,并支持使用限制 Id 属性、分页和排序的谓词进行查询派生。
在Spring Data Commons 参考文档 中阅读有关 Spring Data Repositories 的更多信息。参考文档将向您介绍 Spring Data 存储库。 |
13.1. 用法
要访问存储在 Vault 中的域实体,您可以利用存储库支持来显着简化实施这些实体。
@Secret
public class Credentials {
@Id String id;
String password;
String socialSecurityNumber;
Address address;
}
我们这里有一个非常简单的域对象。请注意,它有一个名为id
annotated with
的属性org.springframework.data.annotation.Id
和一个@Secret
关于其类型的注释。这两个负责创建用于将对象作为 JSON 保存在 Vault 中的实际密钥。
带有注释的属性@Id 以及命名id 的属性被视为标识符属性。带有注释的人比其他人更受青睐。
|
下一步是声明一个使用域对象的存储库接口。
Credentials
示例 15.实体的基本存储库接口public interface CredentialsRepository extends CrudRepository<Credentials, String> {
}
随着我们的存储库的扩展CrudRepository
,它提供了基本的 CRUD 和查询方法。Vault 存储库需要 Spring Data 组件。确保在您的类路径中包含spring-data-commons
和工件。spring-data-keyvalue
实现这一点的最简单方法是设置依赖管理并将工件添加到您的pom.xml
:
然后将以下内容添加到pom.xml
依赖项部分。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-bom</artifactId>
<version>2020.0.2</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- other dependency elements omitted -->
<dependency>
<groupId>org.springframework.vault</groupId>
<artifactId>spring-vault-core</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-keyvalue</artifactId>
<!-- Version inherited from the BOM -->
</dependency>
</dependencies>
我们需要将它们粘合在一起的东西是相应的 Spring 配置。
@Configuration
@EnableVaultRepositories
public class ApplicationConfig {
@Bean
public VaultTemplate vaultTemplate() {
return new VaultTemplate(…);
}
}
鉴于上面的设置,我们可以继续并注入CredentialsRepository
到我们的组件中。
@Autowired CredentialsRepository repo;
public void basicCrudOperations() {
Credentials creds = new Credentials("heisenberg", "327215", "AAA-GG-SSSS");
rand.setAddress(new Address("308 Negra Arroyo Lane", "Albuquerque", "New Mexico", "87104"));
repo.save(creds); (1)
repo.findOne(creds.getId()); (2)
repo.count(); (3)
repo.delete(creds); (4)
}
1 | Credentials 使用密钥模式存储 Vault Hash 内部的属性keyspace/id ,在这种情况下credentials/heisenberg ,存储在通用机密后端中。 |
2 | 使用提供的 id 来检索存储在的对象keyspace/id 。 |
3 | 计算on定义的密钥空间凭据中可用的实体总数。@Secret Credentials |
4 | 从 Vault 中删除给定对象的键。 |
13.2. 对象到 Vault JSON 映射
Vault 存储库使用 JSON 作为交换格式将对象存储在 Vault 中。JSON 和实体之间的对象映射由VaultConverter
. 转换器读取和写入SecretDocument
包含来自VaultResponse
. VaultResponse
s 从 Vault 中读取,Jackson 将主体反序列化为Map
ofString
和Object
。默认VaultConverter
实现读取Map
具有嵌套值List
和Map
对象并将它们转换为实体,反之亦然。
给定Credentials
前几节的类型,默认映射如下:
{
"_class": "org.example.Credentials", (1)
"password", "327215", (2)
"socialSecurityNumber": "AAA-GG-SSSS",
"address": { (3)
"street": "308 Negra Arroyo Lane",
"city": "Albuquerque",
"state": "New Mexico",
"zip":"87104"
}
}
1 | 该_class 属性包含在根级别以及任何嵌套接口或抽象类型上。 |
2 | 简单属性值按路径映射。 |
3 | 复杂类型的属性映射为嵌套对象。 |
该@Id 属性必须映射到String 。
|
类型 | 样本 | 映射值 |
---|---|---|
简单类型 |
字符串名字 = "沃尔特"; |
名字=“沃尔特” |
复杂类型 |
地址 address = new Address("308 Negra Arroyo Lane"); |
地址:{“街道”:“内格拉阿罗约巷 308 号”} |
|
List<String> 昵称 = asList("walt", "heisenberg"); |
昵称:[“沃尔特”、“海森堡”] |
|
Map<String, Integer> atts = asMap("age", 51) |
atts:{“年龄”:51} |
|
List<Address> 地址 = asList(new Address("308… |
地址:[{“街道”:“内格拉阿罗约巷 308 号”},…] |
Converter
您可以通过注册一个in来自定义映射行为VaultCustomConversions
。这些转换器可以处理从/到类型的转换,例如,LocalDate
而SecretDocument
第一个适用于将简单属性和最后一个复杂类型转换为其 JSON 表示。第二个选项提供对结果的完全控制SecretDocument
。写入对象Vault
将删除内容并重新创建整个条目,因此未映射的数据将丢失。
13.3. 查询和查询方法
查询方法允许从方法名称自动派生简单查询。Vault 没有查询引擎,但需要直接访问 HTTP 上下文路径。Vault 查询方法将 Vault 的 API 可能性转换为查询。查询方法执行列出上下文路径下的子项,对 Id 应用过滤,可选择使用偏移量/限制限制 Id 流,并在获取结果后应用排序。
public interface CredentialsRepository extends CrudRepository<Credentials, String> {
List<Credentials> findByIdStartsWith(String prefix);
}
Vault 存储库的查询方法仅支持对@Id 属性进行谓词的查询。
|
以下是保险柜支持的关键字的概述。
关键词 | 样本 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13.3.1. 排序和分页
查询方法通过在内存中选择从 Vault 上下文路径中检索的子列表(偏移量/限制)ID 来支持排序和分页。与查询方法谓词不同,排序不限于特定字段。在 Id 过滤后应用未分页排序,并且所有生成的秘密都从 Vault 中获取。这样,查询方法只获取也作为结果的一部分返回的结果。
使用分页和排序需要在过滤影响性能的 Id 之前进行秘密提取。即使 Vault 返回的 Id 的自然顺序发生变化,排序和分页也保证返回相同的结果。因此,首先从 Vault 中获取所有 Id,然后应用排序,然后进行过滤和偏移/限制。
public interface CredentialsRepository extends PagingAndSortingRepository<Credentials, String> {
List<Credentials> findTop10ByIdStartsWithOrderBySocialSecurityNumberDesc(String prefix);
List<Credentials> findByIdStarts(String prefix, Pageable pageRequest);
}
14. 客户支持
Spring Vault 支持各种 HTTP 客户端访问 Vault 的 HTTP API。Spring Vault
RestTemplate
用作访问 Vault 的主要接口。专用客户端支持源自自定义 SSL 配置
,该配置仅适用于 Spring Vault 的客户端组件。
Spring Vault 支持以下 HTTP 命令式客户端:
-
Java 的内置
HttpURLConnection
(默认客户端) -
Apache Http 组件
-
网状
-
OkHttp 3
Spring Vault 的响应式集成支持以下响应式 HTTP 客户端:
-
反应堆网
-
码头
使用特定客户端需要在类路径上提供相应的依赖项,以便 Spring Vault 可以使用可用客户端与 Vault 进行通信。
14.1. Java的内置HttpURLConnection
Java 的内置HttpURLConnection
功能是开箱即用的,无需额外配置。使用HttpURLConnection
带有关于 SSL 配置的限制。Spring Vault 不会应用定制的 SSL 配置,因为它需要对 JVM 进行深度重新配置。此配置将影响依赖默认 SSL 上下文的所有组件。使用配置 SSL 设置
HttpURLConnection
需要您将这些设置作为系统属性提供。有关详细信息,请参阅
自定义 JSSE。
14.2. 外部客户
您可以使用外部客户端访问 Vault 的 API。只需将以下依赖项之一添加到您的项目中。如果使用 Spring Vault 的 Dependency BOM ,则可以省略版本号
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
可以通过日志配置启用 Apache HttpClient 的有线日志记录。确保不要意外启用线路日志记录,因为日志可能会以纯文本形式公开您的应用程序和 Vault 之间的流量(令牌和机密)。 |
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor.netty</groupId>
<artifactId>reactor-netty</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-reactive-httpclient</artifactId>
</dependency>
14.3. Vault 客户端 SSL 配置
可以SslConfiguration
通过设置各种属性来配置 SSL。您可以设置javax.net.ssl.trustStore
为配置 JVM 范围的 SSL 设置或配置SslConfiguration
为仅为 Spring Vault 设置 SSL 设置。
SslConfiguration sslConfiguration = SslConfiguration.create( (1)
new FileSystemResource("client-cert.jks"), "changeit".toCharArray(),
new FileSystemResource("truststore.jks"), "changeit".toCharArray());
SslConfiguration.forTrustStore(new FileSystemResource("keystore.jks"), (2)
"changeit".toCharArray())
SslConfiguration.forKeyStore(new FileSystemResource("keystore.jks"), (3)
"changeit".toCharArray())
SslConfiguration.forKeyStore(new FileSystemResource("keystore.jks"), (4)
"changeit".toCharArray(),
KeyConfiguration.of("key-password".toCharArray(),
"my-key-alias"))
1 | 完整配置。 |
2 | 仅配置信任存储设置。 |
3 | 仅配置密钥存储设置。 |
4 | 通过提供密钥配置仅配置密钥存储设置。 |
请注意,SslConfiguration
仅当 Apache Http 组件或 OkHttp 客户端位于您的类路径上时,才能应用提供。
SSL 配置还支持 PEM 编码证书作为 Java Key Store 的替代方案。
KeyStoreConfiguration keystore = KeyStoreConfiguration
.of(new ClassPathResource("ca.pem")).withStoreType("PEM");
SslConfiguration configuration = SslConfiguration.forTrustStore(keystore);
PEM 文件可能包含一个或多个证书(-----BEGIN CERTIFICATE-----
和的块-----END CERTIFICATE-----
)。添加到底层的证书KeyStore
使用完整的主题名称作为别名。
15. 认证方法
不同的组织对安全性和身份验证有不同的要求。Vault 通过提供多种身份验证方法来反映这种需求。Spring Vault 支持多种身份验证机制。
15.1. 外部化登录凭据
获得对安全系统的首次访问称为安全引入。任何客户端都需要临时或永久凭据才能访问 Vault。外部化凭证是保持代码可维护性高的一种很好的模式,但存在增加披露的风险。
向任何一方披露登录凭据允许登录到 Vault 并访问底层角色允许的机密。选择适当的客户端身份验证并将凭据注入应用程序需要进行风险评估。
Spring 的PropertySource 抽象非常适合将配置保留在应用程序代码之外。您可以使用系统属性、环境变量或属性文件来存储登录凭据。每种方法都有自己的属性。请记住,命令行和环境属性可以通过适当的操作系统访问级别进行自省。
vault.token
到属性文件@PropertySource("configuration.properties")
@Configuration
public class Config extends AbstractVaultConfiguration {
@Override
public ClientAuthentication clientAuthentication() {
return new TokenAuthentication(getEnvironment().getProperty("vault.token"));
}
}
Spring 允许多种方式获取Environment . 使用时VaultPropertySource ,注入 via@Autowired Environment environment 将不会提供,Environment 因为环境 bean 仍在构建中,并且自动装配在稍后阶段进行。您的配置类应该实现ApplicationContextAware 并获取Environment from ApplicationContext 。
|
SecurePropertyUsage.java
有关在组件和其他属性源中引用属性的示例,请参阅。
15.2. 令牌认证
令牌是 Vault 中进行身份验证的核心方法。令牌身份验证需要提供静态令牌。
令牌认证是默认的认证方法。如果令牌被意外泄露,它可以访问 Vault 并可以访问预期客户的机密。 |
通常,令牌身份验证用于令牌在外部创建和更新的场景(例如HashiCorp Vault 服务代理)。根据实际设置,您可能需要也可能不需要令牌更新和撤销。LifecycleAwareSessionManager
有关 TTL 和令牌撤销的详细信息,请参阅。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
return new TokenAuthentication("…");
}
// …
}
也可以看看:
15.3. AppId 认证
Vault 不推荐使用 AppId 身份验证。请改用AppRole 身份验证。 |
Vault 支持
由两个难以猜测的令牌组成的AppId身份验证。AppId 默认spring.application.name
为静态配置。第二个标记是 UserId,它是由应用程序确定的部分,通常与运行时环境有关。IP 地址、Mac 地址或 Docker 容器名称都是很好的例子。Spring Vault 支持 IP 地址、Mac 地址和静态 UserId(例如通过系统属性提供)。IP 和 Mac 地址表示为十六进制编码的 SHA256 哈希。
基于 IP 地址的 UserId 使用本地主机的 IP 地址。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
AppIdAuthenticationOptions options = AppIdAuthenticationOptions.builder()
.appId("myapp")
.userIdMechanism(new IpAddressUserId())
.build();
return new AppIdAuthentication(options, restOperations());
}
// …
}
从命令行生成 IP 地址 UserId 的相应命令是:
$回声-n 192.168.99.1 | sha256sum
包含导致不同哈希值的换行符,echo 因此请确保包含-n 标志。
|
基于 Mac 地址的 UserId 从本地主机绑定设备获取他们的网络设备。该配置还允许指定network-interface
提示以选择正确的设备。的值
network-interface
是可选的,可以是接口名称或接口索引(从 0 开始)。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
AppIdAuthenticationOptions options = AppIdAuthenticationOptions.builder()
.appId("myapp")
.userIdMechanism(new MacAddressUserId())
.build();
return new AppIdAuthentication(options, restOperations());
}
// …
}
从命令行生成 Mac 地址 UserId 的相应命令是:
$回声-n 0AFEDE1234AC | sha256sum
Mac 地址指定为大写且不带冒号。包含导致不同哈希值的换行符,echo 因此请确保包含-n 标志。
|
15.3.1. 自定义用户 ID
更高级的方法可以让您实现自己的AppIdUserIdMechanism
. 此类必须在您的类路径中,并且必须实现org.springframework.vault.authentication.AppIdUserIdMechanism
接口和createUserId
方法。Spring VaultcreateUserId
每次使用 AppId 进行身份验证时都会调用来获取 UserId 以获取令牌。
public class MyUserIdMechanism implements AppIdUserIdMechanism {
@Override
public String createUserId() {
String userId = …
return userId;
}
}
15.4. 应用角色认证
AppRole允许机器身份验证,例如已弃用(自 Vault 0.6.1 起)的AppId authentication。AppRole 身份验证由两个难以猜测的(秘密)令牌组成:RoleId 和 SecretId。
Spring Vault 通过仅提供 RoleId 或与提供的 SecretId 一起提供并从 Vault 获取 RoleId/SecretId 来支持 AppRole 身份验证(具有响应展开的推送和拉取模式)。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
AppRoleAuthenticationOptions options = AppRoleAuthenticationOptions.builder()
.roleId(RoleId.provided("…"))
.secretId(SecretId.wrapped(VaultToken.of("…")))
.build();
return new AppRoleAuthentication(options, restOperations());
}
// …
}
Spring Vault 还支持完全拉取模式:如果没有提供 RoleId 和 SecretId,Spring Vault 将使用角色名称和初始令牌检索它们。初始令牌可能与 TTL 和使用限制相关联。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
VaultToken initialToken = VaultToken.of("…");
AppRoleAuthenticationOptions options = AppRoleAuthenticationOptions.builder()
.appRole("…")
.roleId(RoleId.pull(initialToken))
.secretId(SecretId.pull(initialToken))
.build();
return new AppRoleAuthentication(options, restOperations());
}
// …
}
15.5。AWS-EC2 身份验证
aws-ec2 auth 后端为 AWS EC2 实例提供安全的 引入机制,允许自动检索 Vault 令牌。与大多数 Vault 身份验证后端不同,此后端不需要首先部署或提供对安全敏感的凭据(令牌、用户名/密码、客户端证书等)。相反,它将 AWS 视为受信任的第三方,并使用唯一代表每个 EC2 实例的加密签名动态元数据信息。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
return new AwsEc2Authentication(restOperations());
}
// …
}
AWS-EC2 身份验证默认启用随机数以遵循首次使用信任 (TOFU) 原则。任何获得 PKCS#7 身份元数据访问权限的非预期方都可以针对 Vault 进行身份验证。
在第一次登录期间,Spring Vault 会生成一个 nonce,该 nonce 存储在 auth 后端的实例 ID 旁边。重新认证需要发送相同的随机数。任何其他方都没有随机数,可以在 Vault 中发出警报以进行进一步调查。
nonce 保存在内存中,并在应用程序重新启动期间丢失。
AWS-EC2 身份验证角色是可选的,默认为 AMI。您可以通过在 中设置身份验证角色来配置身份验证角色AwsEc2AuthenticationOptions
。
15.6。AWS-IAM 身份验证
aws auth 后端允许使用 现有 AWS IAM 凭证登录 Vault。
AWS IAM 身份验证创建一个签名的 HTTP 请求,由 Vault 执行以使用 AWS STS
GetCallerIdentity
方法获取签名者的身份。AWSv4 签名需要 IAM 凭证。
IAM 凭证可以从运行时环境中获取,也可以从外部提供。运行时环境(如 AWS-EC2、Lambda 和 ECS)具有分配的 IAM 委托人不需要特定于客户端的凭证配置,但可以从其元数据源获取这些。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
AwsIamAuthenticationOptions options = AwsIamAuthenticationOptions.builder()
.credentials(new BasicAWSCredentials(…)).build();
return new AwsIamAuthentication(options, restOperations());
}
// …
}
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
AwsIamAuthenticationOptions options = AwsIamAuthenticationOptions.builder()
.credentialsProvider(InstanceProfileCredentialsProvider.getInstance()).build();
return new AwsIamAuthentication(options, restOperations());
}
// …
}
AwsIamAuthentication
需要 AWS Java 开发工具包依赖项 ( com.amazonaws:aws-java-sdk-core
),因为身份验证实施使用 AWS 开发工具包类型进行凭证和请求签名。
您可以通过 配置身份验证AwsIamAuthenticationOptions
。
也可以看看:
15.7. Azure (MSI) 身份验证
azure auth 后端为 Azure VM 实例提供了一种安全的 引入机制,允许自动检索 Vault 令牌。与大多数 Vault 身份验证后端不同,此后端不需要首先部署或提供对安全敏感的凭据(令牌、用户名/密码、客户端证书等)。相反,它将 Azure 视为受信任的第三方,并使用可绑定到 VM 实例的托管服务标识和实例元数据信息。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
AzureMsiAuthenticationOptions options = AzureMsiAuthenticationOptions.builder()
.role(…).build();
return new AzureMsiAuthentication(options, restOperations());
}
// …
}
Azure 身份验证需要有关 VM 环境的详细信息(订阅 ID、资源组名称、VM 名称)。这些详细信息可以通过配置
AzureMsiAuthenticationOptionsBuilder
。如果未配置,则AzureMsiAuthentication
查询 Azure 的实例元数据服务以获取这些详细信息。
也可以看看:
15.8. GCP-GCE 认证
gcp auth 后端允许使用现有的 GCP(谷歌云平台)IAM 和 GCE 凭证登录保险柜。
GCP GCE(Google Compute Engine)身份验证以 JSON Web Token (JWT) 的形式为服务帐户创建签名。Compute Engine 实例的 JWT 是使用Instance Identification从 GCE 元数据服务获取的。此 API 创建可用于确认实例身份的 JSON Web 令牌。
与大多数 Vault 身份验证后端不同,此后端不需要首先部署或提供对安全敏感的凭据(令牌、用户名/密码、客户端证书等)。相反,它将 GCP 视为受信任的第三方,并使用唯一代表每个 GCP 服务帐户的加密签名动态元数据信息。
您可以通过 配置身份验证GcpComputeAuthenticationOptions
。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
GcpComputeAuthenticationOptions options = GcpComputeAuthenticationOptions.builder()
.role(…).build();
GcpComputeAuthentication authentication = new GcpComputeAuthentication(options,
restOperations());
}
// …
}
也可以看看:
15.9。GCP-IAM 身份验证
gcp auth 后端允许使用现有的 GCP(谷歌云平台)IAM 和 GCE 凭证登录保险柜。
GCP IAM 身份验证以 JSON Web 令牌 (JWT) 的形式为服务帐户创建签名。服务账户的 JWT 是通过调用 GCP IAM 的projects.serviceAccounts.signJwt
API 获得的。调用者针对 GCP IAM 进行身份验证并由此证明其身份。此保险柜后端将 GCP 视为受信任的第三方。
IAM 凭证可以从运行时环境中获得,也可以从外部以 JSON 等形式提供。JSON 是首选格式,因为它携带调用所需的项目 ID 和服务帐户标识符
projects.serviceAccounts.signJwt
。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
GcpIamAuthenticationOptions options = GcpIamAuthenticationOptions.builder()
.role(…).credential(GoogleCredentials.getApplicationDefault()).build();
GcpIamAuthentication authentication = new GcpIamAuthentication(options,
restOperations());
}
// …
}
GcpIamAuthenticationOptions
需要 Google Cloud Java SDK 依赖项 (com.google.apis:google-api-services-iam
和com.google.auth:google-auth-library-oauth2-http
),因为身份验证实现使用 Google API 进行凭据和 JWT 签名。
您可以通过 配置身份验证GcpIamAuthenticationOptions
。
Google 凭据需要维护令牌生命周期的 OAuth 2 令牌。因此,所有 API 都是同步的,GcpIamAuthentication 不支持AuthenticationSteps 响应式使用所需的 API。
|
也可以看看:
15.10。PCF认证
pcf auth 后端允许 PCF 实例的 Vault 登录。它利用了 PCF 的应用程序和容器身份保证。
PCF 身份验证使用实例密钥和证书来创建由 Vault 验证的签名。如果签名匹配,并且可能绑定的组织/空间/应用程序 ID 匹配,则 Vault 会发出一个适当范围的令牌。
实例凭证可从文件 atCF_INSTANCE_CERT
和
CF_INSTANCE_KEY
variables 中获得。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
PcfAuthenticationOptions options = PcfAuthenticationOptions.builder()
.role(…).build();
PcfAuthentication authentication = new PcfAuthentication(options,
restOperations());
}
// …
}
PcfAuthenticationOptions
需要BouncyCastle
库来创建 RSA-PSS 签名。
您可以通过 配置身份验证PcfAuthenticationOptions
。
也可以看看:
15.11。TLS证书认证
cert
auth 后端允许使用由 CA 签名或自签名的 SSL/TLS 客户端证书进行身份验证。
要启用cert
身份验证,您需要:
-
使用 SSL,请参阅Vault 客户端 SSL 配置
-
配置
Keystore
包含客户端证书和私钥的 Java
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
ClientCertificateAuthenticationOptions options = ClientCertificateAuthenticationOptions.builder()
.path(…).build();
return new ClientCertificateAuthentication(options, restOperations());
}
// …
}
15.12。Cubbyhole 身份验证
Cubbyhole 身份验证使用 Vault 原语来提供安全的身份验证工作流程。Cubbyhole 身份验证使用令牌作为主要登录方法。临时令牌用于从 Vault 的 Cubbyhole 秘密后端获取第二个登录 VaultToken。登录令牌通常寿命较长,用于与 Vault 交互。可以从包装的响应或data
部分中检索登录令牌。
创建一个包装的令牌
用于创建令牌的响应包装需要 Vault 0.6.0 或更高版本。 |
$ vault token-create -wrap-ttl="10m"
Key Value
--- -----
wrapping_token: 397ccb93-ff6c-b17b-9389-380b01ca2645
wrapping_token_ttl: 0h10m0s
wrapping_token_creation_time: 2016-09-18 20:29:48.652957077 +0200 CEST
wrapped_accessor: 46b6aebb-187f-932a-26d7-4f3d86a68319
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
CubbyholeAuthenticationOptions options = CubbyholeAuthenticationOptions
.builder()
.initialToken(VaultToken.of("…"))
.wrapped()
.build();
return new CubbyholeAuthentication(options, restOperations());
}
// …
}
使用存储的令牌
$ vault token create
Key Value
--- -----
token f9e30681-d46a-cdaf-aaa0-2ae0a9ad0819
token_accessor 4eee9bd9-81bb-06d6-af01-723c54a72148
token_duration 0s
token_renewable false
token_policies [root]
$ vault token create -use-limit=2 -orphan -no-default-policy -policy=none
Key Value
--- -----
token 895cb88b-aef4-0e33-ba65-d50007290780
token_accessor e84b661c-8aa8-2286-b788-f258f30c8325
token_duration 0s
token_renewable false
token_policies [none]
$ export VAULT_TOKEN=895cb88b-aef4-0e33-ba65-d50007290780
$ vault write cubbyhole/token token=f9e30681-d46a-cdaf-aaa0-2ae0a9ad0819
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
CubbyholeAuthenticationOptions options = CubbyholeAuthenticationOptions
.builder()
.initialToken(VaultToken.of("…"))
.path("cubbyhole/token")
.build();
return new CubbyholeAuthentication(options, restOperations());
}
// …
}
剩余 TTL/可再生性
从 Cubbyhole 检索到的与非零 TTL 相关联的令牌在创建令牌时开始其 TTL。该时间不一定与应用程序启动相同。为了补偿初始延迟,Cubbyhole 身份验证对与非零 TTL 关联的令牌执行自我查找,以检索剩余的 TTL。Cubbyhole 身份验证不会在没有 TTL 的情况下自行查找包装的令牌,因为零 TTL 表示没有关联的 TTL。
未包装的令牌不通过仅检索令牌来提供有关可更新性和 TTL 的详细信息。自查找将查找可更新性和剩余的 TTL。
也可以看看:
15.13。Kubernetes 身份验证
自 0.8.3 起,Vault 支持使用 Kubernetes 令牌的基于 kubernetes 的身份验证。
使用 Kubernetes 身份验证需要一个 Kubernetes 服务帐户令牌,通常安装在/var/run/secrets/kubernetes.io/serviceaccount/token
. 该文件包含读取并发送到 Vault 的令牌。Vault 在登录期间使用 Kubernetes 的 API 验证其有效性。
配置 Kubernetes 身份验证至少需要提供角色名称:
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
KubernetesAuthenticationOptions options = KubernetesAuthenticationOptions.builder()
.role(…).jwtSupplier(…).build();
return new KubernetesAuthentication(options, restOperations());
}
// …
}
您可以通过 配置身份验证KubernetesAuthenticationOptions
。
也可以看看:
15.14。认证步骤
ClientAuthentication
对象描述身份验证流程并执行实际的身份验证步骤。预先组合的身份验证易于使用,并且可以通过与同步执行的紧密绑定进行配置。
身份验证方法的组合和重用常见步骤(例如将登录有效负载发布到 Vault 或从 HTTP 源检索身份验证输入)不适用于ClientAuthentication
对象。
身份验证步骤提供了常见身份验证活动的可重用性。通过以功能样式描述身份验证流程创建的步骤AuthenticationSteps
将实际身份验证执行留给特定的执行者。
AuthenticationSteps.just(VaultToken.of(…)); (1)
1 | 仅从. AuthenticationSteps _VaultToken |
可以从单个输入创建单步身份验证流程。声明多个身份验证步骤的流程以Supplier
或HttpRequest
提供身份验证状态对象开头,该对象可用于映射或发布到 Vault 以进行登录。
AuthenticationSteps.fromSupplier( (1)
() -> getAppRoleLogin(options.getRoleId(), options.getSecretId())) (2)
.login("auth/{mount}/login", options.getPath()); (3)
1 | 开始声明AuthenticationSteps 接受一个Supplier<T> . 状态对象类型取决于Supplier 可以在后续步骤中映射的响应类型。 |
2 | 实际Supplier 执行。Map 在这种情况下创建一个。 |
3 | 通过将状态对象 ( Map ) 发布到 Vault 端点以创建 Vault 令牌来执行 Vault 登录。请注意,模板变量会受到 URL 转义的影响。 |
身份验证流程需要执行程序来执行实际登录。我们为不同的执行模型提供了两个执行器:
-
AuthenticationStepsExecutor
作为同步的替代品ClientAuthentication
。 -
AuthenticationStepsOperator
用于反应式执行。
许多ClientAuthentication
's 带有静态工厂方法来AuthenticationSteps
为其特定于身份验证的选项创建:
AuthenticationSteps
执行CubbyholeAuthenticationOptions options = …
RestOperations restOperations = …
AuthenticationSteps steps = CubbyholeAuthentication.createAuthenticationSteps(options);
AuthenticationStepsExecutor executor = new AuthenticationStepsExecutor(steps, restOperations);
VaultToken token = executor.login();
15.15。代币生命周期
Vault 的代币可以与生存时间相关联。只要会话处于活动状态,就可以使用通过身份验证方法获得的令牌,并且在应用程序处于活动状态时不应过期。
Spring Vault 提供了LifecycleAwareSessionManager
一个会话管理器,它可以更新令牌,直到它达到其终端 TTL,然后执行另一个登录以获得与会话关联的下一个令牌。
根据身份验证方法,登录可以创建两种令牌:
-
VaultToken
:封装实际令牌的通用令牌。 -
LoginToken
:与可再生性/TTL 相关的令牌。
身份验证方法,例如TokenAuthentication
仅创建VaultToken
不携带任何可更新性/TTL 详细信息的身份验证方法。LifecycleAwareSessionManager
将对令牌运行自我查找以从 Vault 检索可更新性和 TTL。
VaultToken
如果启用了自我查找,则会定期更新。请注意,VaultToken
永远不会被撤销,只会LoginToken
被撤销。
直接创建的身份验证方法LoginToken
(所有基于登录的身份验证方法)已经提供了设置令牌更新所需的所有详细信息。LifecycleAwareSessionManager
如果会话管理器关闭,则从登录获得的令牌将被撤销。
16. 杂项
在本章中学习有关 Spring Security 集成等值得一提的细节。
16.1. Spring安全
Spring Vault 通过提供 和 的实现与 Spring SecurityBytesKeyGenerator
集成BytesEncryptor
。两种实现都使用 Vault 的transit
后端。
VaultBytesKeyGenerator
示例VaultOperations operations = …;
VaultBytesKeyGenerator generator = new VaultBytesKeyGenerator(operations);
byte[] key = generator.generateKey();
VaultBytesEncryptor
示例VaultTransitOperations transit = …;
VaultBytesEncryptor encryptor = new VaultBytesEncryptor(transit, "my-key-name");
byte[] ciphertext = encryptor.encrypt(plaintext);
byte[] result = encryptor.decrypt(ciphertext);
Vault 封装了一个熵源,它与您的 JVM 以及服务器端密钥管理分离。这减轻了应用程序开发人员进行适当加密/解密的负担,并将负担推到了 Vault 的运营商身上。Vault 的运营商通常包括组织中的安全团队,这意味着他们可以确保数据被正确加密/解密。此外,由于加密/解密操作必须进入审计日志,任何解密事件都会被记录下来。
后端还支持密钥轮换,允许生成命名密钥的新版本。所有使用密钥加密的数据都将使用最新版本的密钥;以前加密的数据可以使用旧版本的密钥解密。管理员可以控制哪些以前版本的密钥可用于解密,以防止攻击者获得密文的旧副本以成功解密。
保险柜毕竟是一种网络服务,每次操作都会有延迟。大量使用加密或随机字节生成的组件可能会遇到吞吐量和性能方面的差异。