認證方法

不同的組織對安全和認證有不同的要求。Vault 透過提供多種認證方法反映了這一需求。Spring Vault 支援多種認證機制。

外部化登入憑據

首次訪問安全系統被稱為安全引入。任何客戶端都需要臨時或永久憑據來訪問 Vault。外部化憑據是一個保持程式碼高可維護性的良好模式,但也帶來了增加洩露的風險。

將登入憑據洩露給任何一方都允許登入 Vault 並訪問基礎角色允許的 Secrets。選擇合適的客戶端認證並將憑據注入應用程式需要進行風險評估。

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,瞭解在元件和其他屬性源中引用屬性的示例。

Token 認證

Tokens 是 Vault 中核心的認證方法。Token 認證需要提供一個靜態 Token。

Token 認證是預設的認證方法。如果 Token 洩露給未經授權的方,則該方將獲得 Vault 的訪問許可權,並可以訪問預期客戶端的 Secrets。

通常,Token 認證用於 Token 在外部建立和續期的場景(例如 HashiCorp Vault service broker)。根據實際設定,您可能希望或不希望進行 Token 續期和撤銷。請參見 LifecycleAwareSessionManager 瞭解有關 TTL 和 Token 撤銷的詳細資訊。

@Configuration
class AppConfig extends AbstractVaultConfiguration {

    // …

    @Override
    public ClientAuthentication clientAuthentication() {
        return new TokenAuthentication("…");
    }

    // …
}

另請參見

AppId 認證

AppId 認證已被 Vault 棄用。請改用 AppRole 認證

Vault 支援 AppId 認證,該認證由兩個難以猜測的 Token 組成。AppId 預設為靜態配置的 spring.application.name。第二個 Token 是 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
包含 echo 的換行符會導致不同的雜湊值,因此請務必包含 -n 標誌。

基於 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 地址指定為大寫且不含冒號。包含 echo 的換行符會導致不同的雜湊值,因此請務必包含 -n 標誌。

自定義 UserId

一種更高階的方法允許您實現自己的 AppIdUserIdMechanism。此類別必須位於您的類路徑中,並且必須實現 org.springframework.vault.authentication.AppIdUserIdMechanism 介面和 createUserId 方法。Spring Vault 將在每次使用 AppId 進行認證以獲取 Token 時,透過呼叫 createUserId 來獲取 UserId。

MyUserIdMechanism.java
public class MyUserIdMechanism implements AppIdUserIdMechanism {

  @Override
  public String createUserId() {

    String userId = …
    return userId;
  }
}

AppRole 認證

AppRole 允許機器認證,類似於已棄用(自 Vault 0.6.1 起)的 AppId 認證。AppRole 認證由兩個難以猜測的(秘密)Token 組成:RoleId 和 SecretId。

Spring Vault 支援 AppRole 認證,可以透過僅提供 RoleId,或同時提供 SecretId 並從 Vault 獲取 RoleId/SecretId(帶響應解包的 push 和 pull 模式)。

@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 還支援完整的 pull 模式:如果未提供 RoleId 和 SecretId,Spring Vault 將使用角色名和初始 Token 來獲取它們。初始 Token 可能與 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 Token。與大多數 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 一起儲存在認證後端。重新認證需要傳送相同的 nonce。任何其他方沒有該 nonce,可以在 Vault 中引發警報以進行進一步調查。

nonce 儲存在記憶體中,並在應用程式重啟時丟失。

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());
    }

    // …
}
示例 2. 使用 AWS-EC2 例項配置檔案作為憑據源
@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 Token。與大多數 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 認證

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 認證後端不同,此後端不需要首先部署或配置安全性敏感的憑據(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 認證

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,
				restOperations());
    }

    // …
}

GcpIamCredentialsAuthenticationOptions 需要 Google Cloud Java SDK 依賴項 (com.google.cloud:google-cloud-iamcredentials),因為認證實現使用 Google API 進行憑據和 JWT 簽名。

您可以透過 GcpIamCredentialsAuthenticationOptions 配置認證。

Google 憑據需要維護 Token 生命週期的 OAuth 2 Token。所有 API 都是同步的,因此 GcpIamCredentialsAuthentication 不支援響應式使用所需的 AuthenticationSteps
GcpIamCredentialsAuthentication 使用 IAM Credentials API,它是替代已棄用的 GcpIamAuthentication(使用已棄用的 IAM API)的方式。

另請參見

PCF 認證

pcf 認證後端允許 PCF 例項登入 Vault。它利用了 PCF 的應用程式和容器身份保障

PCF 認證使用例項金鑰和證書建立一個由 Vault 驗證的簽名。如果簽名匹配,並且潛在繫結的組織/空間/應用程式 ID 匹配,Vault 會頒發一個適當範圍的 Token。

例項憑據可從 CF_INSTANCE_CERTCF_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 認證後端允許使用 SSL/TLS 客戶端證書進行認證,這些證書可以由 CA 簽名或自簽名。

要啟用 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, restOperations());
    }

    // …
}

Cubbyhole 認證

Cubbyhole 認證使用 Vault 原語提供安全的認證工作流。Cubbyhole 認證使用 Tokens 作為主要的登入方法。一個臨時 Token 用於從 Vault 的 Cubbyhole Secret 後端獲取第二個登入 VaultToken。登入 Token 通常具有更長的生命週期,用於與 Vault 互動。登入 Token 可以從包裝的響應或從 data 部分中獲取。

建立包裝的 Token

Response Wrapping 建立 Token 需要 Vault 0.6.0 或更高版本。
示例 3. 建立和儲存 Token
$ 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. 包裝 Token 響應的使用
@Configuration
class AppConfig extends AbstractVaultConfiguration {

    // …

    @Override
    public ClientAuthentication clientAuthentication() {

        CubbyholeAuthenticationOptions options = CubbyholeAuthenticationOptions
                .builder()
                .initialToken(VaultToken.of("…"))
                .wrapped()
                .build();

        return new CubbyholeAuthentication(options, restOperations());
    }

    // …
}

使用儲存的 Token

示例 5. 建立和儲存 Token
$ 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. 儲存 Token 響應的使用
@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 相關的 Token 會在 Token 建立時開始計算其 TTL。該時間不一定與應用程式啟動時間相同。為了補償初始延遲,Cubbyhole 認證會對其與非零 TTL 相關的 Token 執行自查詢,以檢索剩餘的 TTL。Cubbyhole 認證不會對沒有 TTL 的包裝 Token 執行自查詢,因為零 TTL 表示沒有關聯的 TTL。

非包裝 Token 僅透過檢索 Token 本身無法提供關於可續期性和 TTL 的詳細資訊。自查詢將查詢可續期性和剩餘 TTL。

另請參見

JWT 認證

配置 JWT 認證需要提供 Token 或 JWT Supplier。您可以透過 JwtAuthenticationOptions 配置認證。

在 Vault 端,您可以透過啟用 JWT 認證後端並建立一個角色來配置 JWT 後端。您可以使用 oidc_discovery_urljwks_urljwt_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 Token 的 kubernetes 認證。

使用 Kubernetes 認證需要一個 Kubernetes Service Account Token,通常掛載在 /var/run/secrets/kubernetes.io/serviceaccount/token。該檔案包含讀取併發送到 Vault 的 Token。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, 額外支援基於時間的一次性 Token)

  • RADIUS (radius)

UserPasswordAuthenticationOptions 可用於上述所有認證後端,因為登入 API 在所有機制中都相似。請確保在配置 UserPasswordAuthenticationOptions 時使用適當的認證掛載路徑。

示例 7. 配置 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 建立的步驟以函式式風格描述了認證流程,將實際的認證執行留給了特定的執行器。

示例 8. 儲存的 Token 認證流程。
AuthenticationSteps.just(VaultToken.of(…));                              (1)
1 僅使用一個 VaultToken 建立 AuthenticationSteps

單步認證流程可以從單個輸入建立。宣告多個認證步驟的流程始於一個 SupplierHttpRequest,它們提供一個認證狀態物件,該物件可用於對映或傳送到 Vault 進行登入。

示例 9. AppRole 認證流程
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 Token 建立來執行 Vault 登入。請注意,模板變數受 URL 轉義的影響。

認證流程需要一個執行器來執行實際的登入。我們為不同的執行模型提供了兩個執行器

  • AuthenticationStepsExecutor 作為同步 ClientAuthentication 的直接替代。

  • AuthenticationStepsOperator 用於響應式執行。

許多 ClientAuthentication 提供了靜態工廠方法來為其特定於認證的選項建立 AuthenticationSteps

示例 10. 同步 AuthenticationSteps 執行
CubbyholeAuthenticationOptions options = …
RestOperations restOperations = …

AuthenticationSteps steps = CubbyholeAuthentication.createAuthenticationSteps(options);

AuthenticationStepsExecutor executor = new AuthenticationStepsExecutor(steps, restOperations);

VaultToken token = executor.login();

Token 生命週期

Vault 的 Token 可以關聯一個存活時間 (TTL)。透過認證方法獲得的 Token 旨在只要會話處於活動狀態就使用,並且不應在應用程式活動期間過期。

Spring Vault 提供了 LifecycleAwareSessionManager 會話管理器,它可以續期 Token 直到其達到最終 TTL,然後執行另一次登入以獲取與會話關聯的下一個 Token。

根據認證方法,登入可以建立兩種型別的 Token

  • VaultToken:封裝實際 Token 的通用 Token。

  • LoginToken:與可續期性/TTL 相關的 Token。

TokenAuthentication 這樣的認證方法只建立一個不包含任何可續期性/TTL 詳細資訊的 VaultToken。如果啟用了自查詢,LifecycleAwareSessionManager 將對 Token 執行自查詢以從 Vault 獲取可續期性和 TTL。如果啟用了自查詢,VaultToken 會定期續期。請注意,VaultToken 從不被撤銷,只有 LoginToken 會被撤銷。

直接建立 LoginToken 的認證方法(所有基於登入的認證方法)已經提供了設定 Token 續期所需的所有詳細資訊。如果會話管理器關閉,LifecycleAwareSessionManager 會撤銷從登入獲得的 Token。