Authentication Methods
不同的组织对安全性和身份验证有不同的要求。Vault 通过提供多种身份验证方法来反映这一需求。Spring Vault 支持多种身份验证机制。
Externalizing login credentials
首次访问安全系统被称为安全引入。任何客户端都需要短暂或永久的凭证才能访问 Vault。将凭证外置化是一个保持代码可维护性的好模式,但会增加泄露的风险。
向任何一方泄露登录凭证都允许登录 Vault 并访问底层角色允许的机密。选择适当的客户端身份验证和将凭证注入应用程序需要进行风险评估。
Spring 的 {spring-framework-docs}core.html#beans-property-source-abstraction[PropertySource 抽象] 是将配置保留在应用程序代码之外的自然选择。您可以使用系统属性、环境变量或属性文件来存储登录凭据。每种方法都有自己的属性。请记住,命令行和环境属性可以通过适当的操作系统访问级别进行内省。
vault.token
to a properties file@PropertySource("configuration.properties")
@Configuration
public class Config extends AbstractVaultConfiguration {
@Override
public ClientAuthentication clientAuthentication() {
return new TokenAuthentication(getEnvironment().getProperty("vault.token"));
}
}
Spring 允许多种获取 |
请参阅 link:https://github.com/spring-projects/spring-vault/blob/master/spring-vault-core/src/test/java/org/springframework/vault/demo/SecurePropertyUsage.java[SecurePropertyUsage.java
,了解有关在组件和其他属性源中引用属性的示例。
Token authentication
令牌是 Vault 中身份验证的核心方法。令牌身份验证要求提供静态令牌。
令牌身份验证是默认身份验证方法。如果向意外方泄露令牌,它将获得 Vault 的访问权限并可以访问预期客户端的机密。 |
通常, 在令牌在外部创建和更新(例如@ {s22})的情况下,使用令牌身份验证。根据实际设置,您可能需要或不需要令牌更新和吊销。有关 TTL 和令牌吊销的详细信息,请参阅<<`LifecycleAwareSessionManager`,vault.authentication.session>>。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
return new TokenAuthentication("…");
}
// …
}
另请参阅:
AppId authentication
Vault 已弃用 AppId身份验证。请改用 AppRole authentication。 |
Vault 支持@ {s24} 身份验证,该身份验证由两个难以猜测的令牌组成。AppId 默认为@ {s23},这是静态配置的。第二个令牌是 UserId,其中一部分由应用程序确定,通常与运行时环境相关。IP 地址、Mac 地址或 Docker 容器名称是不错的示例。Spring Vault 支持 IP 地址、Mac 地址和静态 UserId(例如通过系统属性提供)。IP 和 Mac 地址表示为十六进制编码的 SHA256 哈希。
基于 IP 地址的 UserId 使用本地主机的 IP 地址。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
AppIdAuthenticationOptions options = AppIdAuthenticationOptions.builder()
.appId("myapp")
.userIdMechanism(new IpAddressUserId())
.build();
return new AppIdAuthentication(options, restOperations());
}
// …
}
从命令行生成 IP 地址 UserId 的相应命令为:
$ echo -n 192.168.99.1 | sha256sum
包括 |
基于 Mac 地址的 UserId 从本地主机绑定的设备中获取其网络设备。该配置还允许指定`network-interface`提示以选择正确的设备。`network-interface`的值是可选的,可以是接口名称或接口索引(从 0 开始)。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
AppIdAuthenticationOptions options = AppIdAuthenticationOptions.builder()
.appId("myapp")
.userIdMechanism(new MacAddressUserId())
.build();
return new AppIdAuthentication(options, restOperations());
}
// …
}
从命令行生成 Mac 地址 UserId 的相应命令是:
$ echo -n 0AFEDE1234AC | sha256sum
Mac 地址是大写指定且不带冒号的。包括 |
Custom UserId
一种更高级的方法允许您实现自己的`AppIdUserIdMechanism`。此类必须在您的类路径中,并且必须实现 `org.springframework.vault.authentication.AppIdUserIdMechanism`界面和 `createUserId`方法。每次使用 AppId 进行身份验证以获取令牌时,Spring Vault 都会调用 `createUserId`来获取 UserId。
public class MyUserIdMechanism implements AppIdUserIdMechanism {
@Override
public String createUserId() {
String userId = …
return userId;
}
}
AppRole authentication
@ {s25} 允许机器身份验证,比如(自 Vault 0.6.1 以来)已弃用的@ {s26}。AppRole 身份验证由两个难以猜测的(机密)令牌组成: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 将使用角色名称和初始令牌检索它们。初始令牌可能与 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 authentication
@ {s27} auth 后端为 AWS EC2 实例提供了一个安全的引入机制,允许自动检索 Vault 令牌。与大多数 Vault 身份验证后端不同,此后端不要求首先部署或配置对安全敏感的凭据(令牌、用户名/密码、客户端证书等)。相反,它将 AWS 视为受信第三方,并使用加密签名动态元数据信息,该信息唯一表示每个 EC2 实例。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
return new AwsEc2Authentication(restOperations());
}
// …
}
AWS-EC2 身份验证默认启用随机数,以遵循“第一次使用信任”(TOFU)原则。任何获得了 PKCS#7 身份元数据访问权限的意外方都可以对 Vault 进行身份验证。
在第一次登录期间,Spring Vault 会生成一个随机数,该随机数与实例 ID 一起存储在身份验证后端。重新身份验证需要发送相同的随机数。任何其他方都没有随机数,并且可以在 Vault 中发出警报以供进一步调查。
随机数保存在内存中,并在应用程序重新启动期间丢失。
AWS-EC2 身份验证角色是可选的,默认为 AMI。您可以通过在`AwsEc2AuthenticationOptions`中进行设置来配置身份验证角色。
另请参阅:@ {s28}
AWS-IAM authentication
@ {s29} auth 后端允许使用现有的 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, 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) authentication
@ {s30} auth 后端为 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, restOperations());
}
// …
}
Azure 身份验证需要关于 VM 环境的详细信息(订阅 ID、资源组名称、VM 名称)。这些详细信息可以通过 AzureMsiAuthenticationOptionsBuilder
配置。如果未配置,则 AzureMsiAuthentication
会查询 Azure 的实例元数据服务以获取这些详细信息。
另请参阅:
GCP-GCE authentication
gcp身份验证后端允许使用现有的 GCP(Google Cloud Platform)IAM 和 GCE 凭证登录 Vault。
GCP GCE(Google Compute Engine)身份验证为服务帐户创建 JSON Web 令牌 (JWT) 形式的签名。用于 Compute Engine 实例的 JWT 是使用@ {s31} 从 GCE 元数据服务获取的。此 API 创建了一个 JSON Web 令牌,可用于确认实例标识。
此后端与大多数 Vault 身份验证后端不同,它不需要先部署或配置安全敏感凭据(令牌、用户名/密码、客户端证书等)。相反,它将 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 authentication
gcp身份验证后端允许使用现有的 GCP(Google Cloud Platform)IAM 和 GCE 凭证登录 Vault。
GCP IAM 身份验证将签名创建为 JSON Web 令牌 (JWT) 的形式,用于服务帐号。服务帐号的 JWT 通过调用 GCP IAM 的 link:https://cloud.google.com/iam/docs/reference/credentials/rest/v1/projects.serviceAccounts/signJwt[projects.serviceAccounts.signJwt
API 获取。调用方会对 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 令牌。所有 API 都同步,因此, |
|
另请参阅:
PCF authentication
@ {s32} auth 后端允许 PCF 实例登录 Vault。它利用@ {s33}。
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,
restOperations());
}
// …
}
PcfAuthenticationOptions
需要 BouncyCastle 库来创建 RSA-PSS 签名。
你可以通过 PcfAuthenticationOptions
配置身份验证。
另请参阅:
TLS certificate authentication
cert
身份验证后端允许使用由 CA 签名或自签名的 SSL/TLS 客户端证书进行身份验证。
若要启用 cert
身份验证,你需要:
-
Use SSL, see [vault.client-ssl]
-
配置包含客户端证书和私钥的 Java
Keystore
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
ClientCertificateAuthenticationOptions options = ClientCertificateAuthenticationOptions.builder()
.path(…).build();
return new ClientCertificateAuthentication(options, restOperations());
}
// …
}
Cubbyhole authentication
Cubbyhole 身份验证将使用 Vault 原语提供安全的身份验证工作流。Cubbyhole 身份验证将令牌用作主登录方法。临时令牌用于从 Vault 的 Cubbyhole 机密后端获取第二个登录 Vault 令牌。登录令牌通常具有较长的生命周期,且用于与 Vault 进行交互。登录令牌可以从包装响应或 data
部分中检索。
-
创建包装令牌 *
令牌创建的响应封装要求 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());
}
// …
}
Using stored 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());
}
// …
}
Remaining TTL/Renewability
与非零 TTL 关联的从 Cubbyhole 中检索到的令牌将在令牌创建之时启动它们的 TTL。该时间与应用程序启动时间不一定相同。为了补偿初始延迟,Cubbyhole 身份验证将针对与非零 TTL 关联的令牌执行自查找,以检索剩余的 TTL。由于零 TTL 表明不存在关联的 TTL,因此 Cubbyhole 身份验证不会自查找无 TTL 的包装令牌。
非包装令牌不会仅通过检索令牌提供有关可更新性和 TTL 的详细信息。自查找将查找可更新性和剩余的 TTL。
另请参阅:
JWT authentication
配置 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, restOperations());
}
// …
}
另请参阅:
Kubernetes authentication
从 0.8.3 起,Vault 支持使用 Kubernetes 令牌进行基于 kubernetes 的身份验证。
使用 Kubernetes 认证需要 Kubernetes Service Account 令牌,该令牌通常加载在 /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, restOperations());
}
// …
}
你可以通过 KubernetesAuthenticationOptions
配置认证。
另请参阅:
Username/Password authentication
用户名/密码通常是终端用户的认证方案。用户名和密码的使用得到多个 Vault 认证后端的支持:
-
Username and Password (
userpass
) -
LDAP (
ldap
) -
Okta (
okta
,额外支持基于时间的的一次性令牌) -
RADIUS (
radius
)
UserPasswordAuthenticationOptions
可以与上述所有认证后端一起使用,因为登录 API 在所有机制中都是相似的。在配置 UserPasswordAuthenticationOptions
时,请确保使用适当的认证挂载路径。
UserPasswordAuthentication
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
UserPasswordAuthenticationOptions options = UserPasswordAuthenticationOptions.builder()
.username(…).password(…).build();
return new UserPasswordAuthentication(options, restOperations());
}
// …
}
另请参阅:
Authentication Steps
ClientAuthentication
对象描述认证流并执行实际认证步骤。预先组合的认证易于使用和配置,并与同步执行紧密绑定。
使用 ClientAuthentication
对象无意对认证方法进行组合和复用常见步骤,例如将登录有效负载发布到 Vault 或从 HTTP 源检索认证输入。
认证步骤提供通用认证活动的复用功能。通过 AuthenticationSteps
创建的步骤以一种函数式描述了认证流,将实际认证执行留给特定执行器。
AuthenticationSteps.just(VaultToken.of(…)); 1
1 | 从 VaultToken 创建 AuthenticationSteps 。 |
可以从单个输入创建一个单步认证流。声明多个认证步骤的流以 Supplier
或 HttpRequest
开头,提供用于映射或发布到 Vault 以实现登录的认证状态对象。
AuthenticationSteps.fromSupplier( 1
() -> getAppRoleLogin(options.getRoleId(), options.getSecretId())) 2
.login("auth/{mount}/login", options.getPath()); 3
1 | 开始声明接受 Supplier<T> 的 AuthenticationSteps 。状态对象类型取决于 Supplier 响应类型,可以稍后映射。 |
2 | 实际的 Supplier 实现。在这种情况下,创建一个 Map 。 |
3 | 通过将状态对象 (Map ) 发送到 Vault 端点以进行 Vault 令牌创建,执行 Vault 登录。请注意,模板变量会受到 URL 转义的影响。 |
认证流需要执行器来执行实际登录。我们为不同的执行模型提供了两个执行器:
-
AuthenticationStepsExecutor
可以作为同步ClientAuthentication
的直接替换。 -
AuthenticationStepsOperator
for reactive execution.
多个 ClientAuthentication’s come with static factory methods to create `AuthenticationSteps
用于其特定的认证选项:
AuthenticationSteps
executionCubbyholeAuthenticationOptions options = …
RestOperations restOperations = …
AuthenticationSteps steps = CubbyholeAuthentication.createAuthenticationSteps(options);
AuthenticationStepsExecutor executor = new AuthenticationStepsExecutor(steps, restOperations);
VaultToken token = executor.login();
Token Lifecycle
Vault 的令牌可以与生存时间关联。通过认证方法获取的令牌打算在会话处于活动状态时使用,并且在应用程序处于活动状态时不应过期。
Spring Vault 使用 LifecycleAwareSessionManager
提供 {self-docs-root}api/org/springframework/vault/authentication/LifecycleAwareSessionManager.html[LifecycleAwareSessionManager
] 会话管理器,该会话管理器可以续订令牌,直到其达到其终端 TTL,然后执行另一项登录以获取与该会话关联的下一个令牌。
根据认证方法的不同,登录可以创建两种令牌:
-
{self-docs-root}api/org/springframework/vault/support/VaultToken.html[
VaultToken
]:封装实际令牌的通用令牌。 -
{self-docs-root}api/org/springframework/vault/authentication/LoginToken.html[
LoginToken
]:与可更新性/TTL 相关的令牌。
{self-docs-root}api/org/springframework/vault/authentication/TokenAuthentication.html[TokenAuthentication
] 等身份验证方法仅创建一个 VaultToken
,该 VaultToken
不包含任何续订/TTL 详细信息。LifecycleAwareSessionManager
会对令牌进行自查找以从 Vault 中检索续订和 TTL。VaultToken
启用了自查找后会定期续订。请注意,VaultToken
永远不会被吊销,只有 LoginToken
会被吊销。
直接创建 LoginToken
的认证方法(所有基于登录的认证方法)已经提供了设置令牌续订所需的所有必要详细信息。如果会话管理器关闭,LifecycleAwareSessionManager
会吊销从登录获得的令牌。