Spring Vault 附带了多个扩展,以支持 Vault 的各种秘密引擎。

具体来说,Spring Vault 附带了以下扩展:

您可以通过 直接 (, ) 上的方法使用所有其他后端。VaultTemplateVaultTemplate.read(…)VaultTemplate.write(…)

键值版本 1(“未版本控制的密钥”)

密钥引擎用于将任意密钥存储在为 Vault 配置的物理存储中。kv

以非版本化方式运行密钥引擎时,仅保留密钥的最近写入值。 非版本化 kv 的优点是减少了每个密钥的存储大小,因为不会存储额外的元数据或历史记录。 此外,以这种方式配置的后端的请求性能更高,因为存储调用更少,并且任何给定请求都没有锁定。kv

Spring Vault 附带了一个专用的键值 API,用于封装各个键值 API 实现之间的差异。 遵循 Vault CLI 设计。 这是 Vault 的主要命令行工具,提供 等命令。VaultKeyValueOperationsvault kv getvault kv put

您可以通过指定版本和挂载路径将此 API 用于两个键值引擎版本。 以下示例使用 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支持所有键值操作,如 、 、 、 。putgetdeletelist

或者,由于 API 的直接映射和简单使用,因此可以通过 API 使用,因为键和响应直接映射到输入和输出键。 以下示例演示了如何在 中写入和读取密钥。 机密引擎安装在:VaultTemplatemykeykvsecret

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 的更多详细信息。

键值版本 2(“版本控制密钥”)

您可以在以下两个版本之一中运行密钥引擎。 本部分介绍如何使用版本 2。运行后端版本 2 时,密钥可以保留可配置的版本数。 您可以检索旧版本的元数据和数据。 此外,还可以使用检查和设置操作来避免无意中覆盖数据。kvkv

键值版本 1(“未版本控制的密钥”)类似,Spring Vault 附带了一个专用的键值 API,用于封装各个键值 API 实现之间的差异。 Spring Vault 附带了一个专用的键值 API,用于封装各个键值 API 实现之间的差异。 遵循 Vault CLI 设计。 这是 Vault 的主要命令行工具,提供 、 等命令。VaultKeyValueOperationsvault kv getvault kv put

您可以通过指定版本和挂载路径将此 API 用于两个键值引擎版本。 以下示例使用 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支持所有键值操作,例如 、 、 、 。putgetdeletelist

您还可以与版本控制键值 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 将机密存储在安装下方。elvissecret/
2 在版本控制后端存储数据将返回元数据,例如版本号。
3 版本控制键值 API 允许检索由版本号标识的特定版本。
4 版本控制的键值机密可以映射到值对象。
5 使用 CAS 更新版本化密钥时,输入必须引用以前获取的版本。

同时使用 v2 机密引擎是可能的。 这不是最方便的方法,因为 API 为上下文路径和输入/输出的表示方式提供了不同的方法。 具体而言,与实际密钥的交互需要包装和解包数据部分,并在挂载和密钥密钥之间引入路径段。kvVaultTemplatedata/

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 键值版本 2 API 的更多详细信息。

1 将机密存储在安装下方。elvissecret/
2 在版本控制后端存储数据将返回元数据,例如版本号。
3 版本控制键值 API 允许检索由版本号标识的特定版本。
4 版本控制的键值机密可以映射到值对象。
5 使用 CAS 更新版本化密钥时,输入必须引用以前获取的版本。

PKI(公钥基础设施)

机密引擎通过实现证书颁发机构操作来表示证书的后端。pki

PKI 机密引擎生成动态 X.509 证书。 使用此密钥引擎,服务可以获取证书,而无需通过生成私钥和 CSR、提交到 CA 以及等待验证和签名过程完成的通常手动过程。 保险柜的内置身份验证和授权机制提供了验证功能。

Spring Vault 支持通过 颁发、签名、吊销证书和 CRL 检索。 所有其他 PKI 功能都可以通过 .VaultPkiOperationsVaultOperations

以下示例简要说明了如何颁发和吊销证书的使用:

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 从保险柜申请证书。 保险柜充当证书颁发机构,并使用签名的 X.509 证书进行响应。 实际响应是 .CertificateBundle
3 您可以直接将生成的证书作为 Java KeyStore 获取,其中包含公钥和私钥以及颁发者证书。KeyStore 具有广泛的用途,这使得这种格式适合配置(例如 HTTP 客户端、数据库驱动程序或受 SSL 保护的 HTTP 服务器)。
4 CertificateBundle允许直接通过 Java 加密扩展 API 访问私钥以及公有证书和颁发者证书。
5 一旦证书不再使用(或已泄露),您可以通过其序列号吊销它。 保险柜在其 CRL 中包含已吊销的证书。

您可以在 Vault 参考文档中找到有关 Vault PKI 密钥 API 的更多详细信息。

1 使用生成器构造证书请求。VaultCertificateRequest
2 从保险柜申请证书。 保险柜充当证书颁发机构,并使用签名的 X.509 证书进行响应。 实际响应是 .CertificateBundle
3 您可以直接将生成的证书作为 Java KeyStore 获取,其中包含公钥和私钥以及颁发者证书。KeyStore 具有广泛的用途,这使得这种格式适合配置(例如 HTTP 客户端、数据库驱动程序或受 SSL 保护的 HTTP 服务器)。
4 CertificateBundle允许直接通过 Java 加密扩展 API 访问私钥以及公有证书和颁发者证书。
5 一旦证书不再使用(或已泄露),您可以通过其序列号吊销它。 保险柜在其 CRL 中包含已吊销的证书。

令牌认证后端

此后端是一个身份验证后端,不与实际机密交互。 相反,它提供对访问令牌管理的访问权限。 您可以在身份验证方法一章中阅读有关基于令牌的身份验证的更多信息。

身份验证方法是内置的,可在 中自动使用。 它允许用户使用令牌进行身份验证,以及创建新令牌、按令牌撤销机密等。token/auth/token

当任何其他身份验证方法返回身份时,保险柜核心会调用令牌方法,为该身份创建新的唯一令牌。

您还可以使用令牌存储来绕过任何其他身份验证方法。您可以直接创建令牌,也可以对令牌执行各种其他操作,例如续费和吊销。

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,您可以为要请求的令牌定义细粒度设置。 请求令牌将返回一个 ,该 用作 Vault 令牌的值对象。VaultToken
3 您可以通过令牌 API 续订令牌。通常,这是通过跟踪 Vault 会话令牌来完成的。SessionManager
4 如果需要,可以通过令牌 API 撤销令牌。通常,这是通过跟踪 Vault 会话令牌来完成的。SessionManager

您可以在 Vault 参考文档中找到有关 Vault 令牌身份验证方法 API 的更多详细信息。

1 通过应用角色默认值创建令牌。
2 使用构建器 API,您可以为要请求的令牌定义细粒度设置。 请求令牌将返回一个 ,该 用作 Vault 令牌的值对象。VaultToken
3 您可以通过令牌 API 续订令牌。通常,这是通过跟踪 Vault 会话令牌来完成的。SessionManager
4 如果需要,可以通过令牌 API 撤销令牌。通常,这是通过跟踪 Vault 会话令牌来完成的。SessionManager

传输后端

传输密钥引擎处理传输中数据的加密功能。 保险柜不会存储发送到此密钥引擎的数据。 它也可以看作是“加密即服务”或“加密即服务”。 传输密钥引擎还可以对数据进行签名和验证,生成数据的哈希和 HMAC,并充当随机字节源。

传输的主要用例是加密来自应用程序的数据,同时仍将加密数据存储在某些主数据存储中。 这减轻了应用程序开发人员进行正确加密和解密的负担,并将负担推给了 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 接下来,我们加密包含应加密的纯文本。 输入使用默认值将字符串编码为其二进制表示形式。 请求令牌将返回一个 ,该 用作 Vault 令牌的值对象。 该方法返回 Base64 编码的密文,通常以 开头。StringStringCharsetVaultTokenencryptvault:
3 若要将密文解密为纯文本,请调用该方法。 它解密密文并返回使用默认字符集解码的密文。decryptString

前面的示例使用简单字符串进行加密操作。 虽然这是一种简单的方法,但它存在字符集错误配置的风险,并且不是二进制安全的。 当纯文本对图像、压缩数据或二进制数据结构等数据使用二进制表示形式时,需要二进制安全性。

若要加密和解密二进制数据,请使用可以保存二进制值的 和 值对象:PlaintextCiphertext

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-keyPlaintextencryptCiphertext
2 该对象可以直接用于解密并返回一个对象。CiphertextPlaintext

Plaintext并附带一个上下文对象 . 它用于为收敛加密提供随机数值,并为上下文值提供使用密钥派生。CiphertextVaultTransitContext

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)
1 签名需要非对称密钥。您可以使用任何椭圆曲线加密或 RSA 密钥类型。创建密钥后,即可满足创建签名的所有先决条件。
2 为纯文本消息创建签名。返回的字符串包含使用 Base64 字符的 ASCII 安全字符串。Signature
3 若要验证签名,验证需要 Signature 对象和纯文本消息。作为返回值,您可以获得签名是否有效。

您可以在 Vault 参考文档中找到有关 Vault 传输后端的更多详细信息。

1 首先,我们需要一把钥匙。 每个键都需要指定类型。 支持加密、解密、密钥派生和收敛加密,本例我们需要加密和解密。aes128-gcm96
2 接下来,我们加密包含应加密的纯文本。 输入使用默认值将字符串编码为其二进制表示形式。 请求令牌将返回一个 ,该 用作 Vault 令牌的值对象。 该方法返回 Base64 编码的密文,通常以 开头。StringStringCharsetVaultTokenencryptvault:
3 若要将密文解密为纯文本,请调用该方法。 它解密密文并返回使用默认字符集解码的密文。decryptString
1 假设密钥已经到位,我们将对对象进行加密。 作为回报,该方法返回一个对象。my-aes-keyPlaintextencryptCiphertext
2 该对象可以直接用于解密并返回一个对象。CiphertextPlaintext
签名使用公钥/私钥拆分来确保真实性。
签名者使用其私钥创建签名。否则,任何人都可以以您的名义对邮件进行签名。 验证器使用公钥部分来验证签名。实际签名通常是哈希值。

在内部,使用私钥计算和加密哈希值以创建最终签名。验证解密签名消息,计算纯文本的哈希值,并比较两个哈希值以检查签名是否有效。
1 签名需要非对称密钥。您可以使用任何椭圆曲线加密或 RSA 密钥类型。创建密钥后,即可满足创建签名的所有先决条件。
2 为纯文本消息创建签名。返回的字符串包含使用 Base64 字符的 ASCII 安全字符串。Signature
3 若要验证签名,验证需要 Signature 对象和纯文本消息。作为返回值,您可以获得签名是否有效。