TLS registry reference

Using TLS registry

要配置 TLS 连接,特别是密钥库和信任库,您可以使用 quarkus.tls.* 属性。

直接位于 quarkus.tls 下的配置是默认配置,该配置将被应用程序中的所有 TLS 连接使用。但是,您还可以通过使用 quarkus.tls.<name>.* 属性为特定连接设置特定配置。

Configure the HTTP server to use https://

若要配置 HTTP 服务器以使用 HTTPS,可以使用以下配置:

quarkus.tls.key-store.pem.0.cert=server.crt
quarkus.tls.key-store.pem.0.key=server.key
quarkus.http.insecure-requests=disabled # Reject HTTP requests

因此,你使用 p12(PKCS12)密钥库,请使用以下配置:

quarkus.tls.key-store.p12.path=server-keystore.p12
quarkus.tls.key-store.p12.password=secret
quarkus.http.insecure-requests=disabled # Reject HTTP requests

你可以使用命名配置,而不是默认配置:

quarkus.tls.https.key-store.p12.path=server-keystore.p12
quarkus.tls.https.key-store.p12.password=secret
quarkus.http.insecure-requests=disabled
quarkus.http.tls-configuration-name=https

Configure a client to use https://

作为说明客户端配置的示例,我们将使用 gRPC 客户端:

quarkus.tls.trust-store.jks.path=grpc-client-truststore.jks
quarkus.tls.trust-store.jks.password=password

quarkus.grpc.clients.hello.plain-text=false
quarkus.grpc.clients.hello.use-quarkus-grpc-client=true

Configuring mTLS

要配置 mTLS,您需要同时配置服务器和客户端。两者都将收到密钥库和信任库:

  • 服务器密钥库包含服务器证书和私钥

  • 客户端密钥库包含客户端证书和私钥

  • 服务器信任库包含客户端证书(用于对客户端进行身份验证)

  • 客户端信任库包含服务器证书(用于对服务器进行身份验证)

quarkus.tls.my-server.key-store.p12.path=target/certs/grpc-keystore.p12
quarkus.tls.my-server.key-store.p12.password=password
quarkus.tls.my-server.trust-store.p12.path=target/certs/grpc-server-truststore.p12
quarkus.tls.my-server.trust-store.p12.password=password

quarkus.tls.my-client.trust-store.p12.path=target/certs/grpc-client-truststore.p12
quarkus.tls.my-client.trust-store.p12.password=password
quarkus.tls.my-client.key-store.p12.path=target/certs/grpc-client-keystore.p12
quarkus.tls.my-client.key-store.p12.password=password

quarkus.grpc.clients.hello.plain-text=false
quarkus.grpc.clients.hello.tls-configuration-name=my-client
quarkus.grpc.clients.hello.use-quarkus-grpc-client=true

quarkus.http.ssl.client-auth=REQUIRED # Enable mTLS
quarkus.http.insecure-requests=disabled
quarkus.http.tls-configuration-name=my-server
quarkus.grpc.server.use-separate-server=false
quarkus.grpc.server.plain-text=false

Referencing a TLS configuration

使用 quarkus.tls.<name> 配置了 named 配置后,您需要引用它。这是通过使用 tls-configuration-name 属性完成的:

quarkus.tls.https.key-store.p12.path=server-keystore.p12
quarkus.tls.https.key-store.p12.password=secret

quarkus.http.insecure-requests=disabled
quarkus.http.tls-configuration-name=https # Reference the named configuration

Configuring TLS

配置 TLS 主要涉及密钥库和信任库。此配置取决于格式 (pemp12jks…​)。还有一些其他重要的属性。本节详细介绍了可用于配置 TLS 的各种属性。

Key stores

密钥库用于存储私钥和证书。它们主要在服务器端使用,但也可在使用 mTLS 时在客户端使用。

PEM key stores

PEM 密钥库由一对对的两个文件列表组成:证书和私钥。证书文件是 .crt.pem 文件,而私钥文件经常是 .key 文件。

要配置一个 PEM 密钥库,请使用以下属性:

quarkus.tls.key-store.pem.a.cert=server.crt
quarkus.tls.key-store.pem.a.key=server.key
quarkus.tls.key-store.pem.b.cert=my-second-cert.crt
quarkus.tls.key-store.pem.b.key=my-second-key.key

通常,你只需要一对证书和私钥。该证书可能包含多个证书(一个链),但应该有一个私钥。

当配置多对证书和私钥时,选择是使用 SNI (服务器名称指示) 完成的。客户端会发送其希望连接到的服务器名称,而服务器会选择合适的证书和私钥对。确保在客户端和服务器上均已启用 SNI,以使用此功能。

在配置多个密钥/证书对时,顺序遵循名称的词典顺序(在先前的代码段中是 a`和 `b)。因此,第一对是词典顺序最低的一对。你可以使用 quarkus.tls.key-store.pem.order`属性定义该顺序,例如: `quarkus.tls.key-store.pem.order=b,c,a。在使用 SNI 时这一点很重要,因为第一对是默认对。

PKCS12 key stores

PKCS12 密钥库是一个包含证书和私钥的单个文件。要配置一个 PKCS12 密钥库,请使用以下属性:

quarkus.tls.key-store.p12.path=server-keystore.p12
quarkus.tls.key-store.p12.password=secret

`.p12`文件是受密码保护的,因此你需要提供密码以打开该密钥库。此外,该文件可以包含多个证书和私钥。在这种情况下,你可以:

  • 提供你要使用的证书和私钥的别名

  • 或使用 SNI 以选择合适的证书和私钥(所有密钥都必须使用相同的密码)

要配置该别名,请使用以下属性:

quarkus.tls.key-store.p12.path=server-keystore.p12
quarkus.tls.key-store.p12.password=secret
quarkus.tls.key-store.p12.alias=my-alias
quarkus.tls.key-store.p12.alias-password=my-alias-password

JKS key stores

JKS 密钥库是一个包含证书和私钥的单个文件。请注意,应该避免使用 JKS 格式,因为它比 PKCS12 的安全性低。要配置一个 JKS 密钥库,请使用以下属性:

quarkus.tls.key-store.jks.path=server-keystore.jks
quarkus.tls.key-store.jks.password=secret

`.jks`文件是受密码保护的,因此你需要提供密码以打开该密钥库。此外,该文件可以包含多个证书和私钥。在这种情况下,你可以:

  • 提供你要使用的证书和私钥的别名

  • 或使用 SNI 以选择合适的证书和私钥(所有密钥都必须使用相同的密码)

要配置该别名,请使用以下属性:

quarkus.tls.key-store.jks.path=server-keystore.jks
quarkus.tls.key-store.jks.password=secret
quarkus.tls.key-store.jks.alias=my-alias
quarkus.tls.key-store.jks.alias-password=my-alias-password

SNI

服务器名称指示 (SNI) 是一个 TLS 扩展,允许客户端在 TLS 握手期间指定它尝试连接到的主机名。它允许一台服务器为单个 IP 地址上的多个域提供不同的 TLS 证书,为虚拟主机场景促进了安全通信。

要启用 SNI,请使用以下属性:

quarkus.tls.key-store.sni=true # Disabled by default

启用此设置后,客户端会在 TLS 握手期间指示服务器名称,从而允许服务器选择正确的证书:

  • 在使用 PEM 文件配置密钥库时,必须给定多个 CRT/Key。

  • 在使用 JKS 或 P12 文件配置密钥库时,它会根据 SNI 主机名选择一个别名。在这种情况下,所有密钥库密码和别名密码都必须相同。在这种情况中,不要设置 `alias`属性。

Credential providers

与其在配置中传递密钥库密码和别名密码,你可以使用凭证提供程序。

凭证提供程序提供了一种检索密钥库密码和别名密码的方法。请注意,仅当密码/别名密码未在配置中设置时,才使用凭证提供程序。

要配置凭证提供程序,请使用以下属性:

# The name of the credential bucket in the credentials provider
quarkus.tls.key-store.credentials-provider.name=my-credentials

# The name of the bean providing the credential provider (optional, using the default credential provider if not set)
quarkus.tls.key-store.credentials-provider.bean-name=my-credentials-provider

# The key used to retrieve the key store password, `password` by default
quarkus.tls.key-store.credentials-provider.password-key=password

# The key used to retrieve the alias password, `alias-password` by default
quarkus.tls.key-store.credentials-provider.alias-password-key=alias-password

凭据提供程序只能与 PKCS12 和 JKS 密钥库一起使用。

Trust stores

信任库用于存储受信任方证书。它们通常用于客户端,当使用 mTLS 时也在服务器端使用。

PEM trust stores

PEM 信任库由 .crt.pem 文件列表组成。每个都包含一个证书。

要配置 PEM 信任库,请使用以下属性:

quarkus.tls.trust-store.pem.certs=ca.crt,ca2.pem

PKCS12 trust stores

PKCS12 信任库是一个包含证书的单个文件。当包含多个证书时,可以使用别名选择适当的证书。

要配置 PKCS12 信任库,请使用以下属性:

quarkus.tls.trust-store.p12.path=client-truststore.p12
quarkus.tls.trust-store.p12.password=password
quarkus.tls.trust-store.p12.alias=my-alias

.p12 文件受密码保护,因此您需要提供密码才能打开信任库。然而,不同于密钥库,别名不需要密码(因为它不是私钥而是公钥证书)。

JKS trust stores

JKS 信任库是一个包含证书的单个文件。当包含多个证书时,可以使用别名选择适当的证书。请注意,应避免使用 JKS 格式,因为它不如 PKCS12 安全。

要配置 JKS 信任库,请使用以下属性:

quarkus.tls.trust-store.jks.path=client-truststore.jks
quarkus.tls.trust-store.jks.password=password
quarkus.tls.trust-store.jks.alias=my-alias

.jks 文件受密码保护,因此您需要提供密码才能打开信任库。然而,不同于密钥库,别名不需要密码(因为它不是私钥而是公钥证书)。

Credential providers

您可以使用凭据提供程序,而不必在配置中传递信任库密码。

凭据提供程序提供了一种检索密码和其他凭证的方法。请注意,仅当配置中未设置密码时才使用凭据提供程序。

要配置凭证提供程序,请使用以下属性:

# The name of the credential bucket in the credentials provider
quarkus.tls.trust-store.credentials-provider.name=my-credentials

# The name of the bean providing the credential provider (optional, using the default credential provider if not set)
quarkus.tls.trust-store.credentials-provider.bean-name=my-credentials-provider

# The key used to retrieve the trust store password, `password` by default
quarkus.tls.trust-store.credentials-provider.password-key=password

凭据提供程序只能与 PKCS12 和 JKS 信任库一起使用。

Other properties

虽然密钥库和信任库是最重要的属性,但您还可以使用其他属性来配置 TLS。

虽然以下示例使用 default 配置,但您可以通过在属性前加上配置名称来使用 named 配置。

Cipher suites

密码套件是 TLS 握手期间可使用密码的列表。您可以配置已启用密码套件的有序列表。如果没有配置,则从内置密码中选择一个合理的默认值。然而,当配置后,它优先于正在使用的 SSL 引擎定义的默认套件。

要配置密码套件,请使用以下属性:

quarkus.tls.cipher-suites=TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384

TLS protocol versions

TLS 协议版本是 TLS 握手期间可使用协议的列表。您可以配置已启用 TLS 协议的有序列表。如果没有配置,则默认为 TLSv1.3TLSv1.2

支持:TLSv1TLSv1.1TLSv1.2TLSv1.3

若要仅启用`TLSv1.3`,请配置以下属性:

quarkus.tls.protocols=TLSv1.3

Handshake timeout

当建立 TLS 连接时,握手阶段是第一个步骤。在此阶段,客户端和服务器交换信息以建立连接,通常是密码套件、TLS 协议版本、认证验证等等。

若要配置握手阶段的超时,请使用以下属性:

quarkus.tls.handshake-timeout=10S # Default.

ALPN

应用程序层协议协商 (ALPN) 是 TLS 扩展,允许客户端和服务器在 TLS 握手过程中协商它们将用于通信的协议。ALPN 通过允许客户端在 TLS 连接建立之前向服务器指示其首选应用程序协议,从而实现更有效的通信。

这有助于在诸如 HTTP/2 之类的场景中,其中可能有多个协议可用,从而实现更快的协议选择。

ALPN 默认启用。若要禁用它,请使用以下属性:

quarkus.tls.alpn=false

Certificate Revocation List (CRL)

证书吊销列表 (CRL) 是一个证书列表,该列表中的证书在其预定的到期日期之前已被颁发证书颁发机构 (CA) 吊销。当证书被破坏、不再需要或由于任何原因被视为无效时,CA 将其添加到 CRL 中以告知依赖方不再信任该证书。

您可以使用不再信任的证书文件列表来配置 CRL。允许使用两种格式:DER 和 PKCS#7(也称为 P7B)。

  • 使用 DER 格式时,必须传递 DER 编码的 CRL。

  • 使用 PKCS#7 格式时,必须传递 PKCS#7 SignedData`对象,其中唯一重要的字段是`crls

若要配置 CRL,请使用以下属性:

quarkus.tls.certificate-revocation-list=ca.crl, ca2.crl

Trusting all certificates and hostname verification

这两个属性不应在生产中使用。

您可以配置您的 TLS 连接以信任所有证书并禁用主机名验证。这两个步骤是不同的:

  • 信任所有证书将忽略证书验证,因此所有证书都是可信的。这对于使用自签名证书进行测试很有用,但不应在生产中使用。

  • 主机名验证是验证服务器身份的过程。这有助于防止中间人攻击。它通常默认为`HTTPS`或`LDAPS`。

若要信任所有证书,请使用以下属性:

quarkus.tls.trust-all=true

若要禁用主机名验证,请使用以下属性:

quarkus.tls.hostname-verification-algorithm=NONE

Configuration reference

下表列出了受支持的属性:

Unresolved include directive in modules/ROOT/pages/tls-registry-reference.adoc - include::../../../target/quarkus-generated-doc/config/quarkus-tls-registry.adoc[]

The registry API

尽管扩展程序会自动使用 TLS 注册表,你也可以使用注册表 API 以编程方式访问 TLS 配置。

若要访问 TLS 配置,请注入 TlsConfigurationRegistry bean,通过名称(或默认名称)获取 TLS 配置:

 @Inject
 TlsConfigurationRegistry certificates;
// ...
TlsConfiguration def = certificates.getDefault().orElseThrow();
TlsConfiguration named = certificates.get("name").orElseThrow();
//...

TlsConfiguration 对象包含密钥存储、信任存储、密码套件、协议和其他属性。它还提供一种从配置创建 SSLContext 的方法。

由于 Vert.x 存在于 Quarkus 的各个方面,因此你还可以使用 TlsConfiguration 对象,配置 Vert.x 客户端或服务器,例如 KeyCertOptionsTrustOptions 等。

Registering a certificate from an extension

此部分仅供扩展开发者使用。扩展可以注册 TLS 注册表中的证书。当扩展需要为应用程序提供证书或提供不同格式时,此举很有用。

为了实现此目的,扩展 processor 必须生成 TlsCertificateBuildItemTlsCertificateBuildItem 由名称和 CertificateSupplier 组成。

TlsCertificateBuildItem item = new TlsCertificateBuildItem("named",
    new MyCertificateSupplier());

证书供应商是运行时对象,通常使用记录器方法进行检索。以下是证书供应商示例:

public class MyCertificateSupplier implements Supplier<TlsConfiguration> {

        @Override
        public TlsConfiguration get() {
            try {
                KeyStore ks = KeyStore.getInstance("PKCS12");
                ks.load(getClass().getResourceAsStream("target/certs/test-registration-keystore.p12"),
                        "password".toCharArray());
                KeyStore ts = KeyStore.getInstance("PKCS12");
                ts.load(getClass().getResourceAsStream("target/certs/test-registration-truststore.p12"),
                        "password".toCharArray());
                return new BaseTlsConfiguration() {
                    @Override
                    public KeyStore getKeyStore() {
                        return ks;
                    }

                    @Override
                    public KeyStore getTrustStore() {
                        return ts;
                    }
                };
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

Startup checks

在应用程序启动时,TLS 注册表会执行一些检查以确保配置正确:

  • 密钥库和信任库可以访问

  • 别名在密钥库和信任库中可用且可以访问

  • the certificates are valid

  • 密码套件和协议有效

  • the CRLs are valid

如果这些检查有任何一项失败,应用程序都将无法启动。

Reloading certificates

TLSConfigurationRegistry 获取的 TlsConfiguration 包含用于重新加载证书的机制。reload 方法刷新密钥库和信任库,通常会从文件系统重新加载。

重新加载操作不是自动的,必须手动触发。此外,TlsConfiguration 实现必须支持重新加载(配置的证书的情况)。

reload 方法返回 boolean,用于指示重新加载是否成功。值为 true 意味着重新加载操作成功,但并不一定意味着证书已有更新。

TlsConfiguration 重新加载后,使用此配置的服务器和客户端可能需要执行特定操作来应用新证书。建议的做法是触发服务器和客户端可以侦听并做出必要更改的 CDI 事件 (CertificateReloadedEvent):

@Inject
TlsConfigurationRegistry registry;

public void reload() {
    TlsConfiguration config = registry.get("name").orElseThrow();
    if (config.reload()) {
        event.fire(new CertificateReloadedEvent("name", config));
    }
}

// In the server or client code
public void onReload(@Observes CertificateReloadedEvent event) {
    if ("name".equals(event.getName())) {
        server.updateSSLOptions(event.tlsConfiguration().getSSLOptions());
        // Or update the SSLContext.
    }
}

这些 API 提供了一种实现自定义证书重新加载的方法。

Periodic reloading

TLS 注册表确实包括一种内置机制,用于定期检查文件系统中的更改并重新加载证书。你可以使用属性配置定期重新加载证书。reload-period 属性指定重新加载证书的时间间隔,并会发出 CertificateReloadedEvent

quarkus.tls.reload-period=1h
quarkus.tls.key-store.pem.0.cert=tls.crt
quarkus.tls.key-store.pem.0.key=tls.key

你可以在每个命名的配置中设置特定重新加载时间:

quarkus.tls.http.reload-period=30min
quarkus.tls.http.key-store.pem.0.cert=tls.crt
quarkus.tls.http.key-store.pem.0.key=tls.key

请记住,受影响的服务器和客户端可能需要侦听 CertificateReloadedEvent 以应用新证书。Quarkus HTTP 服务器(包括启用的管理界面)会自动完成此操作。

Using Kubernetes secrets or cert-manager

在 Kubernetes 中运行时,可以使用 Kubernetes 秘钥来存储密钥库和信托库。

Using Kubernetes secrets

要使用 Kubernetes 秘钥,需要使用密钥库和信托库创建一个秘钥。我们以以下秘钥为例:

apiVersion: v1
data:
  tls.crt: ...
  tls.key: ...
kind: Secret
metadata:
  name: my-certs
type: kubernetes.io/tls

使用这些证书的最简单方法是将秘钥作为 Pod 中的一个卷进行挂载:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/name: demo
    app.kubernetes.io/version: 1.0.0-SNAPSHOT
    app.kubernetes.io/managed-by: quarkus
  name: demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: demo
      app.kubernetes.io/version: 1.0.0-SNAPSHOT
  template:
    metadata:
      labels:
        app.kubernetes.io/managed-by: quarkus
        app.kubernetes.io/name: demo
        app.kubernetes.io/version: 1.0.0-SNAPSHOT
    spec:
      containers:
        - env:
            - name: KUBERNETES_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          image: ...
          imagePullPolicy: IfNotPresent
          name: demo
          ports:
            - containerPort: 8443 # Configure the port to be HTTPS
              name: http
              protocol: TCP
          volumeMounts:
            - mountPath: /certs
              name: my-volume
      volumes:
        - name: my-volume
          secret:
            defaultMode: 0666 # Set the permissions, otherwise the pod may not be able to read the files
            optional: false
            secretName: my-certs # Reference the secret

然后,可以将 TLS 注册表配置为使用这些证书:

# ...
# TLS Registry configuration
%prod.quarkus.tls.http.key-store.pem.0.cert=/certs/tls.crt
%prod.quarkus.tls.http.key-store.pem.0.key=/certs/tls.key

# HTTP server configuration:
%prod.quarkus.http.tls-configuration-name=http
%prod.quarkus.http.insecure-requests=disabled

可以结合周期性重新加载来在证书更改时自动重新加载证书。

Using cert-manager

在 Kubernetes 中运行时,可以使用 cert-manager 自动生成和更新证书。cert-manager 将生成带有密钥库和信托库的秘钥。因此,配置 TLS 注册表与使用 Kubernetes 秘钥时相同。生成的秘钥使用以下文件:

  • tls.crt for the certificate

  • tls.key,用于私钥

  • ca.crt,用于 CA 证书(如果需要)

要处理更新,可以使用周期性重新加载机制:

# ...
# TLS Registry configuration
%prod.quarkus.tls.http.key-store.pem.0.cert=/certs/tls.crt
%prod.quarkus.tls.http.key-store.pem.0.key=/certs/tls.key
%prod.quarkus.tls.http.reload-period=24h

# HTTP server configuration:
%prod.quarkus.http.tls-configuration-name=http
%prod.quarkus.http.insecure-requests=disabled

Utilizing OpenShift serving certificates

在 OpenShift 中运行应用程序时,可以利用 OpenShift serving certificates 自动生成和更新 TLS 证书。Quarkus TLS 注册表可以使用这些证书和证书颁发机构 (CA) 文件来安全地处理 HTTPS 流量并验证证书。

Acquiring a certificate

要让 OpenShift 生成证书,需要为现有 Service 对象添加注释。生成的证书将存储在秘钥中,然后可以将其挂载到 Pod 中。

考虑以下 Service 示例:

---
apiVersion: v1
kind: Service
metadata:
  annotations:
    service.beta.openshift.io/serving-cert-secret-name: my-tls-secret
  labels:
    app.kubernetes.io/name: ...
    app.kubernetes.io/version: ...
    app.kubernetes.io/managed-by: quarkus
  name: hero-service
spec:
  ports:
    - name: http
      port: 443
      protocol: TCP
      targetPort: 8443
  selector:
    app.kubernetes.io/name: ...
    app.kubernetes.io/version: ...
  type: ClusterIP

注释 service.beta.openshift.io/serving-cert-secret-name 指示 OpenShift 生成证书并将证书存储在名为 my-tls-secret 的秘钥中。如果服务已在运行,可以使用以下命令添加此注释:

oc annotate service hero-service \
     service.beta.openshift.io/serving-cert-secret-name=my-tls-secret

接下来,更新 Deployment 配置以包括卷并将秘钥挂载,从而在 Pod 中挂载秘钥:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/name: ...
    app.kubernetes.io/version: ...
  name: my-service
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: ...
      app.kubernetes.io/version: ...
  template:
    metadata:
      labels:
        app.kubernetes.io/name: ...
        app.kubernetes.io/version: ...
    spec:
      volumes:
        - name: my-tls-secret  (1)
          secret:
            secretName: my-tls-secret
      containers:
        - env:
            - name: KUBERNETES_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
            - name: QUARKUS_TLS_KEY_STORE_PEM_ACME_CERT (2)
              value: /etc/tls/tls.crt
            - name: QUARKUS_TLS_KEY_STORE_PEM_ACME_KEY
              value: /etc/tls/tls.key
          image: ...
          imagePullPolicy: Always
          name: my-service
          volumeMounts:  (3)
            - name: my-tls-secret
              mountPath: /etc/tls
              readOnly: true
          ports:
            - containerPort: 8443  (4)
              name: https
              protocol: TCP
1 定义一个用于挂载秘钥的卷。使用与上述声明秘钥相同的名称。
2 使用通往证书和私钥的路径设置密钥库。可以使用环境变量或配置文件进行此配置。此处,我们使用环境变量。OpenShift 提供的证书始终创建 tls.crttls.key 文件。
3 将秘钥挂载到容器中。确保路径与配置中使用的路径(此处为 /etc/tls)相匹配。
4 配置用于提供 HTTPS 的端口。

通过设置 quarkus.tls.key-store.pem.acme.certquarkus.tls.key-store.pem.acme.key 变量(或其如上所示的环境变量变体),TLS 注册表将使用密钥中的证书和私钥。这配置了 Quarkus HTTP 服务器的默认密钥存储,从而允许其使用该证书。有关在命名配置中使用此证书的信息,请参阅 Referencing a TLS configuration

部署您的应用程序,它将利用 OpenShift 生成的证书,使该服务可以通过 HTTPS 使用。

Trusting the Certificate Authority (CA)

现在您的服务使用了 OpenShift 发布的证书,您可能需要配置您的客户端应用程序以信任此证书。要完成此操作,创建一个 ConfigMap 包含 CA 证书并将其安装在应用程序的 pod 中。

在本示例中,我们将使用 Quarkus REST 客户端,但相同原理适用于任何客户端。

首先,为 CA 证书创建一个 ConfigMap。首先定义一个 empty ConfigMap,该 ConfigMap 将使用 CA 证书填充:

apiVersion: v1
kind: ConfigMap
metadata:
  name: client-tls-config
  annotations:
    service.beta.openshift.io/inject-cabundle: "true"

service.beta.openshift.io/inject-cabundle 注释用于将 CA 证书注入到 ConfigMap 中。注意,ConfigMap 最初没有数据——它是空的。在处理期间,OpenShift 将 CA 证书注入到 service-ca.crt 文件中的 ConfigMap 中。

接下来,通过添加一个卷并将其安装到您的 Deployment 配置中来挂载 ConfigMap:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-service-client
  labels:
    app.kubernetes.io/name: ...
    app.kubernetes.io/version: ...
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: ...
      app.kubernetes.io/version: ...
  template:
    metadata:
      labels:
        app.kubernetes.io/name: ...
        app.kubernetes.io/version: ...
    spec:
      containers:
        - name: my-service-client
          image: ...
          ports:
            - name: http
              containerPort: 8080
              protocol: TCP
          volumeMounts: (1)
            - name: my-client-volume
              mountPath: /deployments/tls
      volumes: (2)
        - name: my-client-volume
          configMap:
            name: client-tls-config
1 将 ConfigMap 安装到容器中。确保路径与配置中使用的路径匹配(此处为 /deployments/tls)。
2 定义一个卷以安装 ConfigMap 并引用接收 CA 证书的 ConfigMap。

最后,配置 REST 客户端以使用此 CA 证书。考虑以下 REST 客户端界面:

package org.acme;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

@RegisterRestClient(baseUri = "https://hero-service.cescoffi-dev.svc", configKey = "hero") (1)
public interface HeroClient {

    record Hero (Long id, String name, String otherName, int level, String picture, String powers) {
    }

    @GET
    @Path("/api/heroes/random")
    Hero getRandomHero();

}
1 配置基本 URI 和配置密钥。该名称必须采用 &lt;service-name&gt;.&lt;namespace&gt;.svc 格式,否则证书不会被信任。还要确保配置 configKey

接下来,配置 REST 客户端以信任 CA 证书:

quarkus.rest-client.hero.tls-configuration-name=my-service-tls (1)
quarkus.tls.my-service-tls.trust-store.pem.certs=/deployments/tls/service-ca.crt (2)
1 使用名为 my-service-tls 的 TLS 配置配置 hero REST 客户端。
2 设置 my-service-tls TLS 配置,特别是带有 CA 证书的可信存储。确保路径与 Kubernetes Deployment 配置中使用的路径匹配。该文件始终名为 service-ca.crt

现在,REST 客户端已配置为信任 OpenShift 生成的证书。

Certificate renewal

OpenShift 会自动更新它生成的证书。当证书更新时,密钥将使用新证书和私钥更新。

为了确保您的应用程序使用新证书,您可以利用 Quarkus TLS 注册表的定期重新加载功能。通过设置 reload-period 属性,TLS 注册表将定期检查密钥存储和信任存储是否发生更改,并在需要时重新加载它们:

quarkus.tls.reload-period=24h

您还可以实现一种自定义机制,在密钥更新时重新加载证书。有关详细信息,请参阅 Reloading certificates

Quarkus CLI commands and development CA (Certificate Authority)

TLS 注册表提供 CLI 命令来生成开发 CA 和受信任的证书。这避免了在本地使用自签名证书。

> quarkus tls
Install and Manage TLS development certificates
Usage: tls [COMMAND]
Commands:
  generate-quarkus-ca   Generate Quarkus Dev CA certificate and private key.
  generate-certificate  Generate a TLS certificate with the Quarkus Dev CA if
                          available.

在大多数情况下,你生成 Quarkus 开发 CA 一次,然后生成这个 CA 签署的证书。Quarkus 开发 CA 是一款可用于本地签署证书的证书颁发机构。它仅对开发用途有效,仅在本地机器上受信任。生成的 CA 位于 $HOME/.quarkus/quarkus-dev-root-ca.pem,并安装在系统受信存储区中。

CA, signed vs. self-signed certificates

使用 TLS 进行开发时,可以使用两种类型的证书:

  • 自签名证书:证书由使用它的同一实体签署。默认情况下不受信任。通常,它在我们没有 CA 或不想深入研究 TLS 时使用。这不是生产设置,仅可用于开发。

  • 签名证书:证书由证书颁发机构 (CA) 签署。CA 是签署证书的受信任实体。证书默认情况下受信任。这是我们在生产环境中使用的方法。

当在本地运行应用程序时,我们可以使用自签名证书,但并不总是方便。通常,浏览器不会信任证书,你必须手动导入它。curlwget、`httpie`等工具也不会信任证书。

为避免这种情况,我们可以使用开发 CA 来签署证书,并将其安装到系统受信存储区中。这样,由该 CA 签署的每个证书都将受到系统的信任。

Quarkus 可以轻松生成开发 CA 和由该 CA 签署的证书。

Generate a development CA

开发 CA 是一款可用于本地签署证书的证书颁发机构。请注意,生成的 CA 仅对开发用途有效,并且仅在本地机器上受信任。

要生成开发 CA,请使用以下命令:

quarkus tls generate-ca-certificate --install --renew --truststore

--install`将 CA 安装到系统受信存储区中。支持 Windows、Mac 和 Linux (Fedora 和 Ubuntu)。但是,根据你的浏览器,你可能需要手动导入生成的 CA。有关更多信息,请参阅浏览器文档。生成的 CA 位于 `$HOME/.quarkus/quarkus-dev-root-ca.pem

安装证书时,系统可能会要求你提供密码才能将证书安装到系统受信存储区,或者在对话框中要求你确认(在 Windows 上)。

在 Windows 上,请务必从提升的终端(以管理员身份运行)运行命令将 CA 安装到系统受信存储区中。

--renew`如果 CA 已存在,则会更新 CA。当使用此选项时,你需要重新生成由该 CA 签署的证书,因为私钥已更改。请注意,如果 CA 过期,它将自动续订(不传递 `--renew)。

`--truststore`还会生成一个包含 CA 证书的 PKCS12 信任存储。

Generate a trusted (signed) certificate

安装 Quarkus 开发 CA 后,你可以生成受信任的证书。它将由 Quarkus 开发 CA 签署,因此受到你的系统信任。

quarkus tls generate-certificate --name my-cert

这会生成一个由 Quarkus 开发 CA 签署的证书,因此如果正确安装/导入,它将受到系统的信任。

该证书存储在 `./.certs/`中。会生成两个文件:

  • $NAME-keystore.p12- 包含私钥和证书。它受密码保护。

  • $NAME-truststore.p12- 包含 CA 证书,可用作信任存储(例如,用于测试)。

提供了更多选项:

Usage: tls generate-certificate [-hrV] [-c=<cn>] [-d=<directory>]
       -n=<name> [-p=<password>]
Generate a TLS certificate with the Quarkus Dev CA if available.
  -c, --cn=<cn>       The common name of the certificate. Default is 'localhost'
  -d, --directory=<directory>
                      The directory in which the certificates will be created.
                        Default is `.certs`
  -n, --name=<name>   Name of the certificate. It will be used as file name and
                        alias in the keystore
  -p, --password=<password>
                      The password of the keystore. Default is 'password'
  -r, --renew         Whether existing certificates will need to be replaced

生成证书时,还会生成一个 .env 文件,使 Quarkus 开发模式能够识别这些证书。因此,如果您在开发模式下运行应用程序,它将使用以下证书:

./mvnw quarkus:dev
...
INFO  [io.quarkus] (Quarkus Main Thread) demo 1.0.0-SNAPSHOT on JVM (powered by Quarkus 999-SNAPSHOT) started in 1.286s. Listening on: http://localhost:8080 and https://localhost:8443

现在,您可以使用 HTTPS 打开开发界面: https://localhost:8443/q/dev,或使用 curl 发出请求:

curl https://localhost:8443/hello
Hello from Quarkus REST%

如果未安装 Quarkus Development CA,则会生成一个自签名证书。

Generating a self-signed certificate

即使安装了 Quarkus Development CA,您也可以生成一个自签名证书:

quarkus tls generate-certificate --name my-cert --self-signed

此操作会生成一个由 Quarkus Development CA 签署的自签名证书。

Uninstalling the Quarkus Development CA

从您的系统中卸载 Quarkus Development CA 取决于您的操作系统。

Deleting the CA certificate on Windows

要在 Windows 中删除 CA 证书,请使用具有管理员权限的 Powershell 终端执行以下命令:

# First, we need to identify the serial number of the CA certificate
> certutil -store -user Root
root "Trusted Root Certification Authorities"
================ Certificate 0 ================
Serial Number: 019036d564c8
Issuer: O=Quarkus, CN=quarkus-dev-root-ca # <-That's the CA, copy the Serial Number (the line above)
NotBefore: 6/19/2024 11:07 AM
NotAfter: 6/20/2025 11:07 AM
Subject: C=Cloud, S=world, L=home, OU=Quarkus Dev, O=Quarkus Dev, CN=quarkus-dev-root-ca
Signature matches Public Key
Non-root Certificate uses same Public Key as Issuer
Cert Hash(sha1): 3679bc95b613a2112a3d3256fe8321b6eccce720
No key provider information
Cannot find the certificate and private key for decryption.
CertUtil: -store command completed successfully.

> certutil -delstore -user -v Root $Serial_Number

使用 CA 证书的序列号替换 $Serial_Number

Deleting the CA certificate on Linux

在 Fedora 中,您可以使用以下命令:

sudo rm /etc/pki/ca-trust/source/anchors/quarkus-dev-root-ca.pem
sudo update-ca-trust

在 Ubuntu 中,您可以使用以下命令:

sudo rm /usr/local/share/ca-certificates/quarkus-dev-root-ca.pem
sudo update-ca-certificates

Deleting the CA certificate on Mac

在 Mac 中,您可以使用以下命令:

sudo security -v remove-trusted-cert -d /Users/clement/.quarkus/quarkus-dev-root-ca.pem

Automatic certificate management with Let’s Encrypt

Let’s Encrypt 是由 Internet Security Research Group 提供的免费自动证书颁发机构。

Let’s Encrypt 使用 Automated certificate management environment (ACME) protocol 来支持自动证书签发和续订。请阅读 Let’s Encrypt documentation 以了解有关 Let’s Encrypt 和 ACME 的更多信息。

TLS 注册项目提供了一个 CLI ACME 客户端来签发和续订 Let’s Encrypt 证书。您的应用程序使用 TLS 注册来解决 ACME 协议挑战。

按照以下步骤,为您的 Quarkus 应用程序做好准备,并使用新的和续订的 Let’s Encrypt 证书自动更新。

Prerequisites

确保有一个完全可解析的 DNS 域名,并且可以用来访问您的应用程序。将该域名用于创建 Let’s Encrypt 帐户,并支持 Let’s Encrypt ACME 挑战以证明您拥有此域名。您可以使用 Ngrok 开始尝试 Quarkus Let’s Encrypt ACME 功能,有关更多信息,请参见下面的 Use NGrok for testing 部分。

您的 Quarkus HTTPS 应用程序必须使用 build-time 属性来启用 Let’s Encrypt ACME 挑战路由:

quarkus.tls.lets-encrypt.enabled=true

TLS 注册可以通过主 HTTP 接口或管理接口管理挑战过程。*strongly*建议使用管理接口,以便让 Quarkus 将 ACME 挑战配置与主应用程序的部署和安全要求分开处理:

quarkus.tls.lets-encrypt.enabled=true
quarkus.management.enabled=true

挑战本身由主 HTTP 界面提供(可通过你的 DNS 域名访问)。

不要在此处启动你的应用程序。

Application preparation

在你请求 Let’s Encrypt 证书之前,你必须运行 TLS 注册表 Let’s Encrypt CLI prepare 命令,来为你的应用程序做准备:

quarkus tls lets-encrypt prepare --domain=<domain-dns-name>

确保在你的应用程序根目录中运行准备命令。

prepare 命令执行以下操作:

  • 在你的应用程序的根目录中创建一个 .letsencrypt 文件夹

  • 针对在先前 Prerequisites 步骤中配置的你的应用程序创建一个自签名域证书和私钥,以便启动并接受 HTTPS 请求。

  • 在你的应用程序根目录创建一个 .env 配置文件, 将应用程序配置为使用自签名域证书和私钥(直至我们获取 Let’s Encrypt 证书)。

下文展示了生成的 .env 文件示例:

quarkus.tls.key-store.pem.acme.cert=.letsencrypt/lets-encrypt.crt
quarkus.tls.key-store.pem.acme.key=.letsencrypt/lets-encrypt.key

.env 文件不包含 quarkus.tls.lets-encrypt.enabledquarkus.management.enabled 属性,因为它们是生成时属性,需要重新生成应用程序。

Start your application

你可以启动你的应用程序:

java -jar quarkus-run.jar

使用 https://your-domain-name:8443/ 访问你的应用程序端点,例如,https://your-domain-name:8443/hello,在浏览器中接收自签名证书。

接下来,保持应用程序运行,并请求你的第一个 Let’s Encrypt 证书。

Issue certificate

从应用程序目录,运行 issue-certificate 命令来获取你的第一个 Let’s Encrypt 证书:

quarkus tls lets-encrypt issue-certificate \
  --domain=<domain-dns-name> \ 1
  --email=<your contact email> \ 2
  --management-url=https://localhost:9000 3
1 Set your domain name.
2 提供你的联系电子邮件地址,以便在你的 Let’s Encrypt 帐户出现任何问题时,Let’s Encrypt 可以与你联系。
3 设置你的应用程序管理 URL,可用于处理 ACME 挑战。如果在 Prerequisites 步骤中选择不启用管理路由器,则使用 https://localhost:8443/

在此命令期间,TLS 注册表 CLI 检查应用程序是否已准备就绪,可提供挑战、创建和记录 Let’s Encrypt 帐户信息、发布 Let’s Encrypt 证书请求,并与 Quarkus 应用程序交互,以解决 ACME 挑战。

在成功获取 Let’s Encrypt 证书链和私钥之后,它们会被转换为 PEM 格式并复制到你的应用程序的 .letsencrypt 文件夹。TLS 注册表将被告知已有新的证书和私钥准备就绪,并将自动重新加载它们。

现在,再次使用 https://your-domain-name:8443/ 访问你的应用程序的端点。在浏览器中确认你的域证书现已由 Let’s Encrypt 证书颁发机构签名。

请注意,目前 Let’s Encrypt 帐户是通过 `issue-certificate`命令隐式创建的,以便用户轻松开始使用 ACME 协议。对 Let’s Encrypt 帐户管理的支持将会进一步发展。

Renew certificate

更新证书与签发第一张证书类似,但需要在 Issue certificate步骤中创建一个现有帐户。

运行以下命令以更新 Let’s Encrypt 证书:

quarkus tls lets-encrypt renew-certificate \
  --domain=<domain-dns-name> 1
1 Set your domain name.

在该命令期间,TLS 注册表 CLI 会读取在 Issue certificate步骤中录制的 Let’s Encrypt 帐户信息、签发 Let’s Encrypt 证书请求,并与 Quarkus 应用程序通信以便解决 ACME 质询。

一旦 Let’s Encrypt 证书链和私钥更新成功,它们将被转换为 PEM 格式并复制到应用程序的 `.letsencrypt`文件夹。TLS 注册表将获悉已准备好新证书和私钥,它会自动重新加载它们。

Use NGrok for testing

Ngrok可用于向运行在 localhost 上的应用程序提供安全的 HTTPS 通道,并让 HTTPS 根据应用程序轻松进行测试。

使用 Ngrok 提供了最简单的选项来开始使用 Quarkus Let’s Encrypt ACME 功能。

使用 Ngrok 的第一件事是要求它预留一个域。您可以在开发模式中使用 Quarkiverse NGrok,或直接在 Ngrok 仪表盘中进行预留。

遗憾的是,您无法立即使用 Ngrok 域来测试 Quarkus Let’s Encrypt ACME 功能。这是因为 Ngrok 本身正在使用 Let’s Encrypt,并且会拦截由 Quarkus 应用程序处理的 ACME 质询。

因此,您需要从 Ngrok 域中删除 Ngrok Let’s Encrypt 证书政策:

ngrok api --api-key <YOUR-API-KEY> reserved-domains delete-certificate-management-policy <YOUR-RESERVED-DOMAIN-ID>

`YOUR-RESERVED-DOMAIN-ID`是您的预留域的 ID,它从 `rd_`开始,您可以在 NGrok dashboard domains section中找到它。

现在,Ngrok 将仅通过 HTTP 转发 ACME 质询,因此您需要像这样启动 Ngrok:

ngrok http --domain <YOUR-NGROK-DOMAIN> 8080 --scheme http

其中 `8080`是应用程序正在监听的 localhost HTTP 端口。

您现在可以从本地计算机测试 Quarkus Let’s Encrypt ACME 功能。