参考文档
7. 保险库支持
Vault 支持包含广泛的功能,总结如下。
-
使用基于 Java 的 @Configuration 类的 Spring 配置支持
-
VaultTemplate
辅助类,提高生产力执行常见 Vault作。包括 Vault 响应和 POJO 之间的集成对象映射。
对于大多数任务,您会发现自己使用VaultTemplate
利用
丰富的通信功能。VaultTemplate
是寻找的地方
访问功能,例如从 Vault 读取数据或
管理命令。VaultTemplate
还提供了回调方法,方便您
获取低级 API 项目,例如RestTemplate
沟通
直接与 Vault 一起使用。
7.1. 依赖项
如果您想在项目中使用 Spring Vault,请声明对spring-vault-core
人工制品。
<dependencies>
<dependency>
<groupId>org.springframework.vault</groupId>
<artifactId>spring-vault-core</artifactId>
</dependency>
</dependencies>
查找兼容版本的 Spring Vault 依赖项的最简单方法是检查spring-vault-parent
.
我们通常建议升级到 Jackson、HTTP 客户端和云提供商 SDK 的最新依赖项。
8. 入门
Spring Vault 支持需要 Vault 0.6 或更高版本以及 Java SE 6 或更高版本。 引导设置工作环境的一种简单方法是创建一个 STS 中基于 Spring 的项目。
首先,您需要设置一个正在运行的 Vault 服务器。 有关如何启动 Vault 实例的说明,请参阅 Vault。
要在 STS 中创建 Spring 项目,请转到文件→新建→
Spring 模板项目→简单的 Spring 实用程序项目→
出现提示时按是。然后输入一个项目和包名称,例如org.spring.vault.example
.
然后将以下内容添加到pom.xml
dependencies 部分。
<dependencies>
<!-- other dependency elements omitted -->
<dependency>
<groupId>org.springframework.vault</groupId>
<artifactId>spring-vault-core</artifactId>
<version>3.0.4</version>
</dependency>
</dependencies>
如果您使用的是里程碑或候选版本,则还需要添加 Spring 的位置
里程碑存储库到您的 Mavenpom.xml
与您的同一级别<dependencies/>
元素。
<repositories>
<repository>
<id>spring-milestone</id>
<name>Spring Maven MILESTONE Repository</name>
<url>https://repo.spring.io/libs-milestone</url>
</repository>
</repositories>
存储库也可以在这里浏览。
如果您使用的是 SNAPSHOT,则还需要添加 Spring 的位置
快照存储库到您的 Mavenpom.xml
与您的同一级别<dependencies/>
元素。
<repositories>
<repository>
<id>spring-snapshot</id>
<name>Spring Maven SNAPSHOT Repository</name>
<url>https://repo.spring.io/snapshot</url>
</repository>
</repositories>
存储库也可以在这里浏览。
创建一个简单的Secrets
类以持久化:
package org.spring.vault.example;
public class Secrets {
String username;
String password;
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
}
以及要运行的主要应用程序
package org.springframework.vault.example;
public class VaultApp {
public static void main(String[] args) {
VaultTemplate vaultTemplate = new VaultTemplate(new VaultEndpoint(),
new TokenAuthentication("00000000-0000-0000-0000-000000000000"));
Secrets secrets = new Secrets();
secrets.username = "hello";
secrets.password = "world";
vaultTemplate.write("secret/myapp", secrets);
VaultResponseSupport<Secrets> response = vaultTemplate.read("secret/myapp", Secrets.class);
System.out.println(response.getData().getUsername());
vaultTemplate.delete("secret/myapp");
}
}
即使在这个简单的例子中,也没有什么需要注意的
-
您可以实例化 Spring Vault 的中心类,
VaultTemplate
,使用org.springframework.vault.client.VaultEndpoint
object 和ClientAuthentication
. 您无需启动 Spring Context 即可使用 Spring Vault。 -
Vault 应配置为
00000000-0000-0000-0000-000000000000
以运行此应用程序。 -
映射器适用于标准 POJO 对象,无需任何 其他元数据(尽管您可以选择提供该信息)。
-
映射约定可以使用字段访问。请注意
Secrets
类只有 getters。 -
如果构造函数参数名称与存储文档的字段名称匹配, 它们将用于实例化对象。
9. VaultTemplate简介
班级VaultTemplate
,位于包中org.springframework.vault.core
,
是 Spring 的 Vault 支持的核心类,提供丰富的功能集
与 Vault 交互。该模板提供了方便的读取、写入和作
删除 Vault 中的数据,并提供域对象与 Vault 数据之间的映射。
配置完成后,VaultTemplate 是线程安全的,可以跨多个实例。 |
Vault 文档和域类之间的映射是通过委托给RestTemplate
. Spring Web 支持提供了映射基础设施。
这VaultTemplate
class 实现接口VaultOperations
. 在尽可能多的方法中VaultOperations
以方法在 Vault API 上可用,以使现有 Vault 开发人员熟悉该 API习惯了 API 和 CLI。例如,您会找到诸如“write”、“delete”、“read”和“revoke”之类的方法。设计目标是尽可能轻松地在Vault API 和VaultOperations
. 之间的主要区别两个 API 是VaultOperations
可以传递域对象,而不是JSON 键值对。
引用VaultTemplate 实例
是通过其接口VaultOperations . |
虽然有很多方便的方法VaultTemplate
轻松帮助您
如果您需要直接访问 Vault API 才能访问,请执行常见任务
功能未由VaultTemplate
您可以使用以下选项之一
多个执行回调方法来访问底层 API。执行回调
将为您提供对RestOperations
对象。
有关更多信息,请参阅执行回调部分。
现在让我们看一个示例,了解如何在 Spring 容器的上下文中使用 Vault。
9.1. 注册和配置 Spring Vault Bean
使用 Spring Vault 不需要 Spring Context。但是,实例VaultTemplate
和SessionManager
在托管上下文中注册将参与
在 Spring IoC 容器提供的生命周期事件中。这对于在
应用程序关闭。您还可以从重复使用相同的VaultTemplate
实例。
Spring Vault 带有一个支持配置类,提供 bean 定义
在 Spring 上下文中使用。应用程序配置
类通常从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://localhost:8200 . |
2 | 此示例使用TokenAuthentication 快速入门。
有关支持的身份验证方法的详细信息,请参阅身份验证方法。 |
@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 . |
9.2. 会话管理
Spring Vault 需要一个ClientAuthentication
以登录并访问 Vault。
有关身份验证的详细信息,请参阅身份验证方法。
Vault 登录不应在每次经过身份验证的 Vault 交互时进行,但
必须在整个会话中重复使用。这方面由SessionManager
实现。一个SessionManager
决定它的频率
获取一个Tokens,关于撤销和续订。Spring Vault 带有两种实现:
-
SimpleSessionManager
:仅从提供的ClientAuthentication
无需刷新和吊销 -
LifecycleAwareSessionManager
:这SessionManager
schedules Tokens renew,如果Tokens是可续订的,并在处置时撤销登录Tokens。 续订计划时使用AsyncTaskExecutor
.LifecycleAwareSessionManager
如果使用AbstractVaultConfiguration
.
9.3. 使用EnvironmentVaultConfiguration
Spring Vault 包括EnvironmentVaultConfiguration
从 Spring 的Environment
和一组预定义的
属性键。EnvironmentVaultConfiguration
支持经常应用的配置。其他配置通过派生自最合适的配置类来支持。包括EnvironmentVaultConfiguration
跟@Import(EnvironmentVaultConfiguration.class)
到现有
基于 Java 的配置类,并通过任何 Spring 的PropertySource
s.
@PropertySource("vault.properties")
@Import(EnvironmentVaultConfiguration.class)
public class MyConfiguration{
}
vault.uri=https://localhost:8200
vault.token=00000000-0000-0000-0000-000000000000
属性键
-
保管库 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
,APPID
,APPROLE
,AWS_EC2
,AWS_IAM
,AZURE
,CERT
,CUBBYHOLE
,KUBERNETES
)
特定于身份验证的属性键
-
金库Tokens:
vault.token
-
AppId 路径:
vault.app-id.app-id-path
(默认为app-id
) -
应用 Id:
vault.app-id.app-id
-
用户 ID:
vault.app-id.user-id
.MAC_ADDRESS
和IP_ADDRESS
用MacAddressUserId
各自IpAddressUserId
用户 ID 机制。 任何其他值都与StaticUserId
.
-
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
(deprecated: 使用vault.aws-ec2.role
相反) -
身份证明文件网址:
vault.aws-ec2.identity-document
(默认为http://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
(默认为http://169.254.169.254/metadata/instance?api-version=2017-08-01
) -
身份Tokens服务 URL:
vault.azure-msi.identity-token-service
(默认为http://169.254.169.254/metadata/identity/oauth2/token?resource=https://vault.hashicorp.com&api-version=2018-02-01
)
没有配置选项。
-
初始金库Tokens:
vault.token
-
Kubernetes 路径:
vault.kubernetes.kubernetes-path
(默认为kubernetes
) -
角色:
vault.kubernetes.role
-
服务帐户Tokens文件的路径:
vault.kubernetes.service-account-token-file
(默认为/var/run/secrets/kubernetes.io/serviceaccount/token
)
9.4. 执行回调
所有 Spring 模板类的一个共同设计特征是所有功能都路由到模板执行回调方法之一。
这有助于确保执行异常和可能需要的任何资源管理的一致性。
虽然 JDBC 和 JMS 对此的需求比 Vault 大得多,但它仍然提供了一个访问和日志记录的位置。
因此,使用执行回调是访问 Vault API 的首选方式
执行我们未作为方法公开的不常见作VaultTemplate
.
下面是执行回调方法的列表。
-
<T> T
doWithVault(RestOperationsCallback<T> callback)
执行给定的RestOperationsCallback
,允许使用RestOperations
无需会话。 -
<T> T
doWith会话(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();
}
});
10. 支持 Vault 的秘密引擎
Spring Vault 附带了多个扩展来支持 Vault 的各种秘密引擎。
具体来说,Spring Vault 附带了以下扩展:
-
转换(企业功能)
-
系统后端
您可以通过以下方法使用所有其他后端VaultTemplate
直接 (VaultTemplate.read(…)
,VaultTemplate.write(…)
).
10.1. 键值版本 1(“未版本控制的密钥”)
这kv
secrets 引擎用于在为 Vault 配置的物理存储中存储任意密钥。
运行kv
secrets 引擎,仅保留密钥的最新写入值。
非版本控制 kv 的好处是减小了每个键的存储大小,因为不会存储额外的元数据或历史记录。
此外,发送到以这种方式配置的后端的请求性能更高,因为存储调用更少,并且任何给定请求都没有锁定。
Spring Vault 附带一个专用的键值 API,用于封装各个键值 API 实现之间的差异。VaultKeyValueOperations
遵循 Vault CLI 设计。
这是 Vault 的主要命令行工具,提供诸如vault kv get
,vault kv put
等等。
您可以通过指定版本和挂载路径,将此 API 与键值引擎版本一起使用。 以下示例使用键值版本 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
支持所有键值作,例如put
,get
,delete
,list
.
或者,可以通过VaultTemplate
由于其直接映射和简单使用,AS 键和响应直接映射到输入和输出键。
以下示例说明了在mykey
.
这kv
secrets 引擎安装在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 键值版本 1 API 的更多详细信息。
10.2. 键值版本 2(“版本化密钥”)
您可以运行kv
secrets 引擎中的两个版本之一。
本节介绍使用版本 2。当运行kv
后端密钥可以保留可配置数量的版本。
您可以检索旧版本的元数据和数据。
此外,您可以使用检查和设置作来避免无意中覆盖数据。
与键值版本 1(“未版本控制的密钥”)类似,Spring Vault 附带一个专用的键值 API,用于封装各个键值 API 实现之间的差异。
Spring Vault 附带一个专用的键值 API,用于封装各个键值 API 实现之间的差异。VaultKeyValueOperations
遵循 Vault CLI 设计。
这是 Vault 的主要命令行工具,提供诸如vault kv get
,vault kv put
,依此类推。
您可以通过指定版本和挂载路径,将此 API 与键值引擎版本一起使用。 以下示例使用键值版本 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
支持所有键值作,例如put
,get
,delete
,list
.
您还可以与版本化键值 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 | 版本化键值 API 允许检索由版本号标识的特定版本。 |
4 | 版本控制的键值密钥可以映射到值对象中。 |
5 | 使用 CAS 更新版本控制的密钥时,输入必须引用以前获取的版本。 |
使用kv
v2 secrets 引擎通过VaultTemplate
是可能的。
这不是最方便的方法,因为 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 键值版本 2 API 的更多详细信息。
10.3. PKI(公钥基础设施)
这pki
secrets 引擎通过实现证书颁发机构作来表示证书的后端。
PKI 机密引擎生成动态 X.509 证书。 使用此密钥引擎,服务可以获取证书,而无需经历通常的手动过程,即生成私钥和 CSR、提交给 CA 以及等待验证和签名过程完成。 Vault 的内置身份验证和授权机制提供了验证功能。
Spring Vault 支持通过VaultPkiOperations
.
所有其他 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 具有广泛的用途,这使得此格式适合配置(例如 HTTP 客户端、数据库驱动程序或 SSL 保护的 HTTP 服务器)。 |
4 | CertificateBundle 允许直接通过 Java Cryptography Extension API 访问私钥以及公共证书和颁发者证书。 |
5 | 一旦证书不再使用(或被泄露),您可以通过其序列号吊销它。 Vault 将吊销的证书包含在其 CRL 中。 |
您可以在 Vault 参考文档中找到有关 Vault PKI 密钥 API 的更多详细信息。
10.4. Tokens身份验证后端
此后端是一个身份验证后端,不与实际密钥交互。相反,它允许访问Tokens管理。您可以在身份验证方法一章中阅读有关基于Tokens的身份验证的更多信息。
这token
身份验证方法是内置的,并在/auth/token
. 它允许用户使用Tokens进行身份验证,以及创建新Tokens、按Tokens撤销机密等。
当任何其他身份验证方法返回身份时,Vault 核心会调用Tokens方法为该身份创建新的唯一Tokens。
您还可以使用Tokens存储绕过任何其他身份验证方法。您可以直接创建Tokens,也可以对Tokens执行各种其他作,例如续订和吊销。
Spring Vault 使用此后端来续订和撤销配置的身份验证方法提供的会话Tokens。
以下示例演示了如何从应用程序中请求、续订和撤销 Vault Tokens:
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 | 通过应用角色默认值创建Tokens。 |
2 | 使用构建器 API,您可以为要请求的Tokens定义细粒度设置。
请求Tokens将返回一个VaultToken ,用作 Vault Tokens的值对象。 |
3 | 您可以通过Tokens API 续订Tokens。通常,这是通过SessionManager 以跟踪 Vault 会话Tokens。 |
4 | 如果需要,可以通过Tokens API 撤销Tokens。通常,这是通过SessionManager 以跟踪 Vault 会话Tokens。 |
您可以在 Vault 参考文档中找到有关 Vault Tokens身份验证方法 API 的更多详细信息。
10.5. 传输后端
传输密钥引擎处理传输中数据的加密功能。 Vault 不存储发送到此密钥引擎的数据。 也可以看作是“密码即服务”或“加密即服务”。 传输机密引擎还可以对数据进行签名和验证,生成数据的哈希值和 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 | 接下来,我们将String 包含应加密的纯文本。
输入String 使用默认的Charset 将字符串编码为其二进制表示形式。
请求Tokens将返回一个VaultToken ,用作 Vault Tokens的值对象。 这encrypt 方法返回 Base64 编码的密文,通常以vault: . |
3 | 要将密文解密为纯文本,请调用decrypt 方法。
它解密密文并返回一个String 使用默认字符集进行解码。 |
前面的示例使用简单的字符串进行加密作。虽然这是一种简单的方法,但它存在字符集配置错误的风险,并且不是二进制安全的。当纯文本对图像、压缩数据或二进制数据结构等数据使用二进制表示时,需要二进制安全。
要加密和解密二进制数据,请使用Plaintext
和Ciphertext
value 对象,可以保存二进制值:
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 object 可以直接用于解密,并返回一个Plaintext 对象。 |
Plaintext
和Ciphertext
带有上下文对象,VaultTransitContext
. 它用于为收敛加密提供随机数值,并为上下文值提供使用密钥派生。
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 | 为纯文本消息创建签名。返回的Signature 包含使用 Base64 字符的 ASCII 安全字符串。 |
3 | 若要验证签名,验证需要 Signature 对象和纯文本消息。作为返回值,您可以获取签名是否有效。 |
您可以在 Vault 参考文档中找到有关 Vault Transit 后端的更多详细信息。
11. ReactiveVaultTemplate 简介
本节介绍有关使用 Spring Vault 的响应式编程支持的基本信息。
11.1. 什么是响应式编程?
简单来说,响应式编程是关于非阻塞应用程序,这些应用程序是 异步和事件驱动,需要少量线程才能垂直扩展 (即在 JVM 内)而不是水平(即通过聚类)。
响应式应用的一个关键方面是背压的概念,这是一种机制 以确保生产者不会压垮消费者。例如,在响应式管道中 当 HTTP 连接 太慢的数据存储库也会变慢或完全停止,直到网络容量释放。
11.2. 响应式 Vault 客户端
Spring Vault 的响应式客户端支持建立在可组合的身份验证步骤和 Spring 的功能之上WebClient
通过 Reactor Netty 或 Jetty,它们都具有完全非阻塞、事件驱动的 HTTP 客户端。
它暴露了VaultTokenSupplier
作为提供商VaultToken
对 HTTP 请求进行身份验证
和ReactiveVaultOperations
作为主要入口点。的核心配置VaultEndpoint
,ClientOptions
和 SSL 在
各种客户端实现。
班级ReactiveVaultTemplate
,位于包中org.springframework.vault.core
,
是 Spring 响应式 Vault 支持的核心类,提供丰富的功能集
与 Vault 交互。该模板提供了方便的读取、写入和作
删除 Vault 中的数据,并提供域对象与 Vault 数据之间的映射。
配置完成后,ReactiveVaultTemplate 是线程安全的,可以跨多个实例。 |
Vault 文档和域类之间的映射是通过委托给WebClient
及其编解码器。
这ReactiveVaultTemplate
class 实现接口ReactiveVaultOperations
. 在尽可能多的方法中ReactiveVaultOperations
以方法命名
在 Vault API 上可用,以使现有 Vault 开发人员熟悉该 API
他们习惯了 API 和 CLI。例如,您会发现诸如
“写入”、“删除”和“读取”。
设计目标是尽可能轻松地在
Vault API 的使用和ReactiveVaultOperations
. 之间的主要区别两个 API 是ReactiveVaultOperations
可以传递域对象,而不是JSON 键值对。
引用ReactiveVaultTemplate 实例
是通过其接口ReactiveVaultOperations . |
未显式公开的功能ReactiveVaultTemplate
您可以使用以下选项之一
多个执行回调方法来访问底层 API。执行回调
将为您提供对WebClient
对象。
有关更多信息,请参阅执行回调部分。
现在让我们看一个示例,了解如何在 Spring 容器的上下文中使用 Vault。
11.3. 注册和配置 Spring Vault Bean
使用 Spring Vault 不需要 Spring Context。但是,实例ReactiveVaultTemplate
和VaultTokenSupplier
在托管上下文中注册将参与
在 Spring IoC 容器提供的生命周期事件中。这对于在
应用程序关闭。您还可以从重复使用相同的ReactiveVaultTemplate
实例。
Spring Vault 带有一个支持配置类,提供 bean 定义
在 Spring 上下文中使用。应用程序配置
类通常从AbstractVaultConfiguration
并且必须
提供特定于环境的其他详细信息。
扩展自AbstractVaultConfiguration
需要实现
' VaultEndpoint vaultEndpoint()' 和ClientAuthentication clientAuthentication()
方法。
@Configuration
public class AppConfig extends AbstractReactiveVaultConfiguration {
/**
* 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://localhost:8200 . |
2 | 此示例使用TokenAuthentication 快速入门。
有关支持的身份验证方法的详细信息,请参阅身份验证方法。 |
11.5. 执行回调
所有 Spring 模板类的一个共同设计特征是所有功能
路由到模板执行回调方法之一。这有助于确保
执行异常和可能需要的任何资源管理
一致性。虽然在 JDBC 和 JMS 的情况下,这更需要
与 Vault 相比,它仍然提供一个访问和日志记录的位置。
因此,使用执行回调是访问 Vault API 的首选方式
执行我们未作为方法公开的不常见作ReactiveVaultTemplate
.
下面是执行回调方法的列表。
-
<T> T
doWithVault(Function<WebClient, ? extends T> clientCallback)
组成一个响应式 对给定的WebClient
,允许在没有会话上下文的情况下与 Vault 进行交互。 -
<T> T
doWith会话(Function<WebClient, ? extends T> clientCallback)
组成一个响应式 对给定的WebClient
,允许在经过身份验证的会话中与 Vault 进行交互。
下面是一个使用回调初始化 Vault 的示例:
reactiveVaultOperations.doWithVault(webClient -> {
return webClient.put()
.uri("/sys/init")
.syncBody(request)
.retrieve()
.toEntity(VaultInitializationResponse.class);
});
12. Vault 属性源支持
Vault 可以以多种不同的方式使用。一个特定的用例是使用 Vault 以存储加密属性。Spring Vault 支持 Vault 作为属性 source 使用 Spring 的 PropertySource 抽象获取配置属性。
您可以在其他属性源中引用存储在 Vault 中的属性,也可以将值注入与@Value(…) .引导需要存储在 Vault 内部的数据的 Bean 时需要特别注意。一个VaultPropertySource 必须在该时初始化才能从 Vault 检索属性。 |
Spring Boot/Spring Cloud 用户可以从 Spring Cloud Vault 的 在应用程序启动期间初始化各种属性源的配置集成。 |
12.1. 注册VaultPropertySource
Spring Vault 提供了一个VaultPropertySource
与 Vault 一起使用以获取
性能。它使用嵌套的data
元素来公开存储的属性和
在 Vault 中加密。
ConfigurableApplicationContext ctx = new GenericApplicationContext();
MutablePropertySources sources = ctx.getEnvironment().getPropertySources();
sources.addFirst(new VaultPropertySource(vaultTemplate, "secret/my-application"));
在上面的代码中,VaultPropertySource
已以最高优先级添加
在搜索中。如果它包含“foo”属性,则将检测并返回它
领先于任何foo
属性PropertySource
.MutablePropertySources
公开了许多允许精确
对属性源集的作。
12.2. @VaultPropertySource
这@VaultPropertySource
注释提供了方便的声明性
添加PropertySource
到 Spring 的Environment
与@Configuration
类。
@VaultPropertySource
采用 Vault 路径,例如secret/my-application
并将存储在节点上的数据公开在PropertySource
.@VaultPropertySource
支持与租约关联的机密的租约续订
(即来自mysql
backend)和终端上的凭证轮换
租约到期。默认情况下,租约续订处于禁用状态。
{
// …
"data": {
"database": {
"password": ...
},
"user.name": ...,
}
// …
}
@VaultPropertySource
@Configuration
@VaultPropertySource("secret/my-application")
public class AppConfig {
@Autowired Environment env;
@Bean
public TestBean testBean() {
TestBean testBean = new TestBean();
testBean.setUser(env.getProperty("user.name"));
testBean.setPassword(env.getProperty("database.password"));
return testBean;
}
}
@VaultPropertySource
使用凭据轮换和前缀@Configuration
@VaultPropertySource(value = "aws/creds/s3-access",
propertyNamePrefix = "aws.",
renewal = Renewal.ROTATE)
public class AppConfig {
// provides aws.access_key and aws.secret_key properties
}
从中获得的秘密generic 秘密后端与 TTL (refresh_interval ),但不是租约 Id。Spring Vault 的PropertySource 在达到其 TTL 时轮换通用密钥。 |
您可以使用@VaultPropertySource 从版本控制的键值后端获取最新的机密版本。确保不包含data/ 路径中的段。 |
任何${…}
占位符@VaultPropertySource
path 是针对已针对环境注册的属性源集进行解析的,如以下示例所示:
@VaultPropertySource
使用占位符的路径@Configuration
@VaultPropertySource(value = "aws/creds/${my.placeholder:fallback/value}",
propertyNamePrefix = "aws.",
renewal = Renewal.ROTATE)
public class AppConfig {
}
假设my.placeholder
存在于已注册的属性源之一(例如,系统属性或环境变量)中,则占位符将解析为相应的值。
如果没有,那么fallback/value
用作默认值。
如果未指定默认值并且无法解析属性,则IllegalArgumentException
被抛出。
在某些情况下,严格控制可能是不可能的,也不切实际的
使用时的属性源排序@VaultPropertySource
附注。
例如,如果@Configuration
上述课程是通过
组件扫描,顺序难以预测。
在这种情况下,如果覆盖很重要,建议将
用户回退到使用编程 PropertySource API。
看ConfigurableEnvironment
和MutablePropertySources
了解详情。
13. Vault 存储库
使用VaultTemplate
映射到 Java 类的响应允许读取、写入和删除等基本数据作。
Vault 存储库在 Vault 之上应用了 Spring Data 的存储库概念。
Vault 存储库公开了基本的 CRUD 功能,并支持使用约束标识符属性、分页和排序的谓词进行查询派生。
保管库存储库使用键/值机密引擎功能来保存和查询数据。
从版本 2.4 开始,Spring Vault 还可以使用键/值版本 2 密钥引擎,实际的密钥引擎版本是在运行时发现的。
版本控制的键/值密钥引擎中的删除使用DELETE 操作。机密不会通过CrudRepository.delete(…) . |
在 Spring Data Commons 参考文档中阅读有关 Spring Data Repositories 的更多信息。 参考文档将向您介绍 Spring Data 存储库。 |
13.1. 用法
要访问存储在 Vault 中的域实体,您可以利用存储库支持来显着简化这些实体的实现。
@Secret
class Credentials {
@Id String id;
String password;
String socialSecurityNumber;
Address address;
}
我们这里有一个非常简单的域对象。
请注意,它有一个名为id
注释为org.springframework.data.annotation.Id
和@Secret
注释。
这两个负责创建用于在 Vault 中将对象作为 JSON 持久化的实际密钥。
用@Id 以及那些被命名的id 被视为标识符属性。
那些有注释的人比其他人更受青睐。 |
下一步是声明使用域对象的存储库接口。
Credentials
实体interface CredentialsRepository extends CrudRepository<Credentials, String> {
}
随着我们的存储库的扩展CrudRepository
它提供了基本的 CRUD 和查询方法。
Vault 存储库需要 Spring Data 组件。
确保包括spring-data-commons
和spring-data-keyvalue
项目。
实现此目的的最简单方法是设置依赖项管理并将工件添加到pom.xml
:
然后将以下内容添加到pom.xml
dependencies 部分。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-bom</artifactId>
<version>2022.0.8</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.0.4</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 | 计算由@Secret 上Credentials . |
4 | 从 Vault 中删除给定对象的键。 |
13.2. 对象到Vault JSON映射
Vault 存储库使用 JSON 作为交换格式将对象存储在 Vault 中。
JSON 和实体之间的对象映射由VaultConverter
.
转换器读写SecretDocument
包含来自VaultResponse
.VaultResponse
s 从 Vault 中读取,并且 Jackson 将正文反序列化为Map
之String
和Object
.
默认值VaultConverter
实现读取Map
嵌套值,List
和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 . |
类型 | 样本 | 映射值 |
---|---|---|
简单类型 |
字符串 firstname = “Walter”; |
“firstname”: “沃尔特” |
复杂类型 |
地址地址 = 新地址(“308 Negra Arroyo Lane”); |
“地址”: { “street”: “内格拉阿罗约巷 308 号” } |
简单类型列表 |
List<String>昵称 = asList(“walt”, “heisenberg”); |
“昵称”: [“沃尔特”、“海森堡”] |
简单类型的地图 |
Map<String, Integer> atts = asMap(“age”, 51) |
“atts” : {“年龄” : 51} |
复杂类型列表 |
List<Address> 地址 = asList(new Address(“308... |
“地址”: [{ “street”: “308 Negra Arroyo Lane” }, ...] |
您可以通过注册Converter
在VaultCustomConversions
.
这些转换器可以负责从/转换为类型,例如LocalDate
以及SecretDocument
而第一个适用于将简单属性转换为简单属性,最后一个则适合将复杂类型转换为其 JSON 表示形式。
第二个选项提供对结果的完全控制SecretDocument
.
将对象写入Vault
将删除内容并重新创建整个条目,因此未映射的数据将丢失。
13.3. 查询和查询方法
查询方法允许从方法名称自动派生简单查询。 Vault 没有查询引擎,但需要直接访问 HTTP 上下文路径。 Vault 查询方法将 Vault 的 API 可能性转换为查询。 查询方法执行在上下文路径下列出子项,对 Id 应用筛选,(可选)使用偏移量/限制限制 Id 流,并在提取结果后应用排序。
interface CredentialsRepository extends CrudRepository<Credentials, String> {
List<Credentials> findByIdStartsWith(String prefix);
}
Vault 存储库的查询方法仅支持对@Id 财产。 |
以下是 Vault 支持的关键字的概述。
关键词 | 样本 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13.3.1. 排序和分页
查询方法通过在内存中选择从 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);
}
13.4. 乐观锁定
保管库密钥/值机密引擎版本 2 可以维护版本控制的机密。
Spring Vault 支持通过域模型中的版本属性进行版本控制,这些属性带有@Version
.
使用乐观锁定可确保更新仅应用于具有匹配版本的机密。
因此,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 | 更新使用先前版本的第二个实例。
该作失败,并显示OptimisticLockingFailureException 同时,该版本在 Vault 中递增。 |
删除版本化密钥时,按 Id 删除会删除最新的密钥。按实体删除 删除所提供版本的机密。 |
13.5. 访问版本控制的密钥
键/值版本 2 机密引擎维护可通过实现RevisionRepository
在 Vault 存储库界面声明中。
修订存储库定义查找方法以获取特定标识符的修订。
标识符必须是String
.
RevisionRepository
interface RevisionCredentialsRepository extends CrudRepository<Credentials, String>,
RevisionRepository<Credentials, String, Integer> (1)
{
}
1 | 第一个类型参数 (Credentials ) 表示实体类型,第二个 (String ) 表示 id 属性的类型,最后一个 (Integer ) 是修订号的类型。Vault 仅支持String identifiers 和Integer 修订号。 |
13.5.1. 用法
您现在可以使用RevisionRepository
查询实体的修订,如以下示例所示:
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));
14. 客户支持
Spring Vault 支持各种 HTTP 客户端访问 Vault 的 HTTP API。Spring Vault 使用RestTemplate
作为访问 Vault 的主接口。
专用客户端支持源自自定义的 SSL 配置,该配置仅限于 Spring Vault 的客户端组件。
Spring Vault 支持以下 HTTP 命令式客户端:
-
Java 的内置
HttpURLConnection
(如果没有其他客户端可用,则默认客户端) -
Apache Http 组件
-
好的Http 3
Spring Vault 的响应式集成支持以下响应式 HTTP 客户端:
-
Java 内置的响应式
HttpClient
(如果没有其他客户端可用,则默认客户端) -
反应器网
-
Apache Http 组件
-
Jetty
使用特定客户端需要相应的依赖关系在类路径上可用 因此,Spring Vault 可以使用可用的客户端与 Vault 进行通信。
14.1. Java 的内置HttpURLConnection
Java 的内置HttpURLConnection
开箱即用,无需额外
配置。用HttpURLConnection
带有有关 SSL 配置的限制。
Spring Vault 不会像以前那样应用自定义的 SSL 配置
需要对 JVM 进行深度重新配置。此配置将影响所有
组件依赖于默认 SSL 上下文。使用HttpURLConnection
要求您将这些设置作为系统属性提供。有关更多详细信息,请参阅自定义 JSSE。
14.2. 外部客户端
您可以使用外部客户端访问 Vault 的 API。只需添加以下内容之一 依赖项。如果使用 Spring Vault 的依赖项 BOM,则可以省略版本号
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
</dependency>
Apache HttpClient 的线路日志可以通过日志记录配置来启用。确保不要意外启用有线日志记录,因为日志可能会以纯文本形式暴露应用程序和 Vault 之间的流量(Tokens和密钥)。 |
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor.netty</groupId>
<artifactId>reactor-netty</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.core5</groupId>
<artifactId>httpcore5-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-reactive-httpclient</artifactId>
</dependency>
14.3. Vault 客户端 SSL 配置
SSL 可以使用SslConfiguration
通过设置各种属性。
您可以设置javax.net.ssl.trustStore
配置
JVM 范围的 SSL 设置或配置SslConfiguration
仅为 Spring Vault 设置 SSL 设置。
SslConfiguration sslConfiguration = SslConfiguration.create( (1)
new FileSystemResource("client-cert.jks"), "changeit".toCharArray(),
new FileSystemResource("truststore.jks"), "changeit".toCharArray());
SslConfiguration.forTrustStore(new FileSystemResource("keystore.jks"), (2)
"changeit".toCharArray())
SslConfiguration.forKeyStore(new FileSystemResource("keystore.jks"), (3)
"changeit".toCharArray())
SslConfiguration.forKeyStore(new FileSystemResource("keystore.jks"), (4)
"changeit".toCharArray(),
KeyConfiguration.of("key-password".toCharArray(),
"my-key-alias"))
1 | 完整配置。 |
2 | 仅配置信任存储设置。 |
3 | 仅配置密钥存储设置。 |
4 | 仅配置密钥存储设置,并提供密钥配置。 |
请注意,提供SslConfiguration
只能在 Apache Http 组件或 OkHttp 客户端位于您的类路径上时应用。
SSL 配置还支持 PEM 编码的证书,作为 Java 密钥库的替代方案。
KeyStoreConfiguration keystore = KeyStoreConfiguration
.of(new ClassPathResource("ca.pem")).withStoreType("PEM");
SslConfiguration configuration = SslConfiguration.forTrustStore(keystore);
PEM 文件可能包含一个或多个证书(-----BEGIN CERTIFICATE-----
和-----END CERTIFICATE-----
).
添加到基础KeyStore
使用完整的主题名称作为别名。
15. 认证方法
不同的组织对安全有不同的要求 和身份验证。Vault 通过提供多重身份验证来反映这一需求 方法。Spring Vault 支持多种身份验证机制。
15.1. 外部化登录凭证
首次访问安全系统称为安全引入。 任何客户端都需要临时或永久凭据才能访问 Vault。外部化凭据 是保持高代码可维护性的良好模式,但存在增加披露的风险。
向任何一方披露登录凭据允许登录 Vault 并访问 由基础角色允许。选择适当的客户端身份验证和 将凭据注入应用程序需要进行风险评估。
Spring 的 PropertySource 抽象是自然而然的 将配置保留在应用程序代码之外。您可以使用系统属性、环境 变量或属性文件来存储登录凭据。每种方法都有自己的属性。 请记住,命令行和环境属性可以使用适当的 作系统访问级别。
vault.token
到属性文件@PropertySource("configuration.properties")
@Configuration
public class Config extends AbstractVaultConfiguration {
@Override
public ClientAuthentication clientAuthentication() {
return new TokenAuthentication(getEnvironment().getProperty("vault.token"));
}
}
Spring 允许多种方式获取Environment .使用时VaultPropertySource ,注射通过@Autowired Environment environment 不会提供Environment 由于环境 Bean 仍在建设中,自动布线是在后期阶段进行的。您的配置类应该实现ApplicationContextAware 并获取Environment 从ApplicationContext . |
看SecurePropertyUsage.java
有关引用组件和其他属性源中的属性的示例。
15.2. Tokens身份验证
Tokens是 Vault 中身份验证的核心方法。 Tokens身份验证需要提供静态Tokens。
Tokens身份验证是默认的身份验证方法。 如果Tokens被披露为非预期方,则该Tokens将获得对 Vault 的访问权限,并且 可以访问目标客户端的密钥。 |
通常,Tokens身份验证用于创建和续订Tokens的方案
外部(例如 HashiCorp Vault 服务代理)。
根据实际设置,您可能希望也可能不需要Tokens续订和吊销。
看LifecycleAwareSessionManager
有关 TTL 和Tokens吊销的详细信息。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
return new TokenAuthentication("…");
}
// …
}
另见:
15.3. AppId 身份验证
Vault 已弃用 AppId 身份验证。请改用 AppRole 身份验证。 |
Vault 支持 AppId 身份验证,该身份验证由两个难以猜测的Tokens组成。The AppId
默认为spring.application.name
这是静态配置的。
第二个Tokens是 UserId,它是由应用程序确定的部分,
通常与运行时环境有关。IP 地址、Mac 地址或
Docker 容器名称就是很好的例子。Spring Vault 支持
IP 地址、Mac 地址和静态 UserId(例如通过系统属性提供)。
IP 和 Mac 地址表示为十六进制编码的 SHA256 哈希值。
基于 IP 地址的用户 ID 使用本地主机的 IP 地址。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
AppIdAuthenticationOptions options = AppIdAuthenticationOptions.builder()
.appId("myapp")
.userIdMechanism(new IpAddressUserId())
.build();
return new AppIdAuthentication(options, restOperations());
}
// …
}
从命令行生成 IP 地址 UserId 的相应命令是:
$ echo -n 192.168.99.1 | sha256sum
包括echo 导致不同的哈希值
因此,请确保包含-n 旗。 |
基于 Mac 地址的 UserId 从
localhost 绑定设备。该配置还允许指定
一个network-interface
提示选择正确的设备。的值network-interface
是可选的,可以是接口
名称或接口索引(从 0 开始)。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
AppIdAuthenticationOptions options = AppIdAuthenticationOptions.builder()
.appId("myapp")
.userIdMechanism(new MacAddressUserId())
.build();
return new AppIdAuthentication(options, restOperations());
}
// …
}
从命令行生成 Mac 地址 UserId 的相应命令是:
$ echo -n 0AFEDE1234AC | sha256sum
Mac 地址指定为大写,不带冒号。
包括echo 导致不同的哈希值
因此,请确保包含-n 旗。 |
15.3.1. 自定义用户 ID
更高级的方法允许您实现自己的AppIdUserIdMechanism
.
此类必须位于您的类路径上,并且必须实现
这org.springframework.vault.authentication.AppIdUserIdMechanism
接口
和createUserId
方法。Spring Vault 将获取 UserId
通过调用createUserId
每次使用 AppId 进行身份验证时,它都会使用
获取Tokens。
public class MyUserIdMechanism implements AppIdUserIdMechanism {
@Override
public String createUserId() {
String userId = …
return userId;
}
}
15.4. AppRole 身份验证
AppRole 允许计算机 身份验证,就像已弃用的(自 Vault 0.6.1 起)AppId 身份验证一样。 AppRole 身份验证由两个难以猜测的(机密)Tokens组成:RoleId 和 SecretId。
Spring Vault 通过仅提供 RoleId 来支持 AppRole 身份验证 或与提供的 SecretId 一起,并从 Vault 获取 RoleId/SecretId (推拉模式,响应展开)。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
AppRoleAuthenticationOptions options = AppRoleAuthenticationOptions.builder()
.roleId(RoleId.provided("…"))
.secretId(SecretId.wrapped(VaultToken.of("…")))
.build();
return new AppRoleAuthentication(options, restOperations());
}
// …
}
Spring Vault 还支持全拉模式:如果未提供 RoleId 和 SecretId, Spring Vault 将使用角色名称和初始Tokens检索它们。这 初始Tokens可能与 TTL 和使用限制相关联。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
VaultToken initialToken = VaultToken.of("…");
AppRoleAuthenticationOptions options = AppRoleAuthenticationOptions.builder()
.appRole("…")
.roleId(RoleId.pull(initialToken))
.secretId(SecretId.pull(initialToken))
.build();
return new AppRoleAuthentication(options, restOperations());
}
// …
}
15.5. AWS-EC2 身份验证
aws-ec2 auth 后端提供安全的引入机制 对于 AWS EC2 实例,允许自动检索 Vault Tokens。与大多数 Vault 身份验证后端不同,此后端 不需要首次部署或配置安全敏感型 凭据(Tokens、用户名/密码、客户端证书等)。 相反,它将 AWS 视为受信任的第三方,并使用 加密签名的动态元数据信息,唯一的 表示每个 EC2 实例。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
return new AwsEc2Authentication(restOperations());
}
// …
}
AWS-EC2 身份验证默认情况下允许随机数遵循 首次使用时信任 (TOFU) 原则。任何意外的一方 获得对 PKCS#7 身份元数据的访问权限可以进行身份验证 反对 Vault。
在第一次登录期间,Spring Vault 会生成一个随机数 存储在实例 ID 旁边的身份验证后端中。 重新身份验证需要发送相同的随机数。任何其他 party 没有随机数,并且可以在 Vault 中针对 进一步调查。
随机数保存在内存中,并在应用程序重新启动期间丢失。
AWS-EC2 身份验证角色是可选的,默认为 AMI。
您可以通过设置
它AwsEc2AuthenticationOptions
.
15.6. AWS-IAM 身份验证
aws auth 后端允许使用现有的 AWS IAM 凭证登录 Vault。
AWS IAM 身份验证会创建一个签名的 HTTP 请求,该请求是
由 Vault 执行,以使用 AWS STS 获取签名者的身份GetCallerIdentity
方法。AWSv4 签名需要 IAM 凭证。
可以从任一运行时环境中获取 IAM 凭证 或外部供应。运行时环境,例如 AWS-EC2、 分配了 IAM 主体的 Lambda 和 ECS 不需要特定于客户端 凭据的配置,但可以从其元数据源获取这些凭据。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
AwsIamAuthenticationOptions options = AwsIamAuthenticationOptions.builder()
.credentials(new BasicAWSCredentials(…)).build();
return new AwsIamAuthentication(options, restOperations());
}
// …
}
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
AwsIamAuthenticationOptions options = AwsIamAuthenticationOptions.builder()
.credentialsProvider(InstanceProfileCredentialsProvider.getInstance()).build();
return new AwsIamAuthentication(options, restOperations());
}
// …
}
AwsIamAuthentication
需要 AWS Java SDK 依赖项 (com.amazonaws:aws-java-sdk-core
)
因为身份验证实施使用 AWS SDK 类型进行凭证和请求签名。
您可以通过以下方式配置身份验证AwsIamAuthenticationOptions
.
另见:
15.7. Azure (MSI) 身份验证
Azure 身份验证后端提供安全的引入机制 对于 Azure VM 实例,允许自动检索保管库 Tokens。与大多数 Vault 身份验证后端不同,此后端 不需要首次部署或配置安全敏感型 凭据(Tokens、用户名/密码、客户端证书等)。 相反,它将 Azure 视为受信任的第三方,并使用 托管服务标识和实例元数据信息,可以是 绑定到 VM 实例。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
AzureMsiAuthenticationOptions options = AzureMsiAuthenticationOptions.builder()
.role(…).build();
return new AzureMsiAuthentication(options, restOperations());
}
// …
}
Azure 身份验证需要有关 VM 环境的详细信息(订阅 ID、
资源组名称、VM 名称)。这些详细信息可以通过AzureMsiAuthenticationOptionsBuilder
.
如果未配置,AzureMsiAuthentication
将 Azure 的实例元数据服务查询到
获取这些详细信息。
另见:
15.8. GCP-GCE 身份验证
gcp 身份验证后端允许使用现有的 GCP (Google Cloud Platform) IAM 和 GCE 凭据登录 Vault。
GCP GCE(Google Compute Engine)身份验证会以JSON Web Tokens (JWT) 的形式为服务帐号创建签名。Compute Engine 实例的 JWT是使用实例标识从 GCE 元数据服务获取的。此 API 会创建一个 JSON Web Tokens,可用于确认实例身份。
与大多数保管库身份验证后端不同,此后端不需要首次部署或配置安全敏感的凭据(Tokens、用户名/密码、客户端证书等)。相反,它将 GCP 视为受信任的第三方,并使用加密签名的动态元数据信息,这些信息唯一代表每个 GCP 服务帐户。
您可以通过以下方式配置身份验证GcpComputeAuthenticationOptions
.
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
GcpComputeAuthenticationOptions options = GcpComputeAuthenticationOptions.builder()
.role(…).build();
GcpComputeAuthentication authentication = new GcpComputeAuthentication(options,
restOperations());
}
// …
}
另见:
15.9. GCP-IAM 身份验证
gcp 身份验证后端允许使用现有的 GCP (Google Cloud Platform) IAM 和 GCE 凭据登录 Vault。
GCP IAM 身份验证以 JSON Web Tokens (JWT) 的形式创建签名
对于服务帐户。服务帐户的 JWT 由以下方式获取
调用 GCP IAMprojects.serviceAccounts.signJwt
应用程序接口。调用方针对 GCP IAM 进行身份验证
并由此证明其身份。此 Vault 后端将 GCP 视为受信任的第三方。
可以从任一运行时环境中获取 IAM 凭证
或作为e.g. JSON从外部供应。JSON 是首选形式,因为它
携带调用所需的项目 ID 和服务帐户标识符projects.serviceAccounts.signJwt
.
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
GcpIamCredentialsAuthenticationOptions options = GcpIamCredentialsAuthenticationOptions.builder()
.role(…).credential(GoogleCredentials.getApplicationDefault()).build();
GcpIamCredentialsAuthentication authentication = new GcpIamCredentialsAuthentication(options,
restOperations());
}
// …
}
GcpIamCredentialsAuthenticationOptions
需要 Google Cloud Java SDK 依赖项
(com.google.cloud:google-cloud-iamcredentials
)
因为身份验证实现使用 Google API 进行凭据和 JWT 签名。
您可以通过以下方式配置身份验证GcpIamCredentialsAuthenticationOptions
.
Google 凭据需要 OAuth 2 Tokens来维护Tokens生命周期。所有 API
因此是同步的,GcpIamCredentialsAuthentication 不支持AuthenticationSteps 这是
需要被动使用。 |
GcpIamCredentialsAuthentication 使用 IAM 凭证 API,并且是使用GcpIamAuthentication 使用已弃用的 IAM API。 |
另见:
15.10. PCF 身份验证
pcf 身份验证后端允许 PCF 实例的 Vault 登录。 它利用 PCF 的应用程序和容器身份保证。
PCF 身份验证使用实例密钥和证书创建由 Vault 验证的签名。 如果签名匹配,并且可能绑定组织/空间/应用程序 ID 匹配,Vault 将颁发适当范围的Tokens。
实例凭据可从以下文件中获得:CF_INSTANCE_CERT
和CF_INSTANCE_KEY
变量。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
PcfAuthenticationOptions options = PcfAuthenticationOptions.builder()
.role(…).build();
PcfAuthentication authentication = new PcfAuthentication(options,
restOperations());
}
// …
}
PcfAuthenticationOptions
需要 BouncyCastle 库来创建 RSA-PSS 签名。
您可以通过以下方式配置身份验证PcfAuthenticationOptions
.
另见:
15.11. TLS 证书身份验证
这cert
身份验证后端允许使用 SSL/TLS 客户端进行身份验证
由 CA 签名或自签名的证书。
启用cert
身份验证,您需要:
-
使用 SSL,请参见 Vault 客户端 SSL 配置
-
配置 Java
Keystore
包含客户端 证书和私钥
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
ClientCertificateAuthenticationOptions options = ClientCertificateAuthenticationOptions.builder()
.path(…).build();
return new ClientCertificateAuthentication(options, restOperations());
}
// …
}
另请参阅:Vault 文档:使用证书身份验证后端
15.12. Cubbyhole 身份验证
Cubbyhole 身份验证使用 Vault 基元提供安全身份验证
工作流程。Cubbyhole 身份验证使用Tokens作为主要登录方法。
临时Tokens用于从 Vault 的
Cubbyhole 秘密后端。登录Tokens的寿命通常较长,并且用于
与 Vault 交互。登录Tokens可以从包装的
响应或来自data
部分。
创建包装Tokens
用于创建Tokens的响应包装需要 Vault 0.6.0 或更高版本。 |
$ vault token-create -wrap-ttl="10m"
Key Value
--- -----
wrapping_token: 397ccb93-ff6c-b17b-9389-380b01ca2645
wrapping_token_ttl: 0h10m0s
wrapping_token_creation_time: 2016-09-18 20:29:48.652957077 +0200 CEST
wrapped_accessor: 46b6aebb-187f-932a-26d7-4f3d86a68319
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
CubbyholeAuthenticationOptions options = CubbyholeAuthenticationOptions
.builder()
.initialToken(VaultToken.of("…"))
.wrapped()
.build();
return new CubbyholeAuthentication(options, restOperations());
}
// …
}
使用存储的Tokens
$ vault token create
Key Value
--- -----
token f9e30681-d46a-cdaf-aaa0-2ae0a9ad0819
token_accessor 4eee9bd9-81bb-06d6-af01-723c54a72148
token_duration 0s
token_renewable false
token_policies [root]
$ vault token create -use-limit=2 -orphan -no-default-policy -policy=none
Key Value
--- -----
token 895cb88b-aef4-0e33-ba65-d50007290780
token_accessor e84b661c-8aa8-2286-b788-f258f30c8325
token_duration 0s
token_renewable false
token_policies [none]
$ export VAULT_TOKEN=895cb88b-aef4-0e33-ba65-d50007290780
$ vault write cubbyhole/token token=f9e30681-d46a-cdaf-aaa0-2ae0a9ad0819
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
CubbyholeAuthenticationOptions options = CubbyholeAuthenticationOptions
.builder()
.initialToken(VaultToken.of("…"))
.path("cubbyhole/token")
.build();
return new CubbyholeAuthentication(options, restOperations());
}
// …
}
剩余 TTL/可续订性
从 Cubbyhole 检索到的与非零 TTL 关联的Tokens从 Tokens创建时间。该时间不一定与申请相同 启动。为了补偿初始延迟,Cubbyhole 身份验证执行 自查找与非零 TTL 关联的Tokens,以检索剩余的 TTL。 Cubbyhole 身份验证不会在没有 TTL 的情况下自查找包装的Tokens,因为 零 TTL 表示没有关联的 TTL。
非包装Tokens不提供有关可续订性和 TTL 的详细信息,仅 检索Tokens。自查找将查找可续订性和剩余 TTL。
另见:
15.13. Kubernetes 身份验证
Vault 从 0.8.3 开始支持使用 Kubernetes Tokens进行基于 Kubernetes 的身份验证。
使用 Kubernetes 身份验证需要 Kubernetes 服务帐户Tokens,
通常安装在/var/run/secrets/kubernetes.io/serviceaccount/token
.
该文件包含读取并发送到 Vault 的Tokens。
Vault 在登录期间使用 Kubernetes 的 API 验证其有效性。
配置 Kubernetes 身份验证至少需要提供角色名称:
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
KubernetesAuthenticationOptions options = KubernetesAuthenticationOptions.builder()
.role(…).jwtSupplier(…).build();
return new KubernetesAuthentication(options, restOperations());
}
// …
}
您可以通过以下方式配置身份验证KubernetesAuthenticationOptions
.
另见:
15.14. 用户名/密码身份验证
用户名/密码通常是最终用户身份验证方案。 多个 Vault 身份验证后端支持使用用户名和密码:
-
用户名和密码 (
userpass
) -
LDAP (
ldap
) -
奥克塔 (
okta
,支持额外的基于时间的一次性Tokens) -
半径 (
radius
)
UserPasswordAuthenticationOptions
可以与上述所有身份验证后端一起使用,因为登录 API 在所有机制上都是相似的。
配置时请确保使用适当的身份验证挂载路径UserPasswordAuthenticationOptions
.
UserPasswordAuthentication
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
UserPasswordAuthenticationOptions options = UserPasswordAuthenticationOptions.builder()
.username(…).password(…).build();
return new UserPasswordAuthentication(options, restOperations());
}
// …
}
另见:
15.15. 身份验证步骤
ClientAuthentication
对象描述身份验证流程并执行实际的
身份验证步骤。预先组合的身份验证易于使用和配置
与同步执行的紧密绑定。
身份验证方法的组成和重复使用常见步骤,例如发布登录
无意将有效负载发送到 Vault 或从 HTTP 源检索身份验证输入
跟ClientAuthentication
对象。
身份验证步骤提供常见身份验证活动的可重用性。
通过以下方式创建的步骤AuthenticationSteps
描述功能中的身份验证流
样式,将实际的身份验证执行留给特定的执行器。
AuthenticationSteps.just(VaultToken.of(…)); (1)
1 | 创建AuthenticationSteps 从一个VaultToken . |
可以从单个输入创建单步身份验证流。声明的流
多个身份验证步骤以Supplier
或HttpRequest
提供
身份验证状态对象,可用于映射或发布到 Vault 进行登录。
AuthenticationSteps.fromSupplier( (1)
() -> getAppRoleLogin(options.getRoleId(), options.getSecretId())) (2)
.login("auth/{mount}/login", options.getPath()); (3)
1 | 开始声明AuthenticationSteps 接受Supplier<T> .
状态对象类型取决于Supplier 响应类型,可以在后续步骤中映射。 |
2 | 实际的Supplier 实现。
创建Map 在这种情况下。 |
3 | 通过发布状态对象 (Map ) 添加到 Vault 端点以创建 Vault Tokens。
请注意,模板变量受 URL 转义的影响。 |
身份验证流需要执行程序来执行实际登录。我们提供两个执行者 对于不同的执行模型:
-
AuthenticationStepsExecutor
作为同步的直接替代品ClientAuthentication
. -
AuthenticationStepsOperator
用于反应性执行。
多ClientAuthentication
自带静态工厂方法来创建AuthenticationSteps
对于特定于身份验证的选项:
AuthenticationSteps
执行CubbyholeAuthenticationOptions options = …
RestOperations restOperations = …
AuthenticationSteps steps = CubbyholeAuthentication.createAuthenticationSteps(options);
AuthenticationStepsExecutor executor = new AuthenticationStepsExecutor(steps, restOperations);
VaultToken token = executor.login();
15.16. Tokens生命周期
Vault 的Tokens可以与生存时间相关联。通过身份验证方法获取的Tokens 只要会话处于活动状态,就可以使用,并且在应用程序处于活动状态时不应过期。
Spring Vault 提供了LifecycleAwareSessionManager
一个会话管理器,可以续订Tokens,直到它达到其终端 TTL,然后执行另一次登录以获取与会话关联的下一个Tokens。
根据身份验证方法,登录可以创建两种Tokens:
-
VaultToken
:封装实际Tokens的通用Tokens。 -
LoginToken
:与可续订性/TTL 关联的Tokens。
身份验证方法,例如TokenAuthentication
只需创建一个VaultToken
不包含任何可续订性/TTL 详细信息。LifecycleAwareSessionManager
将对Tokens运行自查找,以从 Vault 检索可续订性和 TTL。VaultToken
如果启用了自查找,则会定期续订。请注意,VaultToken
永远不会被撤销,只有LoginToken
被撤销。
创建身份验证方法LoginToken
直接(所有基于登录的身份验证方法)已经提供了设置Tokens续订所需的所有详细信息。从登录中获取的Tokens由LifecycleAwareSessionManager
如果会话管理器已关闭。