VaultTemplate 简介
位于 org.springframework.vault.core
包中的 VaultTemplate
类是 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 的示例。
注册和配置 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 快速入门。有关支持的身份验证方法的详细信息,请参见 [vault.core.authentication]。 |
@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 中了解更多信息。
|
会话管理
Spring Vault 需要一个 ClientAuthentication
来登录并访问 Vault。有关身份验证的详细信息,请参见 [vault.core.authentication]。Vault 登录不应在每次经过身份验证的 Vault 交互时发生,而应在整个会话中重复使用。这方面由 SessionManager
实现处理。SessionManager
决定它获取令牌的频率、撤销和续订。Spring Vault 附带两个实现
-
SimpleSessionManager
:仅从提供的ClientAuthentication
获取令牌,不进行刷新和撤销 -
LifecycleAwareSessionManager
:此SessionManager
如果令牌可续订,则安排令牌续订,并在处置时撤销登录令牌。续订使用AsyncTaskExecutor
安排。如果使用AbstractVaultConfiguration
,则默认情况下会配置LifecycleAwareSessionManager
。
使用 EnvironmentVaultConfiguration
Spring Vault 包含 EnvironmentVaultConfiguration
,它可以从 Spring 的 Environment
和一组预定义的属性键配置 Vault 客户端。EnvironmentVaultConfiguration
支持常用的配置。其他配置可以通过从最合适的配置类派生来支持。将 EnvironmentVaultConfiguration
与 @Import(EnvironmentVaultConfiguration.class)
结合使用到现有的基于 Java 的配置类中,并通过 Spring 的任何 PropertySource
提供配置属性。
@PropertySource("vault.properties")
@Import(EnvironmentVaultConfiguration.class)
public class MyConfiguration{
}
vault.uri=https://localhost:8200
vault.token=00000000-0000-0000-0000-000000000000
属性键
-
Vault 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
) -
启用的 SSL/TLS 协议:
vault.ssl.enabled-protocols
(自 2.3.2 版本起,可选,协议之间用逗号分隔) -
启用的 SSL/TLS 密码套件:
vault.ssl.enabled-cipher-suites
(自 2.3.2 版本起,可选,密码套件之间用逗号分隔)
-
-
身份验证方法:
vault.authentication
(默认值为TOKEN
,支持的身份验证方法包括:TOKEN
、APPID
、APPROLE
、AWS_EC2
、AWS_IAM
、AZURE
、CERT
、CUBBYHOLE
、KUBERNETES
)
身份验证特定的属性键
-
Vault 令牌:
vault.token
-
AppId 路径:
vault.app-id.app-id-path
(默认值为app-id
) -
AppId:
vault.app-id.app-id
-
UserId:
vault.app-id.user-id
。MAC_ADDRESS
和IP_ADDRESS
使用MacAddressUserId
,分别使用IpAddressUserId
用户 ID 机制。任何其他值都将与StaticUserId
一起使用。
-
AppRole 路径:
vault.app-role.app-role-path
(默认值为approle
) -
RoleId:
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
-
角色 ID:
vault.aws-ec2.role-id
(**已弃用:** 请改用vault.aws-ec2.role
) -
身份文档 URL:
vault.aws-ec2.identity-document
(默认值为169.254.169.254/latest/dynamic/instance-identity/pkcs7
)
-
角色:
vault.aws-iam.role
-
Azure MSI 路径:
vault.azure-msi.azure-path
(默认值为azure
) -
角色:
vault.azure-msi.role
-
元数据服务 URL:
vault.azure-msi.metadata-service
(默认值为169.254.169.254/metadata/instance?api-version=2017-08-01
) -
身份令牌服务 URL:
vault.azure-msi.identity-token-service
(默认值为169.254.169.254/metadata/identity/oauth2/token?resource=https://vault.hashicorp.com&api-version=2018-02-01
)
无配置选项。
-
初始 Vault 令牌:
vault.token
-
Kubernetes 路径:
vault.kubernetes.kubernetes-path
(默认值为kubernetes
) -
角色:
vault.kubernetes.role
-
服务帐户令牌文件路径:
vault.kubernetes.service-account-token-file
(默认值为/var/run/secrets/kubernetes.io/serviceaccount/token
)
执行回调
所有 Spring 模板类的一个常见设计特征是,所有功能都路由到其中一个模板的执行回调方法中。这有助于确保异常和可能需要的任何资源管理以一致的方式执行。虽然在 JDBC 和 JMS 的情况下,这比 Vault 更需要,但它仍然提供了一个用于访问和记录的单一位置。因此,使用执行回调是访问 Vault API 以执行我们尚未在 VaultTemplate
上公开为方法的非通用操作的首选方式。
以下是执行回调方法的列表。
-
<T> T
doWithVault(RestOperationsCallback<T> callback)
执行给定的RestOperationsCallback
,允许在不使用会话的情况下使用RestOperations
与 Vault 交互。 -
<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();
}
});