认证方法
不同的组织对安全性和身份验证有不同的要求。Vault 通过提供多种身份验证方法来反映这一需求。Spring Vault 支持多种身份验证机制。
外部化登录凭据
首次获得对安全系统的访问权限被称为安全引入。 任何客户端都需要临时或永久的凭据来访问 Vault。将凭据外部化是一种很好的模式,有助于保持代码的可维护性,但同时也带来了更高的泄露风险。
将登录凭据披露给任何一方都可能导致对方通过Vault登录并访问底层角色所允许的秘密。选择合适的客户端身份验证方式以及将凭据注入应用程序需根据风险评估来决定。
Spring的PropertySource抽象非常适合将配置保持在应用程序代码之外。您可以使用系统属性、环境变量或属性文件来存储登录凭据。每种方法都有其自己的特性。请记住,使用适当的操作系统访问级别可以检查命令行和环境属性。
vault.token 提取到属性文件的示例 1@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。 |
See SecurePropertyUsage.java for a sample on referencing properties in components and other property sources.
Tokens认证
Tokens 是 Vault 内部进行身份验证的核心方法。 Token 身份验证需要提供一个静态 Token。
| Tokens认证是默认的认证方法。 如果Tokens被泄露给非预期的第三方,该第三方将获得对 Vault 的访问权限, 并可以访问目标客户端的秘密信息。 |
通常,Tokens身份验证用于Tokens在外部创建和更新的场景(例如 HashiCorp Vault 服务代理)。 根据实际设置,您可能希望或者不希望进行Tokens更新和吊销。 有关 TTL 和Tokens吊销的详细信息,请参见 LifecycleAwareSessionManager。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
return new TokenAuthentication("…");
}
// …
}
见亦:
应用角色认证
AppRole 允许机器进行身份验证。AppRole 身份验证由两个难以猜测(秘密)的Tokens组成:RoleId 和 SecretId。
Spring Vault 通过提供仅 RoleId 或与提供的 SecretId 一起使用,并从 Vault 中获取 RoleId/SecretId(推送和拉取模式,带响应解包)来支持 AppRole 身份验证。
@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());
}
// …
}
AWS-EC2 认证
aws-ec2 身份验证方法为 AWS EC2 实例提供了一种安全的引入机制,允许自动检索 Vault Tokens。与大多数 Vault 身份验证方法不同,此方法不需要预先部署或配置敏感的安全凭证(如Tokens、用户名/密码、客户端证书等)。相反,它将 AWS 视为受信任的第三方,并使用加密签名的动态元数据信息,这些信息唯一地标识每个 EC2 实例。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
return new AwsEc2Authentication(restOperations());
}
// …
}
AWS-EC2 认证默认启用 nonce,以遵循首次使用信任 (TOFU) 原则。任何非预期的获得 PKCS#7 身份元数据访问权限的第三方都可以对 Vault 进行身份验证。
在首次登录时,Spring Vault 会生成一个随机数(nonce),并将其与实例 ID 一起存储在认证方法中。 重新认证时需要发送相同的随机数。其他任何 方都不拥有该随机数,并且可以在 Vault 中引发警报以进行进一步调查。
随机数存储在内存中,并在应用程序重启期间丢失。
自 Spring Vault 3.2 起,AWS-EC2 认证支持请求/响应(IMDSv1)元数据检索以及基于会话的变体(IMDSv2)。
AWS-EC2 身份验证角色是可选的,默认为 AMI。 您可以通过在 AwsEc2AuthenticationOptions 中设置来配置身份验证角色。
AWS-IAM 认证
The aws auth 方法允许通过使用现有的 AWS IAM 凭证进行 Vault 登录。
AWS IAM 身份验证创建了一个由 Vault 执行的签名 HTTP 请求,以使用 AWS STS GetCallerIdentity 方法获取签名者的身份。AWSv4 签名需要 IAM 凭证。
IAM 凭证可以从运行时环境获取,也可以从外部提供。像 AWS-EC2、Lambda 和 ECS 这样的运行时环境如果分配了 IAM 主体,则不需要特定于客户端的凭证配置,而是可以从其元数据源中获取这些信息。
@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 配置身份验证。
见亦:
Azure (MSI) 身份验证
azure 身份验证方法为 Azure VM 实例提供了一种安全的引入机制, 允许自动检索 Vault 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 的实例元数据服务以获取这些详细信息。
见亦:
GCP-GCE 身份验证
The gcp auth 方法允许通过使用现有的 GCP(Google Cloud Platform)IAM 和 GCE 凭证进行 Vault 登录。
GCP GCE(Google Compute Engine)身份验证为服务账户创建一个JSON Web Token(JWT)形式的签名。Compute Engine实例的JWT通过实例标识从GCE元数据服务获取。此API创建一个可用于确认实例身份的JSON Web Token。
与大多数 Vault 身份验证方法不同,此方法不需要先部署或配置安全敏感的凭据(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());
}
// …
}
见亦:
GCP-IAM 认证
The gcp auth 方法允许通过使用现有的 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,
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。 |
见亦:
GitHub 认证
The github auth method 提供了一种基于 GitHub Tokens的身份验证机制。 Vault 不支持生成 GitHub Tokens的 OAuth 工作流程, 因此它不充当 GitHub 应用程序。
身份验证机制需要一个 GitHub Tokens(或提供程序) 将Tokens传递给 Vault,然后通过您的 GitHub 帐户进行身份验证。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
GitHubAuthentication options = GitHubAuthentication.builder()
.token(…).build();
return new GitHubAuthentication(options, restOperations());
}
// …
}
见亦:
PCF 认证
The pcf auth 方法允许 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 配置身份验证。
见亦:
TLS证书认证
cert 认证方法允许使用由 CA 签名或自签名的 SSL/TLS 客户端证书进行身份验证。
To enable cert 认证您需要:
-
使用 SSL,参见 [vault.client-ssl]
-
Configure a Java
Keystorethat contains the client certificate and the private key
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
ClientCertificateAuthenticationOptions options = ClientCertificateAuthenticationOptions.builder()
.path(…).build();
return new ClientCertificateAuthentication(options, restOperations());
}
// …
}
另请参阅: Vault 文档:使用 Cert 认证方法
Cubbyhole 认证
Cubbyhole认证使用Vault的原语来提供一种安全的认证工作流程。Cubbyhole认证使用Tokens作为主要的登录方法。 一个临时Tokens被用来从Vault的Cubbyhole秘密引擎获取第二个登录VaultTokens。 登录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/可续期性
从与非零TTL相关联的Cubbyhole检索的Tokens在创建Tokens时开始计算其TTL。该时间不一定与应用程序启动时间相同。为了补偿初始延迟,Cubbyhole身份验证会对与非零TTL相关联的Tokens执行自我查找,以检索剩余的TTL。Cubbyhole身份验证不会对没有TTL的包装Tokens进行自我查找,因为零TTL表示没有与之关联的TTL。
未包装的Tokens仅通过检索Tokens并不提供有关可续期性和TTL的详细信息。自我查找将查询可续期性和剩余的TTL。
见亦:
JWT 身份验证
配置 JWT 身份验证需要Tokens或 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, restOperations());
}
// …
}
见亦:
Kubernetes 认证
Vault 自 0.8.3 起支持基于 kubernetes 的身份验证,使用 Kubernetes Tokens。
使用 Kubernetes 身份验证需要一个 Kubernetes 服务帐户Tokens, 通常挂载在 /var/run/secrets/kubernetes.io/serviceaccount/token。 该文件包含Tokens,读取后会发送到 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, restOperations());
}
// …
}
您可以通过 KubernetesAuthenticationOptions 配置身份验证。
见亦:
用户名/密码认证
用户名/密码通常是终端用户的身份验证方案。 使用用户名和密码被多种 Vault 身份验证方法支持:
-
用户名和密码 (
userpass) -
LDAP (
ldap) -
Okta (
okta, 还支持基于时间的一次性Tokens) -
RADIUS (
radius)
UserPasswordAuthenticationOptions 可以与上述所有身份验证方法一起使用,因为登录 API 在所有机制中都是类似的。 请确保在配置 UserPasswordAuthenticationOptions 时使用适当的 auth mount 路径。
UserPasswordAuthentication@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
UserPasswordAuthenticationOptions options = UserPasswordAuthenticationOptions.builder()
.username(…).password(…).build();
return new UserPasswordAuthentication(options, restOperations());
}
// …
}
见亦:
认证步骤
ClientAuthentication 对象描述了身份验证流程并执行实际的身份验证步骤。预组合的身份验证易于使用和配置,并且与同步执行紧密绑定。
认证方法的组合以及重用通用步骤,例如将登录信息提交到Vault或从HTTP源检索认证输入,并不适用于ClientAuthentication对象。
认证步骤提供了常见认证活动的可重用性。 通过 AuthenticationSteps 创建的步骤以函数式风格描述了一个认证流程, 而实际的认证执行则交由特定的执行器完成。
AuthenticationSteps.just(VaultToken.of(…)); (1)
| 1 | Creates AuthenticationSteps from just a 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 Tokens的 Vault 端点,执行 Vault 登录。 请注意,模板变量受 URL 转义的影响。 |
认证流程需要一个执行器来执行实际的登录。我们为不同的执行模型提供了两个执行器:
-
AuthenticationStepsExecutor作为同步ClientAuthentication的直接替代品。 -
AuthenticationStepsOperator用于响应式执行。
Many ClientAuthentication附带静态工厂方法来创建AuthenticationSteps 以满足其特定于认证的选项:
AuthenticationSteps 执行CubbyholeAuthenticationOptions options = …
RestOperations restOperations = …
AuthenticationSteps steps = CubbyholeAuthentication.createAuthenticationSteps(options);
AuthenticationStepsExecutor executor = new AuthenticationStepsExecutor(steps, restOperations);
VaultToken token = executor.login();
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 撤销。