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://: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://: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();
    }
});