1. 概述
在本教程中,我們將演示如何使用 Hashicorp 的 Vault 在 Spring Boot 應用程序中安全地保護敏感的配置數據。
我們在此假設您已經具備一定的 Vault 知識,並且已經有一個測試環境運行中。 如果情況並非如此,我們建議您先閲讀我們的 Vault 簡介教程,以便熟悉其基本概念。
2. Spring Cloud Vault
Spring Cloud Vault 是 Spring Cloud 棧中相對較新的組件,它允許應用程序以透明的方式訪問存儲在 Vault 實例中的密鑰。
通常,遷移到 Vault 的過程非常簡單:只需添加所需的庫並添加少量額外的配置屬性到我們的項目,我們就可以順利運行。無需進行任何代碼更改!
這得益於它作為高優先級的 PropertySource 註冊到當前的 Environment 中。
因此,Spring 會在需要屬性時使用它。例如,DataSource 屬性、ConfigurationProperties 等。
3. 在 Spring Boot 項目中添加 Spring Cloud Vault
為了將 spring-cloud-vault 庫包含在基於 Maven 的 Spring Boot 項目中,我們使用相關的 starter 構件,它將拉取所有必需的依賴項。
除了主要的 starter,我們還會包含 spring-vault-config-databases,它添加了對動態數據庫憑據的支持:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-vault-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-vault-config-databases</artifactId>
</dependency>最新版本的Spring Cloud Vault starter 可從 Maven Central 下載。
3.1. 基本配置
為了正常工作,Spring Cloud Vault 需要一種方式來確定如何聯繫 Vault 服務器以及如何使用它進行身份驗證。
我們通過在 application.yml 或 application.properties 中提供必要的配置信息來實現:
spring:
cloud:
vault:
uri: https://localhost:8200
ssl:
trust-store: classpath:/vault.jks
trust-store-password: changeit
config:
import: vault:// spring.cloud.vault.uri 屬性指向 Vault 的 API 地址。由於我們的測試環境使用 HTTPS 協議並採用自簽名證書,因此我們也需要提供一個包含其公鑰的 keystore。如果在導入證書時遇到類似“failed to verify certificate: x509: certificate relies on legacy Common Name field, use SANs instead” 的錯誤,可以使用跳過證書驗證選項,如以下示例,即可解決該問題:
vault read -tls-skip-verify database/creds/fakebank-accounts-ro請注意,此配置未包含任何身份驗證數據。對於最簡單的場景,即我們使用固定令牌的情況,可以通過系統屬性 spring.cloud.vault.token 或環境變量進行傳遞。這種方法與標準的雲配置機制(如 Kubernetes 的 ConfigMaps 或 Docker secrets)配合使用效果良好。
Spring Vault 還需要為我們想要在應用程序中使用的一般密鑰類型配置額外的配置。以下部分描述瞭如何為兩個常見密鑰類型添加支持:鍵值和數據庫憑據。
4. 使用通用密鑰後端
我們使用通用密鑰後端來訪問存儲在 Vault 中作為鍵值對的未版本化密鑰。
假設我們已經在類路徑中包含了 spring-cloud-starter-vault-config 依賴項,我們只需要在 application.yml 文件中添加一些屬性:
spring:
cloud:
vault:
# other vault properties omitted ...
generic:
enabled: true
application-name: fakebank
屬性 application-name 在本例中是可選的。如果未指定,Spring 將假定其值為標準屬性 spring.application.name 的值。
現在,我們可以使用存儲在 secret/fakebank 的所有鍵值對,就像任何其他 Environment 屬性一樣。以下代碼片段演示瞭如何讀取存儲在路徑下 foo 鍵的值:
@Autowired Environment env;
public String getFoo() {
return env.getProperty("foo");
}
正如我們所見,代碼本身並不瞭解 Vault,這正是件好事!我們仍然可以在本地測試中使用固定的屬性,只需在應用程序的 application.yml 中啓用一個屬性,就可以隨時切換到 Vault。
4.1. 關於 Spring 配置文件的一點説明
如果當前環境(Environment)可用,Spring Cloud Vault 將使用可用的配置文件名稱作為後綴,附加到指定的基礎路徑,用於搜索鍵值對。
它還會查找在可配置的默認應用程序路徑下(帶有和不帶配置文件後綴)的屬性,以便在單個位置共享密鑰。請謹慎使用此功能!
總結一下,如果我們的 fakebank 應用程序的 production 配置文件處於活動狀態,Spring Vault 將查找以下路徑下的屬性:
- secret/fakebank/production (優先級最高)
- secret/fakebank
- secret/application/production
- secret/application (優先級較低)
在上述列表中,application 是 Spring 使用的默認附加位置名稱,用於密鑰。我們可以使用 spring.cloud.vault.generic.default-context 屬性進行修改。
最具體的路徑存儲的屬性將優先於其他路徑中的屬性。例如,如果相同的屬性 foo 在上述路徑中可用,則優先級順序如下:
5. 使用數據庫密鑰後端
數據庫後端模塊允許 Spring 應用使用 Vault 動態生成的數據庫憑據。 Vault 將這些憑據注入到標準的 spring.datasource.username 和 spring.datasource.password 屬性中,以便常規 DataSource 可以從中獲取。
請注意,在使用此後端之前,必須按照我們之前的教程所述在 Vault 中創建數據庫配置和角色。
為了在我們的 Spring 應用中使用 Vault 生成的數據庫憑據,spring-cloud-vault-config-databases 必須存在於項目的類路徑中,以及相應的 JDBC 驅動程序。
我們還需要通過向我們的 application.yml 添加一些屬性來在應用程序中啓用其使用:
spring:
cloud:
vault:
# ... other properties omitted
database:
enabled: true
role: fakebank-accounts-rw這裏最重要的屬性是 role 屬性,它存儲了 Vault 中的數據庫角色名稱。在啓動時,Spring 將聯繫 Vault 並請求它創建具有相應權限的新憑據。
Vault 默認情況下會在配置的時間到期後撤銷與這些憑據相關的權限。
幸運的是,Spring Vault 會自動續訂與獲取的憑據關聯的租約。 這樣做可以確保憑據在我們的應用程序運行期間保持有效。
現在,讓我們看看這種集成在行動中。以下代碼片段從 Spring 管理的 DataSource 獲取一個新的數據庫連接:
Connection c = datasource.getConnection();
再次可以看到,我們的代碼中沒有任何 Vault 使用的痕跡。所有集成都發生在 環境 級別,因此我們的代碼可以像往常一樣輕鬆進行單元測試。
6. 結論
在本教程中,我們演示瞭如何使用 Spring Vault 庫將 Vault 集成到 Spring Boot 項目中。我們涵蓋了兩種常見的用例:通用鍵值對和動態數據庫憑據。