凭据轮换
Vault 全面的凭据轮换功能允许自动续期和轮换机密,例如数据库凭据。通过将机密有效期绑定到应用程序实例生命周期,你的应用程序无需人工干预即可保持对有效凭据的访问。被泄露的凭据仅在有限时间内有效,并且影响被隔离在单个应用程序实例内。
当机密带有租约时,Spring Vault 会在到期前续期该租约,使凭据在整个应用程序生命周期内保持有效。
以下各节介绍 属性源 等组件使用的凭据轮换基础设施。
SecretLeaseContainer
SecretLeaseContainer 管理带租约机密的生命周期。它在租约到期前续期租约,并在必要时轮换凭据,监听租约事件并触发相应的操作。
作为 Spring Lifecycle 组件,该容器支持在应用程序运行期间进行动态机密管理。它接受表示受管机密的 RequestedSecret 实例。
示例 1:设置 SecretLeaseContainer
SecretLeaseContainer container = new SecretLeaseContainer(vaultOperations, 1
taskScheduler);
RequestedSecret requestedSecret = container 2
.requestRotatingSecret("mysql/creds/my-role");
container.addLeaseListener(new LeaseListenerAdapter() { 3
@Override
public void onLeaseEvent(SecretLeaseEvent secretLeaseEvent) {
if (requestedSecret.equals(secretLeaseEvent.getSource())) {
if (secretLeaseEvent instanceof SecretLeaseCreatedEvent) {
// …
}
if (secretLeaseEvent instanceof SecretLeaseExpiredEvent) {
// …
}
}
}
});
container.afterPropertiesSet();
container.start(); // events are triggered after starting the container
使用
VaultOperations和用于续期调度的TaskScheduler进行初始化。从 Vault 路径请求一个轮换机密。
为租约事件注册一个
LeaseListener。注册顺序很重要:在容器启动或机密请求之后添加的监听器可能会错过早期事件。请在启动容器之前设置好监听器,以捕获所有事件。
当你的配置类是 AbstractVaultConfiguration 的子类时,会注册一个 SecretLaseContainer,这通常适用于非 Spring Boot 应用程序。使用 Spring Boot 时,请考虑 Spring Cloud Vault,它通过自动配置处理注册。
事件
常规事件
- AfterSecretLeaseRenewedEvent:租约续期成功。
- AfterSecretLeaseRevocationEvent:租约吊销成功。
- BeforeSecretLeaseRevocationEvent:在租约吊销之前,允许执行吊销前操作。
- SecretLeaseCreatedEvent:创建了新租约,通常在初始请求时。
- SecretLeaseRotatedEvent:
SecretLeaseCreatedEvent的专门化,用于租约到期后的机密轮换。 - SecretLeaseExpiredEvent:租约被检测为已过期,无论是通过 TTL 到期还是通过过期
Predicate<Lease>评估。 - SecretNotFoundEvent:在初始请求或续期时,Vault 路径上未找到机密。
错误事件
- SecretLeaseErrorEvent:通信期间出现 Vault 错误响应或 I/O 错误。
直接使用 SecretLeaseContainer 及其监听器,可以细粒度地控制机密的生命周期和租约事件的处理。在典型的应用程序场景中,你可能希望使用更高级别的抽象来简化机密及其租约的管理。
ManagedSecret 和 SecretRegistrar
ManagedSecret API 提供声明式的机密生命周期管理。ManagedSecret 是一个更高级别的抽象,它向 SecretLeaseContainer 注册并代表你处理租约事件。作为 SecretRegistrar 的实现,registrar bean 会在启动前通过 AbstractVaultConfiguration 注册到容器中。
示例 2:注册 ManagedSecret
@Configuration
class MyConfiguration {
@Bean
ManagedSecret mysqlCredentials(HikariDataSource dataSource) {
return ManagedSecret.rotating("mysql/creds/my-role", secrets -> secrets.as(UsernamePassword::from)
.applyTo((username, password) -> {
connectionPool.setUsername(username);
connectionPool.setPassword(password);
}));
}
}
托管机密允许机密管理与使用机密的应用程序组件之间建立直接联系,从而在请求或轮换机密时更容易将凭据传播到应用程序组件。请注意,SecretLeaseContainers 的生命周期特性通常会将机密的可用性推迟到容器启动并请求机密之后,这与在 InitializingBean.afterPropertiesSet() 或 @PostConstruct 阶段需要凭据的组件使用方式可能不同。AbstractVaultConfiguration 特意在 bean 创建期间就启动容器,以允许尽早访问凭据。在任何情况下,你都应该确保组件的依赖顺序,以保证在需要时正确初始化和可用机密。
TTL 调优
租约续期和轮换受 TTL(生存时间)约束,因此与时间直接相关。SecretLeaseContainer 使用一个过期阈值(默认 1 分钟)来确定租约是否被视为已过期。最小续期 TTL(默认 10 秒)可防止在短时间内连续发出过多的续期请求。续期和轮换时间基于租约 TTL 时长和本地系统时钟(特别是 TaskScheduler 时钟)计算。
你可以配置自定义的过期 Predicate<Lease> 函数来确定租约到期。
令牌续期与会话管理
当会话令牌到期或被吊销时,Vault 会吊销与该令牌关联的租约。当你的 Vault 会话到期(达到最大 TTL)时,该会话内发出的任何租约也会被吊销。SessionLeaseContainer 通过 getAuthenticationListener() 和 getAuthenticationErrorListener() 提供 AuthenticationListener,用于向你的 SessionManager 注册,从而允许在成功重新登录后重新启动机密。
CertificateContainer
CertificateContainer 管理由 Vault 的 PKI 机密引擎颁发的证书。证书通常不与租约关联(实际上,避免租约是一项性能优化建议),因此它们不需要续期,但可以在到期时轮换。证书轮换实际上是重新颁发。
Vault PKI 提供几种证书类型:
- X.509 证书捆绑包
- TLS 加密
- 客户端认证
- X.509 证书
- 信任锚
该容器是一个 Spring Lifecycle 组件,可以启动和停止,允许在应用程序运行期间动态管理证书。它接受 RequestedCertificate 实例,这些实例表示需要管理的证书。以下代码示例展示了如何设置 CertificateContainer 并监听事件:
示例 3:设置 CertificateContainer
CertificateContainer container = new CertificateContainer(vaultOperations.opsForPki()); 1
RequestedCertificate cert = container
.register(RequestedCertificate.trustAnchor("vault-ca")); 2
RequestedCertificate bundle = RequestedCertificateBundle.issue("www.example.com", 3
"testrole", VaultCertificateRequest.builder()
.commonName("www.example.com")
.ttl(Duration.ofHours(12)).build());
container.addCertificateListener(new CertificateListenerAdapter() { 4
@Override
public void onCertificateEvent(CertificateEvent event) {
if (cert.equals(event.getSource())) {
if (event instanceof CertificateBundleIssuedEvent) {
// Certificate bundle issued initially or rotated
}
if (event instanceof CertificateObtainedEvent) {
// initial certificate obtained
}
}
}
});
container.afterPropertiesSet();
container.start(); // events are triggered after starting the container
使用
VaultPkiOperations进行初始化。如果没有提供TaskScheduler,容器会创建一个默认实例。通过
RequestedCertificate请求一个颁发者证书(支持默认或命名的颁发者)。通过
RequestedCertificateBundle使用证书请求请求一个受管证书捆绑包。为证书事件注册一个
CertificateListener。注册顺序很重要:在容器启动或证书请求之后添加的监听器可能会错过早期事件。请在启动容器之前设置好监听器,以捕获所有事件。
当你的配置类是 AbstractVaultConfiguration 的子类时,会注册一个 CertificateContainer,这通常适用于非 Spring Boot 应用程序。使用 Spring Boot 时,请考虑 Spring Cloud Vault,它通过自动配置处理注册。
事件
常规事件
- CertificateObtainedEvent:证书已颁发。
- CertificateRotatedEvent:
CertificateObtainedEvent的专门化,用于证书轮换。 - CertificateBundleIssuedEvent:
CertificateObtainedEvent的专门化,用于证书捆绑包颁发。 - CertificateBundleRotatedEvent:
CertificateBundleIssuedEvent的专门化,用于证书捆绑包轮换。 - CertificateExpiredEvent:证书被检测为已过期。
错误事件
- CertificateErrorEvent:在 Vault 通信期间出现 Vault 错误响应或 I/O 错误时触发。
直接使用 CertificateContainer 及其监听器,可以细粒度地控制证书的生命周期和事件的处理。在典型的应用程序场景中,你可能希望使用更高级别的抽象来简化证书的管理。
ManagedCertificate 和 CertificateRegistrar
ManagedCertificate API 提供声明式的证书生命周期管理。ManagedCertificate 是一个更高级别的抽象,它向 CertificateContainer 注册并代表你处理证书事件。它是 CertificateRegistrar 的实现。Registrar bean 由 AbstractVaultConfiguration 检测,并在容器启动前注册到 CertificateContainer。
示例 4:注册 ManagedCertificate
@Configuration
class MyConfiguration {
@Bean
ManagedCertificate serverCertificate(SslBundles bundles) {
VaultCertificateRequest request = VaultCertificateRequest.builder()
.commonName("www.example.com")
.ttl(Duration.ofHours(12)).build();
return ManagedCertificate.issue("my-bundle", "my-role", request, bundle -> {
bundles.register("my-bundle", bundle.createKeyStore("my-alias"));
});
}
}
托管证书允许证书管理与使用证书的应用程序组件之间建立直接联系,从而更容易将凭据传播到应用程序组件。请注意,CertificateContainer 的生命周期特性通常会将证书的可用性推迟到容器启动并请求证书之后,这与在 InitializingBean.afterPropertiesSet() 或 @PostConstruct 阶段需要凭据的组件使用方式可能不同。AbstractVaultConfiguration 特意在 bean 创建期间就启动容器,以允许尽早访问证书。在任何情况下,你都应该确保组件的依赖顺序,以保证在需要时正确初始化和可用证书。