VaultTemplate 簡介
類 VaultTemplate 位於包 org.springframework.vault.core 中,是 Spring Vault 支援的核心類,提供豐富的功能集以與 Vault 互動。該模板提供方便的操作,用於在 Vault 中讀取、寫入和刪除資料,並提供您的域物件與 Vault 資料之間的對映。
一旦配置完成,VaultTemplate 是執行緒安全的,可以在多個例項中重用。 |
Vault 文件和域類之間的對映透過委託給 RestTemplate 完成。Spring Web 支援提供對映基礎設施。
VaultTemplate 類實現了介面 VaultOperations。在可能的情況下,VaultOperations 上的方法名稱與 Vault API 上可用的方法名稱相同,以使熟悉 API 和 CLI 的現有 Vault 開發人員熟悉該 API。例如,您會找到諸如“write”、“delete”、“read”和“revoke”之類的方法。設計目標是儘可能簡化 Vault API 和 VaultOperations 之間的轉換。兩個 API 之間的一個主要區別是 VaultOperations 可以傳遞域物件而不是 JSON 鍵值對。
VaultTemplate 中使用的路徑(以及可從中訪問的介面)被視為相對於 VaultEndpoint。完全限定的 URI 路徑可用於在經過身份驗證的上下文中訪問 Vault 叢集成員。為防止不必要的完整 URI 訪問,請確保在將路徑傳遞給 VaultTemplate 之前對其進行清理。
引用 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、APPROLE、AWS_EC2、AWS_IAM、AZURE、CERT、CUBBYHOLE、KUBERNETES)
身份驗證特定屬性鍵
-
Vault 令牌:
vault.token
-
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();
}
});