diff --git a/bom/application/pom.xml b/bom/application/pom.xml
index b7950356af21c..6a4cbeaf71ea3 100644
--- a/bom/application/pom.xml
+++ b/bom/application/pom.xml
@@ -288,6 +288,12 @@
${brotli4j.version}
+
+ io.smallrye.certs
+ smallrye-certificate-generator
+ ${smallrye-certificate-generator.version}
+
+
com.fasterxml.jackson
@@ -6269,6 +6275,7 @@
${picocli.version}
+
org.hdrhistogram
diff --git a/build-parent/pom.xml b/build-parent/pom.xml
index d9706721a99be..f1807bfca2832 100644
--- a/build-parent/pom.xml
+++ b/build-parent/pom.xml
@@ -153,8 +153,6 @@
3.1.0
- 0.8.1
-
1.1.0
true
diff --git a/docs/src/main/asciidoc/tls-registry-reference.adoc b/docs/src/main/asciidoc/tls-registry-reference.adoc
index 94cd3a6babf99..2d69218b8dfa8 100644
--- a/docs/src/main/asciidoc/tls-registry-reference.adoc
+++ b/docs/src/main/asciidoc/tls-registry-reference.adoc
@@ -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.
+
+=== CA, signed vs. self-signed certificates
+
+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.
+- 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.
+Thus, every certificate signed by this CA will be trusted by the system.
+
+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.
+Windows, Mac and Linux (Fedora and Ubuntu) are supported.
+However, depending on your browser, you may need to import the generated CA manually.
+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=] [-d=]
+ -n= [-p=]
+Generate a TLS certificate with the Quarkus Dev CA if available.
+ -c, --cn= The common name of the certificate. Default is 'localhost'
+ -d, --directory=
+ The directory in which the certificates will be created.
+ Default is `.certs`
+ -n, --name= Name of the certificate. It will be used as file name and
+ alias in the keystore
+ -p, --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
+----
diff --git a/extensions/tls-registry/cli/pom.xml b/extensions/tls-registry/cli/pom.xml
new file mode 100644
index 0000000000000..0d4c342a3b5a3
--- /dev/null
+++ b/extensions/tls-registry/cli/pom.xml
@@ -0,0 +1,86 @@
+
+
+ 4.0.0
+
+ io.quarkus
+ quarkus-tls-registry-parent
+ 999-SNAPSHOT
+
+
+ quarkus-tls-registry-cli
+ Quarkus - TLS Registry - CLI
+
+
+ io.quarkus.tls.cli.TlsCommand
+
+
+
+
+ info.picocli
+ picocli
+
+
+
+ io.smallrye.certs
+ smallrye-certificate-generator
+
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ -parameters
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ org.jboss.logmanager.LogManager
+ ${maven.home}
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+
+ jar-with-dependencies
+
+ ${project.artifactId}-${project.version}
+ false
+
+
+ true
+ ${main.class}
+
+
+
+
+
+
+ make-assembly
+ package
+
+ single
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/extensions/tls-registry/cli/src/main/java/io/quarkus/tls/cli/Constants.java b/extensions/tls-registry/cli/src/main/java/io/quarkus/tls/cli/Constants.java
new file mode 100644
index 0000000000000..96821d8e3deaa
--- /dev/null
+++ b/extensions/tls-registry/cli/src/main/java/io/quarkus/tls/cli/Constants.java
@@ -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);
+}
diff --git a/extensions/tls-registry/cli/src/main/java/io/quarkus/tls/cli/GenerateCACommand.java b/extensions/tls-registry/cli/src/main/java/io/quarkus/tls/cli/GenerateCACommand.java
new file mode 100644
index 0000000000000..eb612b66ca029
--- /dev/null
+++ b/extensions/tls-registry/cli/src/main/java/io/quarkus/tls/cli/GenerateCACommand.java
@@ -0,0 +1,100 @@
+package io.quarkus.tls.cli;
+
+import static io.quarkus.tls.cli.Constants.CA_FILE;
+import static io.quarkus.tls.cli.Constants.KEYSTORE_FILE;
+import static io.quarkus.tls.cli.Constants.PK_FILE;
+import static java.lang.System.Logger.Level.INFO;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.concurrent.Callable;
+
+import io.smallrye.certs.ca.CaGenerator;
+import picocli.CommandLine;
+
+@CommandLine.Command(name = "generate-quarkus-ca", mixinStandardHelpOptions = true, description = "Generate Quarkus Dev CA certificate and private key.")
+public class GenerateCACommand implements Callable {
+
+ @CommandLine.Option(names = { "-i",
+ "--install" }, description = "Install the generated CA into the system keychain.", defaultValue = "false")
+ boolean install;
+
+ @CommandLine.Option(names = { "-t",
+ "--truststore" }, description = "Generate a PKCS12 (`.p12`) truststore containing the generated CA.", defaultValue = "false")
+ boolean truststore;
+
+ @CommandLine.Option(names = { "-r",
+ "--renew" }, description = "Update certificate if already created.", defaultValue = "false")
+ boolean renew;
+
+ static System.Logger LOGGER = System.getLogger("generate-quarkus-ca");
+
+ @Override
+ public Integer call() throws Exception {
+ LOGGER.log(INFO, "🔥 Generating Quarkus Dev CA certificate...");
+ if (!Constants.BASE_DIR.exists()) {
+ Constants.BASE_DIR.mkdirs();
+ }
+
+ if (CA_FILE.exists() && !renew) {
+ if (!hasExpired()) {
+ LOGGER.log(INFO,
+ "✅ Quarkus Dev CA certificate already exists and has not yet expired. Use --renew to update.");
+ return 0;
+ }
+ }
+
+ String username = System.getProperty("user.name", "");
+ CaGenerator generator = new CaGenerator(CA_FILE, PK_FILE, KEYSTORE_FILE, "quarkus");
+ generator
+ .generate("quarkus-dev-root-ca", "Quarkus Development (" + username + ")", "Quarkus Development",
+ "home", "world", "universe");
+ if (install) {
+ LOGGER.log(INFO, "🔥 Installing the CA certificate in the system truststore...");
+ generator.installToSystem();
+ }
+
+ if (truststore) {
+ LOGGER.log(INFO, "🔥 Generating p12 truststore...");
+ File ts = new File("quarkus-ca-truststore.p12");
+ generator.generateTrustStore(ts);
+ LOGGER.log(INFO, "✅ Truststore generated successfully.");
+ }
+
+ LOGGER.log(INFO, "✅ Quarkus Development CA generated and installed");
+
+ return 0;
+ }
+
+ private boolean hasExpired() throws Exception {
+ var cert = getCertificateFromPKCS12();
+ try {
+ cert.checkValidity();
+ } catch (Exception e) {
+ LOGGER.log(INFO, "🔥 Certificate has expired. Renewing...");
+ return true;
+ }
+ return false;
+ }
+
+ private static X509Certificate getCertificateFromPKCS12()
+ throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException {
+ try (FileInputStream fis = new FileInputStream(KEYSTORE_FILE)) {
+ KeyStore keystore = KeyStore.getInstance("PKCS12");
+ keystore.load(fis, "quarkus".toCharArray());
+ Certificate cert = keystore.getCertificate(CaGenerator.KEYSTORE_CERT_ENTRY);
+ if (cert == null) {
+ throw new KeyStoreException("No certificate found with alias: " + CaGenerator.KEYSTORE_CERT_ENTRY);
+ }
+ return (X509Certificate) cert;
+ }
+ }
+
+}
diff --git a/extensions/tls-registry/cli/src/main/java/io/quarkus/tls/cli/GenerateCertificateCommand.java b/extensions/tls-registry/cli/src/main/java/io/quarkus/tls/cli/GenerateCertificateCommand.java
new file mode 100644
index 0000000000000..f570fd8345939
--- /dev/null
+++ b/extensions/tls-registry/cli/src/main/java/io/quarkus/tls/cli/GenerateCertificateCommand.java
@@ -0,0 +1,167 @@
+package io.quarkus.tls.cli;
+
+import static io.quarkus.tls.cli.Constants.CA_FILE;
+import static io.quarkus.tls.cli.Constants.PK_FILE;
+import static java.lang.System.Logger.Level.ERROR;
+import static java.lang.System.Logger.Level.INFO;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.Security;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.time.Duration;
+import java.util.concurrent.Callable;
+
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.openssl.PEMParser;
+import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
+
+import io.smallrye.certs.CertificateGenerator;
+import io.smallrye.certs.CertificateRequest;
+import io.smallrye.certs.Format;
+import io.smallrye.common.os.OS;
+import picocli.CommandLine;
+
+@CommandLine.Command(name = "generate-certificate", mixinStandardHelpOptions = true, description = "Generate a TLS certificate with the Quarkus Dev CA if available.")
+public class GenerateCertificateCommand implements Callable {
+
+ @CommandLine.Option(names = { "-n",
+ "--name" }, description = "Name of the certificate. It will be used as file name and alias in the keystore", required = true)
+ String name;
+
+ @CommandLine.Option(names = { "-p",
+ "--password" }, description = "The password of the keystore. Default is 'password'", defaultValue = "password", required = false)
+ String password;
+
+ @CommandLine.Option(names = { "-c",
+ "--cn" }, description = "The common name of the certificate. Default is 'localhost'", defaultValue = "localhost", required = false)
+ String cn;
+
+ @CommandLine.Option(names = { "-d",
+ "--directory" }, description = "The directory in which the certificates will be created. Default is `.certs`", defaultValue = ".certs")
+ String directory;
+
+ @CommandLine.Option(names = { "-r",
+ "--renew" }, description = "Whether existing certificates will need to be replaced", defaultValue = "false")
+ boolean renew;
+
+ @CommandLine.Option(names = {
+ "--self-signed" }, description = "Generate a self-signed certificate", defaultValue = "false", hidden = true)
+ boolean selfSigned;
+
+ static {
+ Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
+ }
+
+ static System.Logger LOGGER = System.getLogger("generate-quarkus-ca");
+
+ @Override
+ public Integer call() throws Exception {
+ LOGGER.log(INFO, "\uD83D\uDD0E Looking for the Quarkus Dev CA certificate...");
+
+ if (!CA_FILE.exists() || !PK_FILE.exists() || selfSigned) {
+ LOGGER.log(INFO, "\uD83C\uDFB2 Quarkus Dev CA certificate not found. Generating a self-signed certificate...");
+ generateSelfSignedCertificate();
+ return 0;
+ }
+
+ LOGGER.log(INFO, "\uD83D\uDCDC Quarkus Dev CA certificate found at {0}", CA_FILE.getAbsolutePath());
+ X509Certificate caCert = loadRootCertificate(CA_FILE);
+ PrivateKey caPrivateKey = loadPrivateKey();
+
+ createSignedCertificate(caCert, caPrivateKey);
+
+ LOGGER.log(INFO, "✅ Signed Certificate generated successfully and exported into `{0}-keystore.p12`", name);
+ printConfig(new File(directory, name + "-keystore.p12").getAbsolutePath(), password);
+
+ return 0;
+ }
+
+ private void generateSelfSignedCertificate() throws Exception {
+ File out = new File(directory);
+ if (!out.exists()) {
+ out.mkdirs();
+ }
+ new CertificateGenerator(out.toPath(), renew).generate(new CertificateRequest()
+ .withName(name)
+ .withCN(cn)
+ .withPassword(password)
+ .withDuration(Duration.ofDays(365))
+ .withFormat(Format.PKCS12));
+ LOGGER.log(INFO, "✅ Self-signed certificate generated successfully and exported into `{0}-keystore.p12`", name);
+ printConfig(new File(directory, name + "-keystore.p12").getAbsolutePath(), password);
+
+ }
+
+ private void printConfig(String path, String password) {
+ if (OS.WINDOWS.isCurrent()) {
+ path = path.replace("\\", "\\\\");
+ }
+
+ // .env format
+ String env = String.format("""
+ _DEV_QUARKUS_TLS_KEY_STORE_P12_PATH=%s
+ _DEV_QUARKUS_TLS_KEY_STORE_P12_PASSWORD=%s
+ """, path, password);
+
+ var dotEnvFile = new File(".env");
+ try (var writer = new FileWriter(dotEnvFile, dotEnvFile.isFile())) {
+ writer.write(env);
+ } catch (IOException e) {
+ LOGGER.log(ERROR, "Failed to write to .env file", e);
+ }
+
+ LOGGER.log(INFO, """
+ ✅ Required configuration added to the `.env` file:
+ %dev.quarkus.tls.key-store.p12.path={0}
+ %dev.quarkus.tls.key-store.p12.password={1}
+ """, path, password);
+ }
+
+ private X509Certificate loadRootCertificate(File ca) throws Exception {
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ try (FileInputStream fis = new FileInputStream(ca)) {
+ return (X509Certificate) cf.generateCertificate(fis);
+ }
+ }
+
+ private PrivateKey loadPrivateKey() throws Exception {
+ try (BufferedReader reader = new BufferedReader(new FileReader(Constants.PK_FILE));
+ PEMParser pemParser = new PEMParser(reader)) {
+ Object obj = pemParser.readObject();
+ if (obj instanceof KeyPair) {
+ return ((KeyPair) obj).getPrivate();
+ } else if (obj instanceof PrivateKeyInfo) {
+ JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
+ return converter.getPrivateKey(((PrivateKeyInfo) obj));
+ } else {
+ throw new IllegalStateException(
+ "The file " + Constants.PK_FILE.getAbsolutePath() + " does not contain a private key "
+ + obj.getClass().getName());
+ }
+ }
+ }
+
+ private void createSignedCertificate(X509Certificate issuerCert,
+ PrivateKey issuerPrivateKey) throws Exception {
+ File out = new File(directory);
+ if (!out.exists()) {
+ out.mkdirs();
+ }
+ new CertificateGenerator(out.toPath(), renew).generate(new CertificateRequest()
+ .withName(name)
+ .withCN(cn)
+ .withPassword(password)
+ .withDuration(Duration.ofDays(365))
+ .withFormat(Format.PKCS12)
+ .signedWith(issuerCert, issuerPrivateKey));
+
+ }
+}
diff --git a/extensions/tls-registry/cli/src/main/java/io/quarkus/tls/cli/TlsCommand.java b/extensions/tls-registry/cli/src/main/java/io/quarkus/tls/cli/TlsCommand.java
new file mode 100644
index 0000000000000..e002c66b2249d
--- /dev/null
+++ b/extensions/tls-registry/cli/src/main/java/io/quarkus/tls/cli/TlsCommand.java
@@ -0,0 +1,26 @@
+package io.quarkus.tls.cli;
+
+import java.util.concurrent.Callable;
+
+import picocli.CommandLine;
+
+@CommandLine.Command(name = "tls", sortOptions = false, header = "Install and Manage TLS development certificates", subcommands = {
+ GenerateCACommand.class,
+ GenerateCertificateCommand.class,
+})
+public class TlsCommand implements Callable {
+
+ @CommandLine.Spec
+ protected CommandLine.Model.CommandSpec spec;
+
+ @Override
+ public Integer call() {
+ spec.commandLine().usage(System.out);
+ return 0;
+ }
+
+ public static void main(String[] args) {
+ int exitCode = new CommandLine(new TlsCommand()).execute(args);
+ System.exit(exitCode);
+ }
+}
diff --git a/extensions/tls-registry/cli/src/test/java/io/quarkus/tls/cli/SelfSignedGenerationTest.java b/extensions/tls-registry/cli/src/test/java/io/quarkus/tls/cli/SelfSignedGenerationTest.java
new file mode 100644
index 0000000000000..c3a5b23aef4e4
--- /dev/null
+++ b/extensions/tls-registry/cli/src/test/java/io/quarkus/tls/cli/SelfSignedGenerationTest.java
@@ -0,0 +1,32 @@
+package io.quarkus.tls.cli;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.security.KeyStore;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class SelfSignedGenerationTest {
+
+ @Test
+ public void testSelfSignedGeneration() throws Exception {
+ GenerateCertificateCommand command = new GenerateCertificateCommand();
+ command.name = "test";
+ command.renew = true;
+ command.selfSigned = true;
+ command.directory = "target";
+ command.password = "password";
+ command.call();
+
+ File file = new File("target/test-keystore.p12");
+ Assertions.assertTrue(file.exists());
+
+ KeyStore ks = KeyStore.getInstance("PKCS12");
+ try (FileInputStream fis = new FileInputStream(file)) {
+ ks.load(fis, "password".toCharArray());
+ Assertions.assertNotNull(ks.getCertificate("test"));
+ Assertions.assertNotNull(ks.getKey("test", "password".toCharArray()));
+ }
+ }
+}
diff --git a/extensions/tls-registry/pom.xml b/extensions/tls-registry/pom.xml
index 0b2e443bc9f6e..3a808afcbaea6 100644
--- a/extensions/tls-registry/pom.xml
+++ b/extensions/tls-registry/pom.xml
@@ -17,6 +17,7 @@
deployment
runtime
+ cli
diff --git a/extensions/tls-registry/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/tls-registry/runtime/src/main/resources/META-INF/quarkus-extension.yaml
index 81db75cb09125..43b04fda93333 100644
--- a/extensions/tls-registry/runtime/src/main/resources/META-INF/quarkus-extension.yaml
+++ b/extensions/tls-registry/runtime/src/main/resources/META-INF/quarkus-extension.yaml
@@ -8,3 +8,5 @@ metadata:
unlisted: true
config:
- "quarkus.tls."
+ cli-plugins:
+ - "tls: ${project.groupId}:quarkus-tls-registry-cli:${project.version}"
diff --git a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/project/quarkus/base/..gitignore b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/project/quarkus/base/..gitignore
index af4390a115714..ab558b7afeed7 100644
--- a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/project/quarkus/base/..gitignore
+++ b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/project/quarkus/base/..gitignore
@@ -33,3 +33,5 @@ nb-configuration.xml
# Plugin directory
/.quarkus/cli/plugins/
+# TLS Certificates
+.certs/
diff --git a/pom.xml b/pom.xml
index 6fe5b5015bca7..e53f88b9f4e4d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -86,6 +86,9 @@
${protoc.version}
2.41.0
+
+ 0.8.1
+
7.8.0