VaultTemplate简介
类 VaultTemplate,位于包 org.springframework.vault.core 中,是 Spring 的 Vault 支持的核心类,提供了与 Vault 交互的丰富功能集。该模板提供了读取、写入和删除 Vault 中数据的便捷操作,并在您的域对象和 Vault 数据之间提供映射。
Once configured, VaultTemplate 是线程安全的,并且可以在多个实例中重复使用。 |
Vault 文档与领域类之间的映射是通过委托给 RestTemplate 完成的。Spring Web 支持提供了映射基础设施。
VaultTemplate 类实现了接口 VaultOperations。 尽可能地,VaultOperations 上的方法根据 Vault API 中已有的方法命名, 以便让熟悉 Vault API 和 CLI 的开发者感到熟悉。例如,你会发现诸如 “write”、“delete”、“read”和“revoke”之类的方法。 设计目标是尽可能简化在使用 Vault API 和 VaultOperations 之间的过渡。 两个 API 之间的一个主要区别在于,VaultOperations 可以传递领域对象,而不是 JSON 键值对。
在 VaultTemplate 中使用的路径(以及可从其访问的接口)被认为是相对于 VaultEndpoint 的。完全限定的 URI 路径可以用于在认证上下文中访问 Vault 集群成员。为防止不必要的完整 URI 访问,请确保在将路径传递给 VaultTemplate 之前对其进行清理。
引用VaultTemplate实例上的操作的首选方法是通过其接口VaultOperations。 |
虽然 VaultTemplate 上有许多便捷方法可以帮助您轻松执行常见任务,但如果您需要直接访问 Vault API 以获取 VaultTemplate 未明确暴露的功能,您可以使用多种 execute 回调方法之一来访问底层 API。execute 回调将为您提供一个对 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 | Dependencies for ClientAuthentication 方法的依赖项可以从 AbstractVaultConfiguration 获取,或者由您的配置提供。 |
在某些情况下,创建自定义配置类可能会很麻烦。 请查看 EnvironmentVaultConfiguration,它允许通过使用现有属性源和 Spring 的 Environment 进行配置。更多内容请阅读 使用 EnvironmentVaultConfiguration。 |
会话管理
Spring Vault 需要一个 ClientAuthentication 来登录并访问 Vault。 详见 [vault.core.authentication] 关于身份验证的详细信息。 Vault 登录不应在每次经过身份验证的 Vault 交互时发生,而应在整个会话中重复使用。这一方面由 SessionManager 实现来处理。SessionManager 决定了它获取Tokens的频率以及关于吊销和续订的操作。Spring Vault 提供了两种实现:
-
SimpleSessionManager: 仅从提供的ClientAuthentication中获取Tokens,不进行刷新和撤销 -
LifecycleAwareSessionManager: 这个SessionManager会在Tokens可续期时安排Tokens续期,并在销毁时撤销登录Tokens。续期是通过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(可选) -
Keystore 密码:
vault.ssl.key-store-password(可选) -
Keystore 类型:
vault.ssl.key-store-type(可选,通常为jks,也支持pem) -
信任库资源:
vault.ssl.trust-store(可选) -
Truststore 密码:
vault.ssl.trust-store-password(可选) -
Truststore 类型:
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,APPROLE,AWS_EC2,AWS_IAM,AZURE,CERT,CUBBYHOLE,KUBERNETES)
认证特定的属性键
-
Vault Token:
vault.token
-
AppRole 路径:
vault.app-role.app-role-path(默认为approle) -
角色ID:
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(默认为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 -
Metadata Service URL:
vault.azure-msi.metadata-service(默认为169.254.169.254/metadata/instance?api-version=2017-08-01) -
Identity TokenService 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 Token:
vault.token
-
Kubernetes 路径:
vault.kubernetes.kubernetes-path(默认为kubernetes) -
角色:
vault.kubernetes.role -
服务帐户Tokens文件的路径:
vault.kubernetes.service-account-token-file(默认为/var/run/secrets/kubernetes.io/serviceaccount/token)
执行回调
所有 Spring 模板类的一个共同设计特点是,所有功能都被引导到模板的 execute 回调方法之一。 这有助于确保执行一致性,无论可能需要的异常处理还是资源管理。 虽然在 JDBC 和 JMS 的情况下这种需求比 Vault 大得多,但它仍然为访问和日志记录提供了一个统一的位置。 因此,使用 execute 回调是访问 Vault API 的首选方式, 用于执行我们尚未作为 VaultTemplate 方法公开的不常见操作。
以下是执行回调方法的列表。
-
<T> TdoWithVault(RestOperationsCallback<T> callback)执行给定的RestOperationsCallback,允许使用RestOperations与 Vault 进行交互,而无需会话。 -
<T> TdoWithSession(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();
}
});