身份驗證方法
不同的組織對安全和身份驗證有不同的要求。Vault 透過提供多種身份驗證方法來反映這一需求。Spring Vault 支援多種身份驗證機制。
外部化登入憑據
首次訪問受保護系統稱為安全引入。任何客戶端都需要臨時或永久憑據才能訪問 Vault。外部化憑據是保持程式碼可維護性高的良好模式,但存在披露風險增加的問題。
向任何一方披露登入憑據都允許登入 Vault 並訪問底層角色允許的秘密。選擇合適的客戶端身份驗證並將憑據注入應用程式需要進行風險評估。
Spring 的 PropertySource 抽象非常適合將配置保留在應用程式程式碼之外。您可以使用系統屬性、環境變數或屬性檔案來儲存登入憑據。每種方法都有其自身的屬性。請記住,可以透過適當的作業系統訪問級別內省命令列和環境屬性。
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。
令牌身份驗證
令牌是 Vault 中身份驗證的核心方法。令牌身份驗證需要提供靜態令牌。
| 令牌身份驗證是預設的身份驗證方法。如果令牌被未經授權的一方洩露,它將獲得對 Vault 的訪問許可權,並可以訪問目標客戶端的秘密。 |
通常,令牌身份驗證用於令牌在外部建立和續訂的場景(例如 HashiCorp Vault 服務代理)。根據實際設定,您可能希望或不希望令牌續訂和撤銷。有關 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, 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 身份驗證
aws-ec2 身份驗證後端為 AWS EC2 例項提供了安全的引入機制,允許自動檢索 Vault 令牌。與大多數 Vault 身份驗證後端不同,此後端不需要首先部署或預配安全敏感的憑據(令牌、使用者名稱/密碼、客戶端證書等)。相反,它將 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,該 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, 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 令牌。與大多數 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 身份驗證
gcp 身份驗證後端允許使用現有的 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 身份驗證後端不同,此後端不需要首先部署或預配安全敏感的憑據(令牌、使用者名稱/密碼、客戶端證書等)。相反,它將 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 身份驗證
gcp 身份驗證後端允許使用現有的 GCP (Google Cloud Platform) IAM 和 GCE 憑據進行 Vault 登入。
GCP IAM 身份驗證以 JSON Web Token (JWT) 的形式為服務帳戶建立簽名。服務帳戶的 JWT 是透過呼叫 GCP IAM 的 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 都是同步的,因此 GcpIamCredentialsAuthentication 不支援 AuthenticationSteps,而 AuthenticationSteps 是響應式使用所必需的。 |
GcpIamCredentialsAuthentication 使用 IAM 憑據 API,並且是使用已棄用的 IAM API 的已棄用 GcpIamAuthentication 的替代品。 |
另請參閱
GitHub 身份驗證
github 身份驗證後端提供基於 GitHub 令牌的身份驗證機制。Vault 不支援 OAuth 工作流來生成 GitHub 令牌,因此它不作為 GitHub 應用程式執行。
身份驗證機制需要一個 GitHub 令牌(或供應商)才能將令牌傳遞給 Vault,然後 Vault 會針對您的 GitHub 帳戶進行身份驗證。
@Configuration
class AppConfig extends AbstractVaultConfiguration {
// …
@Override
public ClientAuthentication clientAuthentication() {
GitHubAuthentication options = GitHubAuthentication.builder()
.token(…).build();
return new GitHubAuthentication(options, restOperations());
}
// …
}
另請參閱
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,
restOperations());
}
// …
}
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, restOperations());
}
// …
}
Cubbyhole 身份驗證
Cubbyhole 身份驗證使用 Vault 原語提供安全的身份驗證工作流。Cubbyhole 身份驗證使用令牌作為主要登入方法。臨時令牌用於從 Vault 的 Cubbyhole 秘密後端獲取第二個登入 VaultToken。登入令牌通常具有更長的生命週期,用於與 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());
}
// …
}
使用儲存的令牌
$ 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/可續訂性
從 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, restOperations());
}
// …
}
另請參閱
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, restOperations());
}
// …
}
您可以透過 KubernetesAuthenticationOptions 配置身份驗證。
另請參閱
使用者名稱/密碼身份驗證
使用者名稱/密碼通常是一種終端使用者身份驗證方案。多個 Vault 身份驗證後端支援使用使用者名稱和密碼
-
使用者名稱和密碼 (
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());
}
// …
}
另請參閱
身份驗證步驟
ClientAuthentication 物件描述身份驗證流並執行實際的身份驗證步驟。預設的身份驗證易於使用,並且可以透過與同步執行的緊密繫結進行配置。
身份驗證方法的組合和重用通用步驟(例如將登入負載釋出到 Vault 或從 HTTP 源檢索身份驗證輸入)不適用於 ClientAuthentication 物件。
身份驗證步驟提供了通用身份驗證活動的可重用性。透過 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用於響應式執行。
許多 ClientAuthentication 都帶有靜態工廠方法,用於為其身份驗證特定選項建立 AuthenticationSteps
AuthenticationSteps 執行CubbyholeAuthenticationOptions options = …
RestOperations restOperations = …
AuthenticationSteps steps = CubbyholeAuthentication.createAuthenticationSteps(options);
AuthenticationStepsExecutor executor = new AuthenticationStepsExecutor(steps, restOperations);
VaultToken token = executor.login();
令牌生命週期
Vault 的令牌可以與生存時間相關聯。透過身份驗證方法獲得的令牌旨在只要會話處於活動狀態就一直使用,並且不應在應用程式處於活動狀態時過期。
Spring Vault 提供了 LifecycleAwareSessionManager,它是一個會話管理器,可以續訂令牌直到它達到其終端 TTL,然後執行另一次登入以獲取與會話關聯的下一個令牌。
根據身份驗證方法,登入可以建立兩種令牌
-
VaultToken:封裝實際令牌的通用令牌。 -
LoginToken:與可續訂性/TTL 關聯的令牌。
諸如 TokenAuthentication 之類的身份驗證方法只建立 VaultToken,它不攜帶任何可續訂性/TTL 詳細資訊。 LifecycleAwareSessionManager 將對令牌執行自查詢以從 Vault 檢索可續訂性和 TTL。如果啟用了自查詢,則 VaultToken 會定期續訂。請注意,VaultToken 永遠不會被撤銷,只有 LoginToken 會被撤銷。
直接建立 LoginToken 的身份驗證方法(所有基於登入的身份驗證方法)已經提供了設定令牌續訂所需的所有詳細資訊。如果會話管理器關閉,則從登入獲得的令牌將由 LifecycleAwareSessionManager 撤銷。