Skip to content

Commit

Permalink
Add TLS Command Implementation
Browse files Browse the repository at this point in the history
This commit introduces two new CLI commands to enhance TLS management:

- Generate and install a Quarkus Development CA.
- Create certificates, either signed with the generated CA or unsigned.

As the generated certificates are generated in ``$project-directory/.certs`, this directory is added to the generated .gitignore.

The CLI uses the new alias supported added in #40580, and thus the commands are behind: `quarkus tls`
  • Loading branch information
cescoffier committed Jul 5, 2024
1 parent 7720a88 commit da8d7a9
Show file tree
Hide file tree
Showing 13 changed files with 632 additions and 2 deletions.
7 changes: 7 additions & 0 deletions bom/application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,12 @@
<version>${brotli4j.version}</version>
</dependency>

<dependency>
<groupId>io.smallrye.certs</groupId>
<artifactId>smallrye-certificate-generator</artifactId>
<version>${smallrye-certificate-generator.version}</version>
</dependency>

<!-- Jackson dependencies, imported as a BOM -->
<dependency>
<groupId>com.fasterxml.jackson</groupId>
Expand Down Expand Up @@ -6269,6 +6275,7 @@
<version>${picocli.version}</version>
</dependency>


<!-- Micrometer -->
<dependency>
<groupId>org.hdrhistogram</groupId>
Expand Down
2 changes: 0 additions & 2 deletions build-parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,6 @@
<!-- Jakarta JMS API -->
<jakarta.jms-api.version>3.1.0</jakarta.jms-api.version>

<smallrye-certificate-generator.version>0.8.1</smallrye-certificate-generator.version>

<!-- Quarkus Analytics -->
<properties-maven-plugin.version>1.1.0</properties-maven-plugin.version>
<quarkus.analytics.disabled>true</quarkus.analytics.disabled>
Expand Down
190 changes: 190 additions & 0 deletions docs/src/main/asciidoc/tls-registry-reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -693,3 +693,193 @@ To handle the renewal, you can use the periodic reloading mechanism:
%prod.quarkus.http.insecure-requests=disabled
----

== Quarkus CLI commands and development CA (Certificate Authority)

The TLS registry provides CLI commands to generate a development CA and trusted certificates.
This avoids having to use self-signed certificates locally.

[source, shell]
----
> 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.
----

In most cases, you generate the Quarkus Development CA once, and then generate certificates signed by this CA.
The Quarkus Development CA is a Certificate Authority that can be used to sign certificates locally.
It is only valid for development purposes and only trusted on the local machine.
The generated CA is located in `$HOME/.quarkus/quarkus-dev-root-ca.pem`, and installed in the system trust store.

Check warning on line 715 in docs/src/main/asciidoc/tls-registry-reference.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.TermsWarnings] Consider using 'truststore' rather than 'trust store' unless updating existing content that uses the term. Raw Output: {"message": "[Quarkus.TermsWarnings] Consider using 'truststore' rather than 'trust store' unless updating existing content that uses the term.", "location": {"path": "docs/src/main/asciidoc/tls-registry-reference.adoc", "range": {"start": {"line": 715, "column": 102}}}, "severity": "WARNING"}

=== CA, signed vs. self-signed certificates

Check warning on line 717 in docs/src/main/asciidoc/tls-registry-reference.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.HeadingPunctuation] Do not use end punctuation in headings. Raw Output: {"message": "[Quarkus.HeadingPunctuation] Do not use end punctuation in headings.", "location": {"path": "docs/src/main/asciidoc/tls-registry-reference.adoc", "range": {"start": {"line": 717, "column": 1}}}, "severity": "INFO"}

Check warning on line 717 in docs/src/main/asciidoc/tls-registry-reference.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.TermsWarnings] Consider using 'compared to' rather than 'vs' unless updating existing content that uses the term. Raw Output: {"message": "[Quarkus.TermsWarnings] Consider using 'compared to' rather than 'vs' unless updating existing content that uses the term.", "location": {"path": "docs/src/main/asciidoc/tls-registry-reference.adoc", "range": {"start": {"line": 717, "column": 16}}}, "severity": "WARNING"}

Check warning on line 717 in docs/src/main/asciidoc/tls-registry-reference.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.HeadingPunctuation] Do not use end punctuation in headings. Raw Output: {"message": "[Quarkus.HeadingPunctuation] Do not use end punctuation in headings.", "location": {"path": "docs/src/main/asciidoc/tls-registry-reference.adoc", "range": {"start": {"line": 717, "column": 17}}}, "severity": "INFO"}

When developing with TLS, you can use two types of certificates:

- a self-signed certificate: the certificate is signed by the same entity that uses it. It is not trusted by default. It's generally what we use when we don't have a CA, or don't want to dig too much into TLS. This is not a production setup, and may be used only for development.

Check warning on line 721 in docs/src/main/asciidoc/tls-registry-reference.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.TermsWarnings] Consider using 'might (for possiblity)' or 'can (for ability)' rather than 'may' unless updating existing content that uses the term. Raw Output: {"message": "[Quarkus.TermsWarnings] Consider using 'might (for possiblity)' or 'can (for ability)' rather than 'may' unless updating existing content that uses the term.", "location": {"path": "docs/src/main/asciidoc/tls-registry-reference.adoc", "range": {"start": {"line": 721, "column": 248}}}, "severity": "WARNING"}
- a signed certificate: the certificate is signed by a Certificate Authority (CA). The CA is a trusted entity that signs the certificate. The certificate is trusted by default. This is what we use in production.

We could use self-signed certificate when running application locally, but it's not always convenient.
Typically, browsers will not trust the certificate, and you will have to import it manually.
`curl`, `wget`, `httpie` and other tools will also not trust the certificate.

To avoid this, we can use a development CA to sign the certificates, and install it into the system trust store.

Check warning on line 728 in docs/src/main/asciidoc/tls-registry-reference.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.TermsWarnings] Consider using 'truststore' rather than 'trust store' unless updating existing content that uses the term. Raw Output: {"message": "[Quarkus.TermsWarnings] Consider using 'truststore' rather than 'trust store' unless updating existing content that uses the term.", "location": {"path": "docs/src/main/asciidoc/tls-registry-reference.adoc", "range": {"start": {"line": 728, "column": 101}}}, "severity": "WARNING"}
Thus, every certificate signed by this CA will be trusted by the system.

Check warning on line 729 in docs/src/main/asciidoc/tls-registry-reference.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.TermsWarnings] Consider using 'therefore' rather than 'Thus' unless updating existing content that uses the term. Raw Output: {"message": "[Quarkus.TermsWarnings] Consider using 'therefore' rather than 'Thus' unless updating existing content that uses the term.", "location": {"path": "docs/src/main/asciidoc/tls-registry-reference.adoc", "range": {"start": {"line": 729, "column": 1}}}, "severity": "WARNING"}

Quarkus makes it easy to generate a development CA and certificates signed by this CA.

=== Generate a development CA

The development CA is a Certificate Authority that can be used to sign certificates locally.
Note that the generated CA is only valid for development purposes, and only trusted on the local machine.

To generate a development CA, use the following command:

[source, shell]
----
quarkus tls generate-ca-certificate --install --renew --truststore
----

`--install` installs the CA in the system trust store.

Check warning on line 745 in docs/src/main/asciidoc/tls-registry-reference.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.TermsWarnings] Consider using 'truststore' rather than 'trust store' unless updating existing content that uses the term. Raw Output: {"message": "[Quarkus.TermsWarnings] Consider using 'truststore' rather than 'trust store' unless updating existing content that uses the term.", "location": {"path": "docs/src/main/asciidoc/tls-registry-reference.adoc", "range": {"start": {"line": 745, "column": 43}}}, "severity": "WARNING"}
Windows, Mac and Linux (Fedora and Ubuntu) are supported.
However, depending on your browser, you may need to import the generated CA manually.

Check warning on line 747 in docs/src/main/asciidoc/tls-registry-reference.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.TermsWarnings] Consider using 'might (for possiblity)' or 'can (for ability)' rather than 'may' unless updating existing content that uses the term. Raw Output: {"message": "[Quarkus.TermsWarnings] Consider using 'might (for possiblity)' or 'can (for ability)' rather than 'may' unless updating existing content that uses the term.", "location": {"path": "docs/src/main/asciidoc/tls-registry-reference.adoc", "range": {"start": {"line": 747, "column": 41}}}, "severity": "WARNING"}

Check warning on line 747 in docs/src/main/asciidoc/tls-registry-reference.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.Fluff] Depending on the context, consider using 'Rewrite the sentence, or use 'must', instead of' rather than 'need to'. Raw Output: {"message": "[Quarkus.Fluff] Depending on the context, consider using 'Rewrite the sentence, or use 'must', instead of' rather than 'need to'.", "location": {"path": "docs/src/main/asciidoc/tls-registry-reference.adoc", "range": {"start": {"line": 747, "column": 45}}}, "severity": "INFO"}
Refer to the browser documentation for more information.
The generated CA is located in `$HOME/.quarkus/quarkus-dev-root-ca.pem`.

WARNING: When installing the certificate, your system may ask for your password to install the certificate in the system trust store, or ask for confirmation in a dialog (on Windows).

IMPORTANT: On Windows, makes sure you run from an elevated terminal (run as administrator) to install the CA in the system trust store.

`--renew` renews the CA if it already exists.
When this option is used, you need to re-generate the certificates that were signed by the CA, as the private key is changed.
Note that if the CA expires, it will automatically be renewed (without passing `--renew`).

`--truststore` also generates a PKCS12 trust store containing the CA certificate.

=== Generate a trusted (signed) certificate

Once you have installed the Quarkus Development CA, you can generate a trusted certificate.
It will be signed by the Quarkus Development CA, and so trusted by your system.

[source, shell]
----
quarkus tls generate-certificate --name my-cert
----

This generates a certificate signed by the Quarkus Development CA, and so if properly installed / imported, will be trusted by your system.

The certificate is stored in `./.certs/`.
Two files are generated:

- `$NAME-keystore.p12` - contains the private key and the certificate. It's password protected.
- `$NAME-truststore.p12` - contains the CA certificate, that you can used as trust store (for test, for instance).

More options are available:

[source, shell]
----
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
----

When generating the certificate, a `.env` file is also generated making the Quarkus dev mode aware of these certificates.
So, then, if you run your application in dev mode, it will use these certificates:

[source, shell]
----
./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
----

Now, you can open the Dev UI using HTTPS: `https://localhost:8443/q/dev`, or issue a request using `curl`:

[source, shell]
----
curl https://localhost:8443/hello
Hello from Quarkus REST%
----

IMPORTANT: If the Quarkus Development CA is not installed, a self-signed certificate is generated.


=== Generating a self-signed certificate

Even if the Quarkus Development CA is installed, you can generate a self-signed certificate:

[source, shell]
----
quarkus tls generate-certificate --name my-cert --self-signed
----

This generates a self-signed certificate, not signed by the Quarkus Development CA.

=== Uninstalling the Quarkus Development CA

Uninstalling the Quarkus Development CA from your system depends on your OS.

==== Deleting the CA certificate on Windows

To delete the CA certificate on Windows, use the following commands from a Powershell terminal with administrator rights:

[source, shell]
----
# 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
----

Replace `$Serial_Number` with the serial number of the CA certificate.

==== Deleting the CA certificate on Linux

On Fedora, you can use the following command:

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

On Ubuntu, you can use the following command:

[source, shell]
----
sudo rm /usr/local/share/ca-certificates/quarkus-dev-root-ca.pem
sudo update-ca-certificates
----

==== Deleting the CA certificate on Mac

On Mac, you can use the following command:

[source, shell]
----
sudo security -v remove-trusted-cert -d /Users/clement/.quarkus/quarkus-dev-root-ca.pem
----
86 changes: 86 additions & 0 deletions extensions/tls-registry/cli/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-tls-registry-parent</artifactId>
<version>999-SNAPSHOT</version>
</parent>

<artifactId>quarkus-tls-registry-cli</artifactId>
<name>Quarkus - TLS Registry - CLI</name>

<properties>
<main.class>io.quarkus.tls.cli.TlsCommand</main.class>
</properties>

<dependencies>
<dependency>
<groupId>info.picocli</groupId>
<artifactId>picocli</artifactId>
</dependency>

<dependency>
<groupId>io.smallrye.certs</groupId>
<artifactId>smallrye-certificate-generator</artifactId>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>

<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<finalName>${project.artifactId}-${project.version}</finalName>
<appendAssemblyId>false</appendAssemblyId>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>${main.class}</mainClass>
</manifest>
</archive>
</configuration>

<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>

</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.quarkus.tls.cli;

import java.io.File;

public interface Constants {

String CA_FILE_NAME = "quarkus-dev-root-ca.pem";
String PK_FILE_NAME = "quarkus-dev-root-key.pem";
String KEYSTORE_FILE_NAME = "quarkus-dev-keystore.p12";

File BASE_DIR = new File(System.getenv("HOME"), ".quarkus");

File CA_FILE = new File(BASE_DIR, CA_FILE_NAME);
File PK_FILE = new File(BASE_DIR, PK_FILE_NAME);
File KEYSTORE_FILE = new File(BASE_DIR, KEYSTORE_FILE_NAME);
}
Loading

0 comments on commit da8d7a9

Please sign in to comment.