Using a Credentials Provider

与数据存储器交互通常意味着首先使用凭据进行连接。这些凭据将允许对客户端进行识别、验证和最终授权。基于用户名/密码的验证非常常见,但这绝不是唯一的一种。此类凭据信息可能出现在应用程序配置中,但将此类敏感信息存储在安全存储中(如 HashiCorp Vault、Azure Key Vault 或 AWS Secrets Manager,仅举几例)正变得越来越普遍。

Interacting with a datastore typically implies first connecting using credentials. Those credentials will allow the client to be identified, authenticated and eventually authorized. Username/password based authentication is very common, but that is not by any means the only one. Such credentials information may appear in the application configuration, but it is becoming increasingly popular to store this type of sensitive information in secure stores, such as HashiCorp Vault, Azure Key Vault or the AWS Secrets Manager to name just a few.

为了桥接消耗不同形式的凭据的数据存储和提供这些凭据的安全存储,Quarkus 引入了名为 Credentials Provider 的中间抽象,一些扩展可能支持以消耗凭据(例如,agroal),而其他一些可能实现以生成凭据(例如,vault)。

To bridge datastores that consume credentials, which can take different forms, and secure stores that provide those credentials, Quarkus introduces an intermediate abstraction called Credentials Provider, that some extensions may support to consume credentials (e.g. agroal), and some others may implement to produce credentials (e.g. vault).

该服务编程接口 (SPI) 也可被希望支持 Quarkus 中尚未实现的自定义提供程序(例如,Azure Key Vault)的实现者使用。

This Service Programming Interface (SPI) may also be used by implementers that want to support custom providers not yet implemented in Quarkus (e.g. Azure Key Vault).

目前,Credentials Provider 接口由 vault 扩展实现,并由以下凭据使用者扩展支持:

Currently, the Credentials Provider interface is implemented by the vault extension, and is supported by the following credentials consumer extensions:

  • agroal

  • reactive-db2-client

  • reactive-mysql-client

  • reactive-mssql-client

  • reactive-oracle-client

  • reactive-pg-client

  • oidc

  • oidc-client

  • messaging-rabbitmq

所有依赖于用户名/密码身份验证的扩展也允许将配置属性设置为 application.properties 的替代。但是,如果生成凭据(例如,Vault Dynamic DB Credentials)或需要自定义凭据提供程序,则 Credentials Provider 是唯一选项。

All extensions that rely on username/password authentication also allow setting configuration properties in the application.properties as an alternative. But the Credentials Provider is the only option if credentials are generated (e.g. Vault Dynamic DB Credentials) or if a custom credentials provider is required.

本指南将展示如何使用 vault 扩展中提供的 Credentials Provider,然后我们将研究如何实现自定义 Credentials Provider,最后我们将讨论有关在新扩展中实现 Credentials Provider 的其他注意事项。

This guide will show how to use the Credentials Provider provided in the vault extension, then we will look at implementing a custom Credentials Provider, and finally we will talk about additional considerations regarding implementing a Credentials Provider in a new extension. Unresolved directive in credentials-provider.adoc - include::{includes}/extension-status.adoc[]

Vault Credentials Provider

要配置 Vault Credentials Provider,你需要提供以下属性:

To configure a Vault Credentials Provider you need to provide the following properties:

quarkus.vault.credentials-provider.<name>.<property>=<value>

<name> 将在使用者中用于引用此提供程序。<property><value> 字段特定于 Vault Credentials Provider。有关完整详细信息,请参阅 {vault-datasource-guide}。

The <name> will be used in the consumer to refer to this provider. The <property> and <value> fields are specific to the Vault Credentials Provider. For complete details, please refer to the {vault-datasource-guide}.

例如:

For instance:

quarkus.vault.credentials-provider.mydatabase.kv-path=myapps/vault-quickstart/db

一旦定义,mydatabase 提供程序即可在任何支持 Credentials Provider 接口的扩展中使用。例如,在 agroal 中:

Once defined, the mydatabase provider can be used in any extension that supports the Credentials Provider interface. For instance in agroal:

# configure your datasource
quarkus.datasource.db-kind = postgresql
quarkus.datasource.username = sarah
quarkus.datasource.credentials-provider = mydatabase
quarkus.datasource.jdbc.url = jdbc:postgresql://localhost:5432/mydatabase

请注意,quarkus.datasource.username 是原始 agroal 属性,而 password 属性未包含,因为值将来自我们刚刚定义的 mydatabase 凭据提供程序。另一种方法是在 Vault 中定义用户名和密码,并从配置中删除 quarkus.datasource.username 属性。所有正在使用的扩展都支持从提供程序获取用户名和密码,或仅获取密码。

Note that quarkus.datasource.username is the original agroal property, whereas the password property is not included because the value will come from the mydatabase credentials provider we just defined. An alternative is to define both username and password in Vault and drop the quarkus.datasource.username property from configuration. All consuming extensions do support the ability to fetch both the username and password from the provider, or just the password.

Time Limited Credentials

凭据提供程序可能会提供有限时凭据。例如,vault 扩展。在使用有限时凭据时,重要的是要了解凭据提供程序不会自动刷新正在使用的扩展的凭据。必须对每个扩展进行配置,以便在凭据到期之前回收其连接。

A Credentials Provider may provide time limited credentials. For instance, the vault extension. When using time limited credentials, it is important to understand that consuming extensions will not have their credentials refreshed automatically by the Credentials Provider. Each extension must be configured to recycle its connections before the credentials expire.

Datasources

数据存储连接通常是池化的。在使用有限时凭据提供程序时,必须将连接池配置为在每个连接的凭据到期之前回收连接。JDBC 和 Reactive 数据源都包含一个 max-lifetime 配置属性,可用于实现此目的。

Datastore connections are typically pooled. When using a time limited credentials provider, the pool must be configured to recycle connections before each connection’s credentials expire. Both JDBC and Reactive datasources have a max-lifetime configuration property that can be used to achieve this.

JDBC Datasource
quarkus.datasource.jdbc.max-lifetime=60m
Reactive Datasource
quarkus.datasource.reactive.max-lifetime=60m

由开发人员负责确保数据源的 max-lifetime 属性配置小于凭据到期时间。

It is the developer’s responsibility to ensure that the configuration of the datasource’s max-lifetime property is less than the credentials expiration time.

RabbitMQ

在使用 messaging-rabbitmq 扩展时,不需要配置。该扩展将根据凭据提供程序提供的到期时间戳在凭据到期之前自动回收连接。

When using the messaging-rabbitmq extension there is no configuration needed. The extension will automatically recycle connections before their credentials expire based on the expiration timestamp provided by the Credentials Provider.

Custom Credentials Provider

在 Quarkus 中尚未支持保险箱产品或者需要从自定义存储中检索凭据时,实现自定义凭据提供程序是唯一选择。

Implementing a custom credentials provider is the only option when a vault product is not yet supported in Quarkus, or if credentials need to be retrieved from a custom store.

需要实现的唯一界面是:

The only interface to implement is:

public interface CredentialsProvider {

    String USER_PROPERTY_NAME = "user";
    String PASSWORD_PROPERTY_NAME = "password";

    Map<String, String> getCredentials(String credentialsProviderName);

}

`USER_PROPERTY_NAME`和`PASSWORD_PROPERTY_NAME`是标准属性,任何支持基于用户名/密码进行认证的扩展都可以识别这两个属性。

USER_PROPERTY_NAME and PASSWORD_PROPERTY_NAME are standard properties that should be recognized by any consuming extension that support username/password based authentication.

需要实现为有效的`@ApplicationScoped`CDI bean。

It is required that implementations be valid @ApplicationScoped CDI beans.

这是一个简单的示例:

Here is a simple example:

@ApplicationScoped
@Unremovable
public class MyCredentialsProvider implements CredentialsProvider {

    @Override
    public Map<String, String> getCredentials(String credentialsProviderName) {

        Map<String, String> properties = new HashMap<>();
        properties.put(USER_PROPERTY_NAME, "hibernate_orm_test");
        properties.put(PASSWORD_PROPERTY_NAME, "hibernate_orm_test");
        return properties;
    }

}

请注意,我们决定同时返回用户名和密码。

Note that we decided here to return both the username and the password.

此提供程序可以在数据源定义中像这样使用:

This provider may be used in a datasource definition like this:

quarkus.datasource.db-kind=postgresql
quarkus.datasource.credentials-provider=custom
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5431/hibernate_orm_test

也可以使用标准 MicroProfile 配置注入的方式向提供程序传递配置属性:

It is also possible to pass configuration properties to the provider using standard MicroProfile Config injection:

custom.foo=bar

并且在提供程序实现中:

And in the provider implementation:

@Inject
Config config;

@Override
public Map<String, String> getCredentials(String credentialsProviderName) {

    System.out.println("MyCredentialsProvider called with foo=" + config.getValue(credentialsProviderName + ".foo", String.class));
    ...
}

New Credentials Provider extension

在新的扩展中创建自定义凭据提供程序时,还有几项其他注意事项。

When creating a custom credentials provider in a new extension, there are a few additional considerations.

首先,您需要为其命名以避免在项目中存在多个凭据提供程序时发生冲突:

First, you need to name it to avoid collisions in case multiple credentials providers are available in the project:

@ApplicationScoped
@Unremovable
@Named("my-credentials-provider")
public class MyCredentialsProvider implements CredentialsProvider {

用户的责任是允许有`credentials-provider-name`属性:

It is the responsibility of the consumer to allow a credentials-provider-name property:

quarkus.datasource.credentials-provider = custom
quarkus.datasource.credentials-provider-name = my-credentials-provider

扩展应该允许运行时配置,例如允许来自`vault`扩展的`CredentialsProviderConfig`配置提供程序中的任何自定义属性。对于 AWS Secrets Manager 扩展,可以如下配置:

The extension should allow runtime config, such as the CredentialsProviderConfig from the vault extension to configure any custom property in the provider. For an AWS Secrets Manager extension, this could be:

  • region

  • credentials-type

  • secrets-id

还要注意,一些用户(例如 agroal)会将其连接配置添加到凭据提供程序返回的任何属性中,而不仅仅是用户名和密码。因此,在设计新的凭据提供程序时,将属性限制为用户可以理解的属性,或者提供适当的配置选项以支持不同的模式。

Note also that some consumers such as agroal will add to their connection configuration any properties returned by the credentials provider, not just the username and password. So when you design the new credentials provider limit the properties to what would be understood by consumers, or provide appropriate configuration options to support different modes.