认证方法
不同的组织对安全和认证有不同的要求。Vault 通过提供多种认证方法反映了这一需求。Spring Vault 支持多种认证机制。
外部化登录凭据
首次访问受保护的系统被称为安全引入。任何客户端都需要临时或永久的凭据才能访问 Vault。外部化凭据是保持代码高可维护性的好模式,但会带来披露风险增加的问题。
将登录凭据披露给任何一方都会允许其登录 Vault 并访问底层角色所允许访问的机密。选择合适的客户端认证并将凭据注入应用程序需要进行风险评估。
Spring 的 PropertySource 抽象 是将配置保持在应用程序代码之外的自然选择。你可以使用系统属性、环境变量或属性文件来存储登录凭据。每种方式都有自己的属性。请记住,命令行和环境属性可以通过适当的操作系统访问级别进行探查。
示例 1:将 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,并从 ApplicationContext 获取 Environment。
请参阅 SecurePropertyUsage.java,了解在组件和其他属性源中引用属性的示例。
ClientAuthentication 接口
ClientAuthentication 接口支持对 Vault 进行认证,并为已认证的 Vault 请求返回一个 VaultToken。
实现通常是无状态且线程安全的,使用 VaultClient 进行认证请求。大多数认证方法还实现 AuthenticationStepsFactory,用于可组合认证的响应式/非阻塞响应式安排。
通常,一种认证机制需要特定于其方法的配置选项,以及一个 VaultClient 来通过提供特定于方法的凭据请求令牌。例如,AppRole 认证 直接从 Vault 检索所有必要的凭据。
一些认证机制依赖于外部凭据或令牌,特别是那些依赖受信任环境(AWS、GCP、Azure 计算实例)的机制。内置机制接受 RestClient 或特定于传输的客户端(例如 Google IAM TransportChannelProvider)。
为认证提供 RestClient 时,请使用 Vault 的基础 URL 配置它,因为认证机制只使用相对路径。虽然 RestClient 允许自定义超时和 SSL 设置,但我们建议使用单独的 VaultClient,以避免外部通信和认证请求之间意外共享配置。
令牌认证
令牌是 Vault 内认证的核心方法。令牌认证要求提供一个静态令牌。
令牌认证是默认的认证方法。如果令牌被非预期方披露,该方将获得对 Vault 的访问权,并可以访问预期客户端允许访问的机密。
通常,令牌认证用于令牌在外部创建和续期的场景(例如 HashiCorp Vault service broker)。根据实际设置,你可能需要或不需要令牌续期和吊销。有关 TTL 和令牌吊销的详细信息,请参阅 LifecycleAwareSessionManager。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
return new TokenAuthentication("…");
}
// …
}
另请参阅:
AppRole 认证
AppRole 允许机器认证。AppRole 认证由两个难以猜测的(秘密)令牌组成:RoleId 和 SecretId。
Spring Vault 通过仅提供 RoleId 或连同提供的 SecretId 一起支持 AppRole 认证,并从 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, vaultClient());
}
// …
}
Spring Vault 也支持完全拉模式:如果未提供 RoleId 和 SecretId,Spring Vault 将使用角色名称和初始令牌检索它们。初始令牌可能与 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, vaultClient());
}
// …
}
AWS-EC2 认证
aws-ec2 认证方法为 AWS EC2 实例提供了安全引入机制,允许自动检索 Vault 令牌。与大多数 Vault 认证方法不同,此方法不需要预先部署或配置安全敏感的凭据(令牌、用户名/密码、客户端证书等)。相反,它将 AWS 视为受信任的第三方,并使用加密签名的动态元数据信息,这些信息唯一地表示每个 EC2 实例。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
return new AwsEc2Authentication(vaultClient());
}
// …
}
AWS-EC2 认证默认启用 nonce,以遵循首次使用时信任(TOFU)原则。任何获得 PKCS#7 身份元数据访问权限的非预期方都可以对 Vault 进行认证。
在首次登录期间,Spring Vault 会生成一个 nonce,存储在认证方法的实例 Id 旁边。重新认证需要发送相同的 nonce。任何其他方都没有该 nonce,并且可以在 Vault 中引发警报以进行进一步调查。
nonce 保存在内存中,在应用程序重启时丢失。
自 Spring Vault 3.2 起,AWS-EC2 认证支持请求/响应(IMDSv1)元数据检索以及基于会话的变体(IMDSv2)。
AWS-EC2 认证角色是可选的,默认为 AMI。你可以通过在 AwsEc2AuthenticationOptions 中设置来配置认证角色。
AWS-IAM 认证
aws 认证方法允许通过使用现有的 AWS IAM 凭据登录 Vault。
AWS IAM 认证会创建一个签名 HTTP 请求,Vault 使用 AWS STS GetCallerIdentity 方法执行该请求以获取签名者的身份。AWSv4 签名需要 IAM 凭据。
IAM 凭据可以从运行时环境获取,也可以在外部提供。具有指定 IAM 主体的 AWS-EC2、Lambda 和 ECS 等运行时环境不需要客户端特定的凭据配置,但可以从其元数据源获取凭据。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
AwsIamAuthenticationOptions options = AwsIamAuthenticationOptions.builder()
.credentials(new BasicAWSCredentials(…)).build();
return new AwsIamAuthentication(options, vaultClient());
}
// …
}
示例 2:使用 AWS-EC2 实例配置文件作为凭据源
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
AwsIamAuthenticationOptions options = AwsIamAuthenticationOptions.builder()
.credentialsProvider(InstanceProfileCredentialsProvider.getInstance()).build();
return new AwsIamAuthentication(options, vaultClient());
}
// …
}
AwsIamAuthentication 需要 AWS Java SDK 依赖(com.amazonaws:aws-java-sdk-core),因为认证实现使用 AWS SDK 类型进行凭据和请求签名。
你可以通过 AwsIamAuthenticationOptions 配置认证。
另请参阅:
Azure (MSI) 认证
azure 认证方法为 Azure VM 实例提供了安全引入机制,允许自动检索 Vault 令牌。与大多数 Vault 认证方法不同,此方法不需要预先部署或配置安全敏感的凭据(令牌、用户名/密码、客户端证书等)。相反,它将 Azure 视为受信任的第三方,并使用可绑定到 VM 实例的托管服务标识和实例元数据信息。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
AzureMsiAuthenticationOptions options = AzureMsiAuthenticationOptions.builder()
.role(…).build();
return new AzureMsiAuthentication(options, vaultClient());
}
// …
}
Azure 认证需要有关 VM 环境的详细信息(订阅 Id、资源组名称、VM 名称)。这些详细信息可以通过 AzureMsiAuthenticationOptionsBuilder 配置。如果未配置,AzureMsiAuthentication 会查询 Azure 的实例元数据服务以获取这些详细信息。
另请参阅:
GCP-GCE 认证
gcp 认证方法允许通过使用现有的 GCP(Google Cloud Platform)IAM 和 GCE 凭据登录 Vault。
GCP GCE(Google Compute Engine)认证会为服务账户创建 JSON Web Token(JWT)形式的签名。使用 实例标识 从 GCE 元数据服务获取 Compute Engine 实例的 JWT。此 API 创建一个可用于确认实例身份的 JSON Web Token。
与大多数 Vault 认证方法不同,此方法不需要预先部署或配置安全敏感的凭据(令牌、用户名/密码、客户端证书等)。相反,它将 GCP 视为受信任的第三方,并使用加密签名的动态元数据信息,这些信息唯一地表示每个 GCP 服务账户。
你可以通过 GcpComputeAuthenticationOptions 配置认证。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
GcpComputeAuthenticationOptions options = GcpComputeAuthenticationOptions.builder()
.role(…).build();
GcpComputeAuthentication authentication = new GcpComputeAuthentication(options,
vaultClient());
}
// …
}
另请参阅:
GCP-IAM 认证
gcp 认证方法允许通过使用现有的 GCP(Google Cloud Platform)IAM 和 GCE 凭据登录 Vault。
GCP IAM 认证会为服务账户创建 JSON Web Token(JWT)形式的签名。通过调用 GCP IAM 的 projects.serviceAccounts.signJwt API 获取服务账户的 JWT。调用方对 GCP IAM 进行认证,从而证明其身份。此 Vault 认证方法将 GCP 视为受信任的第三方。
IAM 凭据可以从运行时环境获取,也可以在外部提供,例如以 JSON 形式。JSON 是首选形式,因为它携带调用 projects.serviceAccounts.signJwt 所需的项目 Id 和服务账户标识符。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
GcpIamCredentialsAuthenticationOptions options = GcpIamCredentialsAuthenticationOptions.builder()
.role(…).credential(GoogleCredentials.getApplicationDefault()).build();
GcpIamCredentialsAuthentication authentication = new GcpIamCredentialsAuthentication(options,
vaultClient());
}
// …
}
GcpIamCredentialsAuthenticationOptions 需要 Google Cloud Java SDK 依赖(com.google.cloud:google-cloud-iamcredentials),因为认证实现使用 Google API 进行凭据和 JWT 签名。
你可以通过 GcpIamCredentialsAuthenticationOptions 配置认证。
Google 凭据需要一个维护令牌生命周期的 OAuth 2 令牌。所有 API 都是同步的,因此 GcpIamCredentialsAuthentication 不支持响应式使用所需的 AuthenticationSteps。
GcpIamCredentialsAuthentication 使用 IAM Credentials API,是使用已弃用的 IAM API 的已弃用 GcpIamAuthentication 的替代品。
另请参阅:
GitHub 认证
github 认证方法提供了基于 GitHub 令牌的认证机制。Vault 不支持生成 GitHub 令牌的 OAuth 工作流,因此它不作为 GitHub 应用程序运行。
该认证机制需要一个 GitHub 令牌(或一个提供者)将令牌传递给 Vault,然后 Vault 对你的 GitHub 账户进行认证。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
GitHubAuthentication options = GitHubAuthentication.builder()
.token(…).build();
return new GitHubAuthentication(options, vaultClient());
}
// …
}
另请参阅:
PCF 认证
pcf 认证方法允许 PCF 实例登录 Vault。它利用 PCF 的应用和容器身份保证。
PCF 认证使用实例密钥和证书创建签名,由 Vault 验证。如果签名匹配,并且可能绑定的组织/空间/应用程序 Id 匹配,Vault 会颁发一个作用域适当的令牌。
实例凭据可从 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,
vaultClient());
}
// …
}
PcfAuthenticationOptions 需要 BouncyCastle 库来创建 RSA-PSS 签名。
你可以通过 PcfAuthenticationOptions 配置认证。
另请参阅:
TLS 证书认证
cert 认证方法允许使用由 CA 签名或自签名的 SSL/TLS 客户端证书进行认证。
要启用 cert 认证,你需要:
- 使用 SSL,请参阅 [vault.client-ssl]
- 配置一个包含客户端证书和私钥的 Java
Keystore
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
ClientCertificateAuthenticationOptions options = ClientCertificateAuthenticationOptions.builder()
.path(…).build();
return new ClientCertificateAuthentication(options, vaultClient());
}
// …
}
Cubbyhole 认证
Cubbyhole 认证使用 Vault 原语提供安全的认证工作流。Cubbyhole 认证使用令牌作为主要登录方法。一个临时令牌用于从 Vault 的 Cubbyhole 机密引擎获取第二个登录 VaultToken。登录令牌通常寿命更长,用于与 Vault 交互。登录令牌可以从包裹的响应或 data 部分检索。
创建包裹令牌
令牌创建的响应包裹需要 Vault 0.6.0 或更高版本。
示例 3:创建并存储令牌
$ 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
示例 4:包裹令牌响应用法
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
CubbyholeAuthenticationOptions options = CubbyholeAuthenticationOptions
.builder()
.initialToken(VaultToken.of("…"))
.wrapped()
.build();
return new CubbyholeAuthentication(options, vaultClient());
}
// …
}
使用存储的令牌
示例 5:创建并存储令牌
$ 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
示例 6:存储令牌响应用法
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
CubbyholeAuthenticationOptions options = CubbyholeAuthenticationOptions
.builder()
.initialToken(VaultToken.of("…"))
.path("cubbyhole/token")
.build();
return new CubbyholeAuthentication(options, vaultClient());
}
// …
}
剩余 TTL/可续期性
从 Cubbyhole 检索的、具有非零 TTL 的令牌,其 TTL 从令牌创建时开始计算。该时间不一定与应用程序启动时间一致。为了补偿初始延迟,Cubbyhole 认证会对具有非零 TTL 的令牌执行自我查找,以检索剩余的 TTL。Cubbyhole 认证不会对没有 TTL 的包裹令牌执行自我查找,因为零 TTL 表示没有关联的 TTL。
非包裹令牌仅通过检索令牌不提供有关可续期性和 TTL 的详细信息。自我查找将查找可续期性和剩余 TTL。
另请参阅:
JWT 认证
配置 JWT 认证需要令牌或 JWT 提供者。你可以通过 JwtAuthenticationOptions 配置认证。
在 Vault 侧,你可以通过启用 JWT 认证方法并创建角色来配置 JWT 认证方法。你可以使用 oidc_discovery_url、jwks_url 或 jwt_validation_pubkeys 来配置 JWT 认证方法。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
JwtAuthenticationOptions options = JwtAuthenticationOptions.builder()
.role(…).jwt(…).path(…).build();
return new JwtAuthentication(options, vaultClient());
}
// …
}
另请参阅:
Kubernetes 认证
自 0.8.3 起,Vault 支持使用 Kubernetes 令牌进行 kubernetes 认证。
使用 Kubernetes 认证需要一个 Kubernetes 服务账户令牌,通常挂载在 /var/run/secrets/kubernetes.io/serviceaccount/token。该文件包含令牌,会被读取并发送到 Vault。Vault 在登录期间使用 Kubernetes 的 API 验证其有效性。
配置 Kubernetes 认证至少需要提供角色名称:
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
KubernetesAuthenticationOptions options = KubernetesAuthenticationOptions.builder()
.role(…).jwtSupplier(…).build();
return new KubernetesAuthentication(options, vaultClient());
}
// …
}
你可以通过 KubernetesAuthenticationOptions 配置认证。
另请参阅:
用户名/密码认证
用户名/密码通常是一种终端用户认证方案。多种 Vault 认证方法支持使用用户名和密码:
- 用户名和密码(
userpass) - LDAP(
ldap) - Okta(
okta,额外支持基于时间的一次性令牌) - RADIUS(
radius)
UserPasswordAuthenticationOptions 可以与上述所有认证方法一起使用,因为所有机制之间的 Login API 是相似的。配置 UserPasswordAuthenticationOptions 时,请确保使用适当的认证挂载路径。
示例 7:配置 UserPasswordAuthentication
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
UserPasswordAuthenticationOptions options = UserPasswordAuthenticationOptions.builder()
.username(…).password(…).build();
return new UserPasswordAuthentication(options, vaultClient());
}
// …
}
另请参阅:
认证步骤
ClientAuthentication 对象描述认证流程并执行实际的认证步骤。预组合的认证易于使用和配置,并与同步执行紧密绑定。
组合认证方法和复用常见步骤(例如将登录载荷发布到 Vault 或从 HTTP 源检索认证输入)并非 ClientAuthentication 对象的用途。
认证步骤提供了常见认证活动的可复用性。通过 AuthenticationSteps 创建的步骤以函数式风格描述认证流程,将实际的认证执行留给特定的执行器。
示例 8:存储令牌认证流程。
AuthenticationSteps.just(VaultToken.of(…)); 1
仅从一个
VaultToken创建AuthenticationSteps。
单步认证流程可以由单个输入创建。声明多个认证步骤的流程以 Supplier 或 HttpRequest 开始,它们提供一个认证状态对象,可用于映射或发布到 Vault 进行登录。
示例 9:AppRole 认证流程
AuthenticationSteps.fromSupplier( 1
() -> getAppRoleLogin(options.getRoleId(), options.getSecretId())) 2
.login("auth/{mount}/login", options.getPath()); 3
开始声明接受
Supplier<T>的AuthenticationSteps。状态对象类型取决于Supplier响应类型,可以在后续步骤中映射。实际的
Supplier实现。在这种情况下创建一个Map。通过将状态对象(
Map)发布到 Vault 端点来执行 Vault 登录以创建 Vault 令牌。请注意,模板变量会进行 URL 转义。
认证流程需要一个执行器来执行实际的登录。我们为不同的执行模型提供了两个执行器:
AuthenticationStepsExecutor作为同步ClientAuthentication的直接替代品。AuthenticationStepsOperator用于响应式执行。
许多 ClientAuthentication 带有静态工厂方法,用于为其特定于认证的选项创建 AuthenticationSteps:
示例 10:同步 AuthenticationSteps 执行
CubbyholeAuthenticationOptions options = …
VaultClient vaultClient = …
RestClient restClient = …
AuthenticationSteps steps = CubbyholeAuthentication.createAuthenticationSteps(options);
AuthenticationStepsExecutor executor = new AuthenticationStepsExecutor(steps, vaultClient, restClient);
VaultToken token = executor.login();
令牌生命周期
Vault 的令牌可以关联一个生存时间。通过认证方法获得的令牌旨在会话活跃期间使用,并且不应在应用程序活跃期间过期。
Spring Vault 通过 LifecycleAwareSessionManager 提供了一个会话管理器,可以续期令牌直到其达到终端 TTL,然后执行另一次登录以获取与会话关联的下一个令牌。
根据认证方法的不同,一次登录可以创建两种令牌:
- VaultToken:封装实际令牌的通用令牌。
- LoginToken:与可续期性/TTL 关联的令牌。
诸如 TokenAuthentication 之类的认证方法只会创建一个不携带任何可续期性/TTL 详细信息的 VaultToken。LifecycleAwareSessionManager 将对该令牌执行自我查找,以从 Vault 检索可续期性和 TTL。如果启用了自我查找,VaultToken 会被定期续期。请注意,VaultToken 永远不会被吊销,只有 LoginToken 会被吊销。
直接创建 LoginToken 的认证方法(所有基于登录的认证方法)已经提供了设置令牌续期所需的全部细节。如果会话管理器关闭,从登录中获得的令牌会被 LifecycleAwareSessionManager 吊销。