领先一步
VMware 提供培训和认证,助您加速进步。
了解更多Spring Vault 2.1 已经近在眼前。我想借此文深入探讨一下即将在新版本中出现的更改和功能。
团队一直在致力于大量新功能
扩展基于基础设施的认证,支持 Google Cloud IAM 和 Azure Managed Service Identity
集成 Vault 的版本化 Key-Value 后端
Wrapping API 支持
Java 11 兼容性
Spring Vault 支持 HashiCorp Vault 0.5 至 0.11 版本。您可以在 GitHub 上找到 Spring Vault 和 Spring Cloud Vault 的示例仓库。现在,让我们深入了解 Spring Vault 2.1 的功能!
从版本 0.8.1 开始,Vault 引入了对 Google Cloud 的认证支持。GCP 认证使用 GCP 的 IAM 服务来执行以下认证流程之一
使用服务账号凭据生成签名令牌的 IAM 登录
使用 GCP 元数据服务检索签名令牌的 GCE 登录
Spring Vault 支持这两种方法。使用 IAM 认证需要设置凭据(可以通过环境变量或凭据文件),而 GCE 认证使用平台作为身份提供者,因此 GCE 认证对初始设置的要求更少。
IAM 认证使用 Google 的 IAM 服务,通过 Google 凭据中的签名生成签名令牌。签名令牌会传递给 Vault 以验证令牌。此认证方法需要通过 GOOGLE_APPLICATION_CREDENTIALS
环境变量提供凭据,或通过 GcpIamAuthenticationOptions
进行配置。GcpIamAuthentication
使用 Google 的服务 API SDK (google-api-services-iam
) 与 IAM 交互。客户端配置示例如下所示
@Configuration
class VaultConfiguration extends AbstractVaultConfiguration {
@Override
public ClientAuthentication clientAuthentication() {
try {
GcpIamAuthenticationOptions options = GcpIamAuthenticationOptions.builder()
.role("my-role")
.credential(GoogleCredential.getApplicationDefault())
.build();
return new GcpIamAuthentication(options, restOperations());
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
// …
}
默认情况下,IAM 认证方法从凭据中派生项目 ID 和服务账号 ID。如果您想代表特定的服务账号进行认证,也可以配置特定的值。
欲了解更多信息,请参阅参考文档。
GCE (Google Compute Engine) 认证流程适用于虚拟机实例。它使用元数据服务 (compute metadata) 获取签名令牌。签名身份会传递给 Vault 以验证虚拟机实例。客户端配置示例如下所示
@Configuration
class VaultConfiguration extends AbstractVaultConfiguration {
@Override
public ClientAuthentication clientAuthentication() {
GcpComputeAuthenticationOptions options = GcpComputeAuthenticationOptions
.builder().path("my-role").build();
return new GcpComputeAuthentication(options, restOperations());
}
// …
}
欲了解更多信息,请参阅参考文档。
从版本 0.10.0 开始,Vault 引入了对 Azure 的认证支持。在 Azure 虚拟机上运行的应用程序可以使用托管服务标识对 Vault 进行认证。托管服务标识 (MSI) 可以为无需预先配置凭据的虚拟机激活。
Spring Vault 从 Azure Instance Metadata Service (IMDS) 获取 MSI 凭据。Vault 需要额外的详细信息(subscriptionId、资源组名称、VM 名称)来执行认证。默认情况下,这些值也从 IMDS 获取,并与身份令牌一起传递给 Vault。可能的客户端配置示例如下所示
@Configuration
class VaultConfiguration extends AbstractVaultConfiguration {
@Override
public ClientAuthentication clientAuthentication() {
AzureMsiAuthenticationOptions options = AzureMsiAuthenticationOptions.builder()
.role("my-role").build();
return new AzureMsiAuthentication(options, restOperations());
}
// …
}
欲了解更多信息,请参阅参考文档。
Vault 在 0.10 版本中引入了其 Key-Value 后端的版本化变体(这个后端在几个版本前也被称为通用 secret 后端)。此更改引入了另一种后端类型,其操作(list、get、put、delete)的外部 API 相似,但 API 实现不同。
为了统一版本化和非版本化 API 访问,我们引入了一个使用 VaultKeyValueOperations
的通用 API。如果您不想与版本化元数据交互,VaultKeyValueOperations
提供了可以在版本无关风格下使用的通用功能。以下示例展示了如何使用它
VaultOperations vaultOperations = …
VaultKeyValueOperations operations = vaultOperations.opsForKeyValue("secret", KeyValueBackend.unversioned());
Map<String, Object> secret = new HashMap<>();
secret.put("key", "value");
secret.put("ttl", "5");
operations.put("key", secret);
operations.put("key", new Person(…));
VaultResponseSupport<Person> person = operations.get("key", Person.class);
上面所示的变体忽略了版本化细节,即使目标 secret 后端提供了这些细节。您可以获取版本化的 Key-Value API 以与版本交互。VaultVersionedKeyValueOperations
提供了版本特定的操作,例如检索特定 secret 版本或比较并设置。请看以下示例
VaultOperations vaultOperations = …
VaultVersionedKeyValueOperations operations = vaultOperations.opsForVersionedKeyValue("versioned");
Map<String, Object> secret = new HashMap<>();
secret.put("key", "value");
secret.put("ttl", "5");
Metadata metadata = operations.put("key", secret);
Versioned<Map<String, Object>> versioned = operations.get("key", Version.from(42));
Map<String, Object> update = new HashMap<>();
update.put("key", "new-key");
update.put("ttl", "5");
Versioned<Map<String, Object>> compareAndSet = Versioned.create(secret, versioned.getVersion());
operations.put("key", compareAndSet);
operations.delete("key", Version.from(42));
对版本化 secret 的请求和响应将其内容以及版本化元数据包装在一个 Versioned
对象中,以附加版本化上下文。
Vault 的核心概念是将响应包装起来并返回一个令牌,以便获取实际的响应体。现在通过一个带有 VaultWrappingOperations
的专用 API 支持响应包装。Wrapping 支持允许查找包装的响应。您可以读取这些响应并重新包装内容。VaultWrappingOperations
不支持对 Spring Vault API 调用的响应包装。如果您需要创建包装的响应,可以直接使用 RestTemplate
通过 VaultOperations.doWithSession(…)
。
以下示例概述了 VaultWrappingOperations
的用法
VaultOperations vaultOperations = …
VaultWrappingOperations operations = vaultOperations.opsForWrapping();
VaultToken wrappingToken = VaultToken.of(…);
// Metadata encapsulated TTL and Creation Time
WrappedMetadata lookup = operations.lookup(wrappingToken);
// Read the response as generic Map
VaultResponse response = operations.read(wrappingToken);
// Read the response applying a type hint.
VaultResponseSupport<SocialSecurityNumber> response = operations.read(
wrappingToken, SocialSecurityNumber.class);
// You can also wrap user-supplied data and get a token in return
Map<String, String> map = Collections.singletonMap("key", "value");
WrappedMetadata metadata = wrappingOperations.wrap(map, Duration.ofSeconds(100));
Spring Vault 作为其下一个长期支持版本,完全支持 Java 11。实际上,如果您正在针对 JDK 11 进行开发,我们强烈建议您将 Spring Vault 版本升级到 2.1 版本(结合 Spring Framework 5.1),因为这将为您提供 Spring 库的无警告体验。所有 HTTP 客户端集成均支持 JDK 11。
我们正在努力开发下一个 Spring Vault 2.2 版本,以提供基于注解的版本化 Vault key-value 后端配置。我们将继续关注 Vault 项目,并持续努力提供从应用程序角度来看有意义的功能集成。干杯,敬请关注!