VaultTemplate 介绍
VaultTemplate 类位于 org.springframework.vault.core 包中,它是 Spring 的 Vault 支持的核心类,提供了丰富的功能集来与 Vault 交互。该模板提供了便捷的操作来读取、写入和删除 Vault 中的数据,并提供了您的域对象与 Vault 数据之间的映射。
| VaultTemplate配置完成后是线程安全的,可以在多个实例中复用。 | 
Vault 文档与域类之间的映射通过委托给 RestTemplate 完成。Spring Web 支持提供了映射基础设施。
VaultTemplate 类实现了 VaultOperations 接口。VaultOperations 上的方法尽可能地沿用了 Vault API 中可用方法的命名,以便让习惯使用 Vault 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 Context。然而,在托管上下文内注册的 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://: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 支持常用的配置。其他配置可以通过派生自最适合的配置类来支持。使用 @Import(EnvironmentVaultConfiguration.class) 将 EnvironmentVaultConfiguration 包含到现有的基于 Java 的配置类中,并通过 Spring 的任何 PropertySource 提供配置属性。
@PropertySource("vault.properties")
@Import(EnvironmentVaultConfiguration.class)
public class MyConfiguration{
}vault.uri=https://: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
- 
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
- 
元数据服务 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> 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();
    }
});