跳到主要内容
版本:4.1.0

认证方法

Doubao 中英对照 Authentication Methods

不同的组织对安全和认证有不同的要求。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 认证,你需要:

  1. 使用 SSL,请参阅 [vault.client-ssl]
  2. 配置一个包含客户端证书和私钥的 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 吊销。