diff --git a/docs/src/main/asciidoc/tls-registry-reference.adoc b/docs/src/main/asciidoc/tls-registry-reference.adoc index 2d69218b8dfa8..43bc056fd041a 100644 --- a/docs/src/main/asciidoc/tls-registry-reference.adoc +++ b/docs/src/main/asciidoc/tls-registry-reference.adoc @@ -102,6 +102,7 @@ quarkus.grpc.server.use-separate-server=false quarkus.grpc.server.plain-text=false ---- +[#referencing-a-tls-configuration] == Referencing a TLS configuration Once you have configured a _named_ configuration using `quarkus.tls.`, you need to reference it. @@ -348,7 +349,7 @@ To configure the cipher suites, use the following property: quarkus.tls.cipher-suites=TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384 ---- -==== TLS Protocol versions +==== TLS protocol versions The TLS protocol versions are the list of protocols that can be used during the TLS handshake. You can configure the ordered list of enabled TLS protocols. @@ -520,12 +521,14 @@ When the application starts, the TLS registry performs some checks to ensure the If any of these checks fail, the application will fail to start. -== Reloading Certificates +[#reloading-certificates] +== Reloading certificates The `TlsConfiguration` obtained from the `TLSConfigurationRegistry` includes a mechanism for reloading certificates. The `reload` method refreshes the key stores and trust stores, typically by reloading them from the file system. -NOTE: The reload operation is not automatic and must be triggered manually. Additionally, the `TlsConfiguration` implementation must support reloading (which is the case for the configured certificate). +NOTE: The reload operation is not automatic and must be triggered manually. +Additionally, the `TlsConfiguration` implementation must support reloading (which is the case for the configured certificate). The `reload` method returns a `boolean` indicating whether the reload was successful. A value of `true` means the reload operation was successful, not necessarily that there were updates to the certificates. @@ -693,6 +696,227 @@ To handle the renewal, you can use the periodic reloading mechanism: %prod.quarkus.http.insecure-requests=disabled ---- +== Utilizing OpenShift serving certificates + +When running your application in OpenShift, you can leverage the https://docs.openshift.com/container-platform/4.16/security/certificates/service-serving-certificate.html[OpenShift serving certificates] to automatically generate and renew TLS certificates. +The Quarkus TLS registry can use these certificates and Certificate Authority (CA) files to handle HTTPS traffic securely and to validate certificates. + +=== Acquiring a certificate + +To have OpenShift generate a certificate, you need to annotate an existing _Service_ object. +The generated certificate will be stored in a secret, which you can then mount in your pod. + +Consider the following _Service_ example: + +[source, yaml] +---- +--- +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 +---- + +The annotation `service.beta.openshift.io/serving-cert-secret-name` instructs OpenShift to generate a certificate and store it in a secret named `my-tls-secret`. If your service is already running, you can add this annotation with the following command: + +[source, shell] +---- +oc annotate service hero-service \ + service.beta.openshift.io/serving-cert-secret-name=my-tls-secret +---- + +Next, mount the secret in your pod by updating your _Deployment_ configuration to include a volume and mount the secret: + +[source, yaml] +---- +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> Define a volume to mount the secret. Use the same name as the secret declared above. +<2> Set up the key store with the paths to the certificate and private key. This can be configured using environment variables or configuration files. Here, we use environment variables. OpenShift serving certificates always create the `tls.crt` and `tls.key` files. +<3> Mount the secret in the container. Ensure the path matches the one used in the configuration (here `/etc/tls`). +<4> Configure the port to serve HTTPS. + +By setting the `quarkus.tls.key-store.pem.acme.cert` and `quarkus.tls.key-store.pem.acme.key` variables (or their environment variable variant as done above), the TLS registry will use the certificate and private key from the secret. This configures the default key store for the Quarkus HTTP server, allowing it to use the certificate. +For using this certificate in a named configuration, refer to <>. + +Deploy your application, and it will utilize the certificate generated by OpenShift, making the service available over HTTPS. + +=== Trusting the Certificate Authority (CA) + +Now that your service uses a certificate issued by OpenShift, you might need to configure your client applications to trust this certificate. +To accomplish this, create a _ConfigMap_ that holds the CA certificate and mount it in the application's pod. + +In this example, we'll use a Quarkus REST client, but the same principle applies to any client. + +First, create a _ConfigMap_ for the CA certificate. +Start by defining an _empty_ ConfigMap, which will be populated with the CA certificate: + +[source, yaml] +---- +apiVersion: v1 +kind: ConfigMap +metadata: + name: client-tls-config + annotations: + service.beta.openshift.io/inject-cabundle: "true" +---- + +The `service.beta.openshift.io/inject-cabundle` annotation is used to inject the CA certificate into the ConfigMap. +Note that the ConfigMap initially has no data — it is empty. +During its processing, OpenShift injects the CA certificate into the ConfigMap in the `service-ca.crt` file. + +Next, mount the ConfigMap by adding a volume and mount it in your _Deployment_ configuration: + +[source, yaml] +---- +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> Mount the ConfigMap in the container. Ensure the path matches the one used in the configuration (here `/deployments/tls`). +<2> Define a volume to mount the ConfigMap and reference the ConfigMap that receives the CA certificate. + +Finally, configure the REST client to use this CA certificate. Consider the following REST client interface: + +[source, java] +---- +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> Configure the base URI and the configuration key. The name must be in the format `..svc`, otherwise the certificate will not be trusted. Ensure to also configure the `configKey`. + +Next, configure the REST client to trust the CA certificate: + +[source, properties] +---- +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> Configure the `hero` REST client with the TLS configuration named `my-service-tls`. +<2> Set up the `my-service-tls` TLS configuration, specifically the trust store with the CA certificate. Ensure the path matches the one used in the Kubernetes _Deployment_ configuration. The file is always named `service-ca.crt`. + +Now, the REST client is configured to trust the certificate generated by OpenShift. + +=== Certificate renewal + +OpenShift automatically renews the certificates it generates. +When the certificate is renewed, the secret is updated with the new certificate and private key. + +To ensure your application uses the new certificate, you can leverage the Quarkus TLS registry's periodic reloading feature. +By setting the `reload-period` property, the TLS registry will periodically check the key stores and trust stores for changes and reload them if needed: + +[source, properties] +---- +quarkus.tls.reload-period=24h +---- + +You can also implement a custom mechanism to reload the certificates when the secret is updated. +See <> for more information. + == Quarkus CLI commands and development CA (Certificate Authority) The TLS registry provides CLI commands to generate a development CA and trusted certificates.