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。然而,在托管上下文内注册的 VaultTemplateSessionManager 实例将参与 Spring IoC 容器提供的生命周期事件。这有助于在应用程序关闭时处置活动的 Vault 会话。您还可以从在整个应用程序中复用同一个 VaultTemplate 实例中获益。

Spring Vault 提供了一个支持配置类,用于在 Spring 上下文内部提供 bean 定义。应用程序配置类通常继承自 AbstractVaultConfiguration,并且需要提供特定于环境的额外详细信息。

继承自 AbstractVaultConfiguration 需要实现 VaultEndpoint vaultEndpoint()ClientAuthentication clientAuthentication() 方法。

示例 1. 使用基于 Java 的 bean 元数据注册 Spring Vault 对象
@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]
示例 2. 应用注入的属性注册 Spring Vault
@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 提供了两种实现:

使用 EnvironmentVaultConfiguration

Spring Vault 包含 EnvironmentVaultConfiguration,用于从 Spring 的 Environment 和一组预定义属性键配置 Vault 客户端。EnvironmentVaultConfiguration 支持常用的配置。其他配置可以通过派生自最适合的配置类来支持。使用 @Import(EnvironmentVaultConfiguration.class)EnvironmentVaultConfiguration 包含到现有的基于 Java 的配置类中,并通过 Spring 的任何 PropertySource 提供配置属性。

示例 3. 将 EnvironmentVaultConfiguration 与属性文件一起使用
基于 Java 的配置类
@PropertySource("vault.properties")
@Import(EnvironmentVaultConfiguration.class)
public class MyConfiguration{
}
vault.properties
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-idMAC_ADDRESSIP_ADDRESS 分别使用 MacAddressUserIdIpAddressUserId 用户 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

没有配置选项。

  • 初始 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();
    }
});