支援 Vault 的秘密引擎
Spring Vault 提供了多種擴充套件來支援 Vault 的各種秘密引擎。
具體來說,Spring Vault 提供了以下秘密引擎的擴充套件:
-
Transform(轉換)(企業版功能)
-
System 後端
你也可以透過 VaultTemplate
上的方法直接使用所有其他後端(VaultTemplate.read(…)
, VaultTemplate.write(…)
)。
Key-Value 版本 1("非版本化秘密")
kv
秘密引擎用於在配置的 Vault 物理儲存中儲存任意秘密。
以非版本化方式執行 kv
秘密引擎時,只會保留鍵的最新寫入值。非版本化 kv 的優點是每個鍵所需的儲存空間更小,因為不會儲存額外的元資料或歷史記錄。此外,以此方式配置的後端處理請求時效能更高,因為儲存呼叫更少,且對任何給定請求都沒有鎖。
Spring Vault 提供了一個專用的 Key-Value API,用於封裝不同 Key-Value API 實現之間的差異。VaultKeyValueOperations
遵循 Vault CLI 的設計。Vault CLI 是 Vault 的主要命令列工具,提供了諸如 vault kv get
、vault kv put
等命令。
你也可以透過指定版本和掛載路徑將此 API 用於兩種 Key-Value 引擎版本。以下示例使用 Key-Value 版本 1
VaultOperations operations = new VaultTemplate(new VaultEndpoint());
VaultKeyValueOperations keyValueOperations = operations.opsForKeyValue("secret",
VaultKeyValueOperationsSupport.KeyValueBackend.KV_1);
keyValueOperations.put("elvis", Collections.singletonMap("password", "409-52-2002"));
VaultResponse read = keyValueOperations.get("elvis");
read.getRequiredData().get("social-security-number");
VaultKeyValueOperations
支援所有 Key-Value 操作,例如 put
、get
、delete
、list
。
或者,也可以透過 VaultTemplate
使用此 API,因為它具有直接對映和簡單用法,鍵和響應直接對映到輸入和輸出鍵。以下示例演示了在 mykey
處寫入和讀取秘密。kv
秘密引擎掛載在 secret
VaultOperations operations = new VaultTemplate(new VaultEndpoint());
operations.write("secret/elvis", Collections.singletonMap("social-security-number", "409-52-2002"));
VaultResponse read = operations.read("secret/elvis");
read.getRequiredData().get("social-security-number");
你可以在 Vault 參考文件中找到有關 Vault Key-Value 版本 1 API 的更多詳細資訊。
Key-Value 版本 2("版本化秘密")
你可以將 kv
秘密引擎執行在兩個版本之一。本節介紹如何使用版本 2。執行版本 2 的 kv
後端時,一個鍵可以保留可配置數量的版本。你可以檢索舊版本的元資料和資料。此外,你可以使用檢查並設定(check-and-set)操作來避免意外覆蓋資料。
與 Key-Value 版本 1("非版本化秘密")類似,Spring Vault 提供了一個專用的 Key-Value API,用於封裝不同 Key-Value API 實現之間的差異。VaultKeyValueOperations
遵循 Vault CLI 的設計,Vault CLI 是 Vault 的主要命令列工具,提供了諸如 vault kv get
、vault kv put
等命令。
你也可以透過指定版本和掛載路徑將此 API 用於兩種 Key-Value 引擎版本。以下示例使用 Key-Value 版本 2
VaultOperations operations = new VaultTemplate(new VaultEndpoint());
VaultKeyValueOperations keyValueOperations = operations.opsForKeyValue("secret",
VaultKeyValueOperationsSupport.KeyValueBackend.KV_2);
keyValueOperations.put("elvis", Collections.singletonMap("social-security-number", "409-52-2002"));
VaultResponse read = keyValueOperations.get("elvis");
read.getRequiredData().get("social-security-number");
VaultKeyValueOperations
支援所有 Key-Value 操作,例如 put
、get
、delete
、list
。
你也可以與版本化 Key-Value API 的具體細節進行互動。如果你想獲取特定的秘密或需要訪問元資料,這將非常有用。
VaultOperations operations = new VaultTemplate(new VaultEndpoint());
VaultVersionedKeyValueOperations versionedOperations = operations.opsForVersionedKeyValue("secret");
Versioned.Metadata metadata = versionedOperations.put("elvis", (1)
Collections.singletonMap("social-security-number", "409-52-2002"));
Version version = metadata.getVersion(); (2)
Versioned<Object> ssn = versionedOperations.get("elvis", Version.from(42)); (3)
Versioned<SocialSecurityNumber> mappedSsn = versionedOperations.get("elvis", (4)
Version.from(42), SocialSecurityNumber.class);
Versioned<Map<String,String>> versioned = Versioned.create(Collections (5)
.singletonMap("social-security-number", "409-52-2002"),
Version.from(42));
versionedOperations.put("elvis", version);
1 | 在 elvis 處儲存秘密,該位置在 secret/ 掛載路徑下可用。 |
2 | 在版本化後端儲存資料會返回元資料,例如版本號。 |
3 | 版本化 Key-Value API 允許檢索由版本號標識的特定版本。 |
4 | 版本化 Key-Value 秘密可以對映到值物件中。 |
5 | 使用 CAS 更新版本化秘密時,輸入必須引用先前獲取的版本。 |
雖然可以透過 VaultTemplate
使用 kv
v2 秘密引擎,但這並不是最便捷的方式,因為該 API 在上下文路徑和輸入/輸出表示方式上有所不同。具體來說,與實際秘密的互動需要對資料部分進行包裝和解包裝,並在掛載路徑和秘密鍵之間引入一個 data/
路徑段。
VaultOperations operations = new VaultTemplate(new VaultEndpoint());
operations.write("secret/data/elvis", Collections.singletonMap("data",
Collections.singletonMap("social-security-number", "409-52-2002")));
VaultResponse read = operations.read("secret/data/ykey");
Map<String,String> data = (Map<String, String>) read.getRequiredData().get("data");
data.get("social-security-number");
你可以在 Vault 參考文件中找到有關 Vault Key-Value 版本 2 API 的更多詳細資訊。
PKI(公鑰基礎設施)
pki
秘密引擎是一個證書後端,透過實現證書頒發機構操作來提供服務。
PKI 秘密引擎生成動態的 X.509 證書。使用此秘密引擎,服務無需經過通常手動生成私鑰和 CSR、提交給 CA 並等待驗證和簽名過程完成的流程即可獲取證書。Vault 內建的身份驗證和授權機制提供了驗證功能。
Spring Vault 透過 VaultPkiOperations
支援證書的頒發、簽名、吊銷和 CRL 檢索。所有其他 PKI 功能都可以透過 VaultOperations
使用。
以下示例簡要說明了如何頒發和吊銷證書
VaultOperations operations = new VaultTemplate(new VaultEndpoint());
VaultPkiOperations pkiOperations = operations.opsForPki("pki");
VaultCertificateRequest request = VaultCertificateRequest.builder() (1)
.ttl(Duration.ofHours(48))
.altNames(Arrays.asList("prod.dc-1.example.com", "prod.dc-2.example.com"))
.withIpSubjectAltName("1.2.3.4")
.commonName("hello.example.com")
.build();
VaultCertificateResponse response = pkiOperations.issueCertificate("production", request); (2)
CertificateBundle certificateBundle = response.getRequiredData();
KeyStore keyStore = certificateBundle.createKeyStore("my-keystore"); (3)
KeySpec privateKey = certificateBundle.getPrivateKeySpec(); (4)
X509Certificate certificate = certificateBundle.getX509Certificate();
X509Certificate caCertificate = certificateBundle.getX509IssuerCertificate();
pkiOperations.revoke(certificateBundle.getSerialNumber()); (5)
1 | 使用 VaultCertificateRequest 構建器構造證書請求。 |
2 | 從 Vault 請求證書。Vault 作為證書頒發機構,返回一個已簽名的 X.509 證書。實際響應是一個 CertificateBundle 物件。 |
3 | 你可以直接將生成的證書獲取為 Java KeyStore,它包含公鑰、私鑰以及頒發者證書。KeyStore 用途廣泛,此格式適用於配置(例如 HTTP 客戶端、資料庫驅動程式或 SSL 安全的 HTTP 伺服器)。 |
4 | CertificateBundle 允許透過 Java Cryptography Extension API 直接訪問私鑰以及公鑰和頒發者證書。 |
5 | 證書不再使用(或已洩露)後,你可以透過其序列號吊銷它。Vault 會將吊銷的證書包含在其 CRL 中。 |
你可以在 Vault 參考文件中找到有關 Vault PKI secrets API 的更多詳細資訊。
Token(令牌)身份驗證後端
token
身份驗證方法是內建的,並自動在 /auth/token
處可用。它允許使用者使用令牌進行身份驗證,還可以建立新令牌、透過令牌撤銷秘密等。
當任何其他身份驗證方法返回一個身份時,Vault core 會呼叫令牌方法為該身份建立一個新的唯一令牌。
你還可以使用令牌儲存繞過任何其他身份驗證方法。你可以直接建立令牌,並對令牌執行各種其他操作,例如續訂和吊銷。
Spring Vault 使用此後端來續訂和吊銷由配置的身份驗證方法提供的會話令牌。
以下示例展示瞭如何在應用程式中請求、續訂和吊銷 Vault 令牌
VaultOperations operations = new VaultTemplate(new VaultEndpoint());
VaultTokenOperations tokenOperations = operations.opsForToken();
VaultTokenResponse tokenResponse = tokenOperations.create(); (1)
VaultToken justAToken = tokenResponse.getToken();
VaultTokenRequest tokenRequest = VaultTokenRequest.builder().withPolicy("policy-for-myapp")
.displayName("Access tokens for myapp")
.renewable()
.ttl(Duration.ofHours(1))
.build();
VaultTokenResponse appTokenResponse = tokenOperations.create(tokenRequest); (2)
VaultToken appToken = appTokenResponse.getToken();
tokenOperations.renew(appToken); (3)
tokenOperations.revoke(appToken); (4)
1 | 透過應用角色預設值建立一個令牌。 |
2 | 使用構建器 API,你可以定義要請求的令牌的細粒度設定。請求令牌會返回一個 VaultToken 物件,該物件用作 Vault 令牌的值物件。 |
3 | 你可以透過 Token API 續訂令牌。通常,這由 SessionManager 完成,用於跟蹤 Vault 會話令牌。 |
4 | 如果需要,可以透過 Token API 吊銷令牌。通常,這由 SessionManager 完成,用於跟蹤 Vault 會話令牌。 |
你可以在 Vault 參考文件中找到有關 Vault Token 身份驗證方法 API 的更多詳細資訊。
Transit 後端
Transit 秘密引擎處理傳輸中資料的加密功能。Vault 不儲存傳送到此秘密引擎的資料。它也可以被視為“密碼學即服務”或“加密即服務”。Transit 秘密引擎還可以簽名和驗證資料,生成資料的雜湊和 HMAC,並作為隨機位元組源。
Transit 的主要用例是加密來自應用程式的資料,同時仍將加密資料儲存在某個主要資料儲存中。這減輕了應用程式開發人員正確處理加密和解密流程的負擔,並將負擔轉移給了 Vault 的運維人員。
Spring Vault 支援廣泛的 Transit 操作
-
金鑰建立
-
金鑰重新配置
-
加密/解密/重打包
-
HMAC 計算
-
簽名和簽名驗證
transit
中的所有操作都圍繞著金鑰。Transit 引擎支援金鑰的版本控制和多種金鑰型別。請注意,金鑰型別可能會限制可使用的操作。
以下示例展示瞭如何建立金鑰以及如何加密和解密資料
VaultOperations operations = new VaultTemplate(new VaultEndpoint());
VaultTransitOperations transitOperations = operations.opsForTransit("transit");
transitOperations.createKey("my-aes-key", VaultTransitKeyCreationRequest.ofKeyType("aes128-gcm96")); (1)
String ciphertext = transitOperations.encrypt("my-aes-key", "plaintext to encrypt"); (2)
String plaintext = transitOperations.decrypt("my-aes-key", ciphertext); (3)
1 | 首先,我們需要一個金鑰。每個金鑰都需要指定型別。aes128-gcm96 支援加密、解密、金鑰派生和會聚加密,本示例中我們需要加密和解密。 |
2 | 接下來,我們加密包含應被加密的明文的 String 。輸入的 String 使用預設的 Charset 將字串編碼為其二進位制表示形式。請求令牌會返回一個 VaultToken ,該物件用作 Vault 令牌的值物件。encrypt 方法返回 Base64 編碼的密文,通常以 vault: 開頭。 |
3 | 要將密文解密為明文,請呼叫 decrypt 方法。它解密密文並返回一個使用預設字元集解碼的 String 。 |
前面的示例對加密操作使用了簡單的字串。雖然這是一種簡單的方法,但存在字元集配置錯誤的風險,並且不是二進位制安全的。當明文使用二進位制表示形式表示影像、壓縮資料或二進位制資料結構等資料時,需要二進位制安全。
要加密和解密二進位制資料,請使用可以儲存二進位制值的 Plaintext
和 Ciphertext
值物件。
byte [] plaintext = "plaintext to encrypt".getBytes();
Ciphertext ciphertext = transitOperations.encrypt("my-aes-key", Plaintext.of(plaintext)); (1)
Plaintext decrypttedPlaintext = transitOperations.decrypt("my-aes-key", ciphertext); (2)
1 | 假設金鑰 my-aes-key 已經存在,我們正在加密 Plaintext 物件。相應地,encrypt 方法返回一個 Ciphertext 物件。 |
2 | Ciphertext 物件可以直接用於解密,並返回一個 Plaintext 物件。 |
Plaintext
和 Ciphertext
附帶一個上下文物件 VaultTransitContext
。它用於為會聚加密提供 nonce 值,並用於提供上下文值以利用金鑰派生。
Transit 允許對明文進行簽名並驗證給定明文的簽名。簽名操作需要非對稱金鑰,通常使用橢圓曲線密碼學或 RSA。
簽名使用公鑰/私鑰對來確保真實性。 簽名者使用其私鑰建立簽名。否則,任何人都可以在你的名義下籤署訊息。驗證者使用公鑰部分來驗證簽名。實際簽名通常是一個雜湊值。 在內部,計算雜湊值並使用私鑰對其進行加密以建立最終簽名。驗證過程解密簽名訊息,計算明文的雜湊值,並比較兩個雜湊值以檢查簽名是否有效。 |
byte [] plaintext = "plaintext to sign".getBytes();
transitOperations.createKey("my-ed25519-key", VaultTransitKeyCreationRequest.ofKeyType("ed25519")); (1)
Signature signature = transitOperations.sign("my-ed25519-key", Plaintext.of(plaintext)); (2)
boolean valid = transitOperations.verify("my-ed25519-key", Plaintext.of(plaintext), signature); (3)
你可以在 Vault 參考文件中找到有關 Vault Transit 後端的更多詳細資訊。