Vault 儲存庫
透過使用 VaultTemplate
以及對應至 Java 類別的回應,可以執行基本的資料操作,例如讀取、寫入和刪除。Vault 儲存庫將 Spring Data 的儲存庫概念應用於 Vault 之上。Vault 儲存庫公開基本的 CRUD 功能,並支援使用限制識別碼屬性的述詞、分頁和排序進行查詢衍生。Vault 儲存庫使用金鑰值密碼引擎功能來持久化和查詢資料。從 2.4 版開始,Spring Vault 可以額外使用金鑰值版本 2 密碼引擎,實際的密碼引擎版本會在執行時探索。
版本化金鑰值密碼引擎中的刪除作業使用 DELETE 操作。密碼不會透過 CrudRepository.delete(…) 銷毀。 |
請閱讀 Spring Data Commons 參考文件,以深入了解 Spring Data 儲存庫。參考文件將為您介紹 Spring Data 儲存庫。 |
用法
若要存取儲存在 Vault 中的網域實體,您可以利用儲存庫支援,大幅簡化實作。
@Secret
class Credentials {
@Id String id;
String password;
String socialSecurityNumber;
Address address;
}
我們有一個非常簡單的網域物件。請注意,它有一個名為 id
的屬性,並使用 org.springframework.data.annotation.Id
進行註解,並且在其類型上具有 @Secret
註解。這兩者負責建立實際的金鑰,用於將物件以 JSON 格式持久化在 Vault 中。
使用 @Id 註解以及名稱為 id 的屬性都視為識別碼屬性。具有註解的屬性優先於其他屬性。 |
下一步是宣告使用網域物件的儲存庫介面。
interface CredentialsRepository extends CrudRepository<Credentials, String> {
}
由於我們的儲存庫擴充了 CrudRepository
,因此它提供了基本的 CRUD 和查詢方法。Vault 儲存庫需要 Spring Data 元件。請確保在您的類別路徑中包含 spring-data-commons
和 spring-data-keyvalue
構件。
最簡單的達成方式是設定相依性管理,並將構件新增至您的 pom.xml
然後將以下內容新增至 pom.xml
相依性區段。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-bom</artifactId>
<version>2023.1.9</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- other dependency elements omitted -->
<dependency>
<groupId>org.springframework.vault</groupId>
<artifactId>spring-vault-core</artifactId>
<version>3.1.2</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-keyvalue</artifactId>
<!-- Version inherited from the BOM -->
</dependency>
</dependencies>
我們需要在中間將它們連結在一起的東西是相應的 Spring 設定。
@Configuration
@EnableVaultRepositories
class ApplicationConfig {
@Bean
VaultTemplate vaultTemplate() {
return new VaultTemplate(…);
}
}
假設上述設定,我們可以繼續將 CredentialsRepository
注入到我們的元件中。
@Autowired CredentialsRepository repo;
void basicCrudOperations() {
Credentials creds = new Credentials("heisenberg", "327215", "AAA-GG-SSSS");
rand.setAddress(new Address("308 Negra Arroyo Lane", "Albuquerque", "New Mexico", "87104"));
repo.save(creds); (1)
repo.findOne(creds.getId()); (2)
repo.count(); (3)
repo.delete(creds); (4)
}
1 | 將 Credentials 的屬性儲存在 Vault Hash 中,金鑰模式為 keyspace/id ,在本例中為 credentials/heisenberg ,在金鑰值密碼引擎中。 |
2 | 使用提供的 id 來檢索儲存在 keyspace/id 的物件。 |
3 | 計算由 Credentials 上 @Secret 定義的 keyspace credentials 內可用的實體總數。 |
4 | 從 Vault 移除給定物件的金鑰。 |
物件至 Vault JSON 對應
Vault 儲存庫使用 JSON 作為交換格式,將物件儲存在 Vault 中。JSON 和實體之間的物件對應由 VaultConverter
完成。轉換器讀取和寫入 SecretDocument
,其中包含來自 VaultResponse
的本文。VaultResponse
是從 Vault 讀取的,而本文則由 Jackson 反序列化為 String
和 Object
的 Map
。預設的 VaultConverter
實作會讀取具有巢狀值、List
和 Map
物件的 Map
,並將其轉換為實體,反之亦然。
假設先前章節中的 Credentials
類型,預設對應如下
{
"_class": "org.example.Credentials", (1)
"password": "327215", (2)
"socialSecurityNumber": "AAA-GG-SSSS",
"address": { (3)
"street": "308 Negra Arroyo Lane",
"city": "Albuquerque",
"state": "New Mexico",
"zip": "87104"
}
}
1 | _class 屬性包含在根層級以及任何巢狀介面或抽象類型上。 |
2 | 簡單屬性值會依路徑對應。 |
3 | 複雜型別的屬性會對應為巢狀物件。 |
@Id 屬性必須對應至 String 。 |
型別 | 範例 | 對應值 |
---|---|---|
簡單型別 |
String firstname = "Walter"; |
"firstname": "Walter" |
複雜型別 |
Address adress = new Address("308 Negra Arroyo Lane"); |
"address": { "street": "308 Negra Arroyo Lane" } |
List |
List<String> nicknames = asList("walt", "heisenberg"); |
"nicknames": ["walt", "heisenberg"] |
Map |
Map<String, Integer> atts = asMap("age", 51) |
"atts" : {"age" : 51} |
List |
List<Address> addresses = asList(new Address("308… |
"address": [{ "street": "308 Negra Arroyo Lane" }, …] |
您可以透過在 VaultCustomConversions
中註冊 Converter
來客製化對應行為。這些轉換器可以負責從/到類型(例如 LocalDate
)以及 SecretDocument
進行轉換,其中第一個適用於轉換簡單屬性,而最後一個適用於將複雜型別轉換為其 JSON 表示法。第二個選項提供對結果 SecretDocument
的完全控制。將物件寫入 Vault
將刪除內容並重新建立整個項目,因此未對應的資料將遺失。
查詢與查詢方法
查詢方法允許從方法名稱自動衍生簡單查詢。Vault 沒有查詢引擎,但需要直接存取 HTTP 內容路徑。Vault 查詢方法將 Vault 的 API 可能性轉換為查詢。查詢方法執行會列出內容路徑下的子項目、將篩選套用至 Id、選擇性地使用偏移/限制來限制 Id 串流,並在擷取結果後套用排序。
interface CredentialsRepository extends CrudRepository<Credentials, String> {
List<Credentials> findByIdStartsWith(String prefix);
}
Vault 儲存庫的查詢方法僅支援在 @Id 屬性上使用述詞的查詢。 |
以下是 Vault 支援的關鍵字概觀。
關鍵字 | 範例 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
排序與分頁
查詢方法支援排序和分頁,方法是在記憶體中選取從 Vault 內容路徑檢索的 Id 子清單(偏移/限制)。排序不限於特定欄位,這與查詢方法述詞不同。未分頁的排序會在 Id 篩選之後套用,並且從 Vault 擷取所有產生的密碼。這樣,查詢方法只會擷取也作為結果一部分傳回的結果。
使用分頁和排序需要先擷取密碼,然後再篩選 Id,這會影響效能。即使 Vault 傳回的 Id 自然順序變更,排序和分頁也能保證傳回相同的結果。因此,首先從 Vault 擷取所有 Id,然後套用排序,然後進行篩選和偏移/限制。
interface CredentialsRepository extends PagingAndSortingRepository<Credentials, String> {
List<Credentials> findTop10ByIdStartsWithOrderBySocialSecurityNumberDesc(String prefix);
List<Credentials> findByIdStarts(String prefix, Pageable pageRequest);
}
樂觀鎖定
Vault 的金鑰值密碼引擎版本 2 可以維護版本化密碼。Spring Vault 透過網域模型中以 @Version
註解的版本屬性來支援版本控制。使用樂觀鎖定可確保更新僅套用至具有相符版本的密碼。因此,版本屬性的實際值會透過 cas
屬性新增至更新請求。如果另一個操作在此期間變更了密碼,則會擲回 OptimisticLockingFailureException,並且不會更新密碼。
版本屬性必須是數值屬性,例如 int
或 long
,並且在更新密碼時對應至 cas
屬性。
@Secret
class VersionedCredentials {
@Id String id;
@Version int version;
String password;
String socialSecurityNumber;
Address address;
}
以下範例顯示這些功能
VersionedCredentialsRepository repo = …;
VersionedCredentials credentials = repo.findById("sample-credentials").get(); (1)
VersionedCredentials concurrent = repo.findById("sample-credentials").get(); (2)
credentials.setPassword("something-else");
repos.save(credentials); (3)
concurrent.setPassword("concurrent change");
repos.save(concurrent); // throws OptimisticLockingFailureException (4)
1 | 透過 Id sample-credentials 取得密碼。 |
2 | 透過 Id sample-credentials 取得密碼的第二個實例。 |
3 | 更新密碼,並讓 Vault 遞增版本。 |
4 | 更新使用先前版本的第二個實例。由於 Vault 中的版本已在此期間遞增,因此操作失敗並出現 OptimisticLockingFailureException 。 |
刪除版本化密碼時,依 Id 刪除會刪除最新的密碼。依實體刪除會刪除指定版本的密碼。 |
存取版本化密碼
金鑰值版本 2 密碼引擎維護可以透過在您的 Vault 儲存庫介面宣告中實作 RevisionRepository
來存取的密碼版本。修訂儲存庫定義了查詢方法,以取得特定識別碼的修訂。識別碼必須是 String
。
interface RevisionCredentialsRepository extends CrudRepository<Credentials, String>,
RevisionRepository<Credentials, String, Integer> (1)
{
}
1 | 第一個型別參數 (Credentials ) 表示實體類型,第二個 (String ) 表示 id 屬性的類型,最後一個 (Integer ) 是修訂號碼的類型。Vault 僅支援 String 識別碼和 Integer 修訂號碼。 |
用法
您現在可以使用 RevisionRepository
中的方法來查詢實體的修訂,如下列範例所示
RevisionCredentialsRepository repo = …;
Revisions<Integer, Credentials> revisions = repo.findRevisions("my-secret-id");
Page<Revision<Integer, Credentials>> firstPageOfRevisions = repo.findRevisions("my-secret-id", Pageable.ofSize(4));