diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 6b77ab0497e75..6b3c0bb5ac2a4 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 737abec09f9b8..c0299e314e8a8 100644 --- a/pom.xml +++ b/pom.xml @@ -86,6 +86,9 @@ ${protoc.version} 2.41.0 + + 0.8.1 + 7.8.0