Open jiliapp opened 1 year ago
Doesn't look like it is possible to configure io.vertx.core.net.PemTrustOptions
in yml. It does not have setter, only available is method
public PemTrustOptions addCertPath(String certPath) throws NullPointerException {
Objects.requireNonNull(certPath, "No null certificate accepted");
Arguments.require(!certPath.isEmpty(), "No empty certificate path accepted");
certPaths.add(certPath);
return this;
}
so this needs to be done manually somehow, just not sure where would be the execution point to add cert path.
@jiliapp Potential workaround for this (since can't configure PemTrustOptions
via config file, or at least I wasn't able to) could be creating custom config class and custom factory, something like this
/**
* The custom configuration class for {@link io.vertx.core.net.PemTrustOptions}.
*/
@ConfigurationProperties(PgClientSettings.PREFIX + ".custom-pem-trust-options")
public class CustomPemTrustConfiguration {
private ArrayList<String> certPaths;
public ArrayList<String> getCertPaths() {
return certPaths;
}
public void setCertPaths(ArrayList<String> certPaths) {
this.certPaths = certPaths;
}
}
Custom factory replacing default one so we can set PemTrustOptions. Can extend if needed for other non configurable options
/**
* The custom client factory able to configure custom {@link PemTrustOptions}.
*/
@Factory
@Replaces(factory = PgClientFactory.class)
public class PgClientCustomFactory {
private final PgClientConfiguration connectionConfiguration;
private final CustomPemTrustConfiguration customPemTrustConfiguration;
/**
* The Vertx instance if you are running with Vert.x.
*/
private final Vertx vertx;
public PgClientCustomFactory(PgClientConfiguration connectionConfiguration, @Nullable CustomPemTrustConfiguration customPemTrustConfiguration, @Nullable Vertx vertx) {
this.connectionConfiguration = connectionConfiguration;
this.customPemTrustConfiguration = customPemTrustConfiguration;
this.vertx = vertx;
}
@Singleton
@Bean(preDestroy = "close")
public PgPool client() {
if (this.vertx == null) {
return createClient();
} else {
return createClient(vertx);
}
}
private PgPool createClient() {
PgClientConfiguration configuration = this.connectionConfiguration;
String connectionUri = configuration.getUri();
if (StringUtils.isNotEmpty(connectionUri)) {
return PgPool.pool(connectionUri, configuration.getPoolOptions());
} else {
return PgPool.pool(initPemTrustOptions(configuration.getConnectOptions()), configuration.getPoolOptions());
}
}
private PgPool createClient(Vertx vertx) {
PgClientConfiguration configuration = this.connectionConfiguration;
String connectionUri = configuration.getUri();
if (StringUtils.isNotEmpty(connectionUri)) {
return PgPool.pool(vertx, connectionUri, configuration.getPoolOptions());
} else {
return PgPool.pool(vertx, initPemTrustOptions(configuration.getConnectOptions()), configuration.getPoolOptions());
}
}
private PgConnectOptions initPemTrustOptions(PgConnectOptions connectOptions) {
if (customPemTrustConfiguration != null) {
List<String> certPaths = customPemTrustConfiguration.getCertPaths();
if (CollectionUtils.isNotEmpty(certPaths)) {
PemTrustOptions pemTrustOptions = new PemTrustOptions();
certPaths.forEach(pemTrustOptions::addCertPath);
connectOptions.setPemTrustOptions(pemTrustOptions);
}
}
return connectOptions;
}
}
and then application.yml would look like this
vertx:
pg:
client:
port: 5432
host: localhost
database: stores_db
user: user
password: password
maxSize: 5
custom-pem-trust-options:
cert-paths:
- /path/.certs/my.cert
This is just the idea, you can rearrange your config classes and config paths for other needs.
Thank you for your reply. I do not know if your code would be called upon starting the application. Because the crash stacktrace upon starting the application is caused by
"at io.micronaut.configuration.vertx.pg.client.PgDriverFactory.build(PgDriverFactory.java:67)"
My temporary workaround is to copy the code of PgDriverFactory.java to my own project directory and then add certificate related configurations.
Here is my change of the code Translated:
/*
* Copyright 2017-2020 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.configuration.vertx.pg.client;
import com.bbbang.parent.configuration.properties.VertXProperties;
import com.bbbang.parent.tools.TrustOptionsSSL;
import io.micronaut.configuration.vertx.pg.client.PgClientConfiguration;
import io.micronaut.context.annotation.Bean;
import io.micronaut.context.annotation.Factory;
import io.micronaut.context.annotation.Replaces;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.core.util.StringUtils;
import io.vertx.core.Vertx;
import io.vertx.pgclient.PgConnectOptions;
import io.vertx.pgclient.spi.PgDriver;
import io.vertx.sqlclient.Pool;
import jakarta.inject.Singleton;
import java.util.Collections;
/**
* The Factory for creating Vertx Pg client.
*
* @author Denis Stepanov
* @since 4.5.0
*/
@Factory
//@Replaces(factory = io.micronaut.configuration.vertx.pg.client.PgDriverFactory.class)
class PgDriverFactory {
private final PgClientConfiguration connectionConfiguration;
/**
* The Vertx instance if you are running with Vert.x.
*/
private final Vertx vertx;
private final VertXProperties vertXProperties;
/**
* Create the factory with given Pg Client configuration.
*
* @param connectionConfiguration The Pg ClientOption configurations
* @param vertx The vertx instance
* @param vertXProperties
*/
PgDriverFactory(PgClientConfiguration connectionConfiguration, @Nullable Vertx vertx, VertXProperties vertXProperties) {
this.vertXProperties = vertXProperties;
connectionConfiguration.getConnectOptions().setSsl(this.vertXProperties.getSsl());
if (this.vertXProperties.getSsl()){
connectionConfiguration.getConnectOptions()
.setSslMode(this.vertXProperties.getSslMode())
.setPemTrustOptions(TrustOptionsSSL.Companion.getDefaultTrustOptionsSSL());
}
this.connectionConfiguration = connectionConfiguration;
this.vertx = vertx;
}
/**
* @return client A pool of connections.
*/
@Singleton
@Bean(preDestroy = "close")
Pool build() {
String connectionUri = connectionConfiguration.getUri();
if (StringUtils.isNotEmpty(connectionUri)) {
PgConnectOptions pgConnectOptions = PgDriver.INSTANCE.parseConnectionUri(connectionUri);
return PgDriver.INSTANCE.createPool(vertx, Collections.singletonList(pgConnectOptions), connectionConfiguration.getPoolOptions());
}
return PgDriver.INSTANCE.createPool(vertx, Collections.singletonList(connectionConfiguration.getConnectOptions()), connectionConfiguration.getPoolOptions());
}
}
TrustOptionsSSL.kt
class TrustOptionsSSL {
companion object{
/**
* 根据cockroachdb文档显示,默认root.crt证书执行后放置位置在
* windows: C:\Users\admin\AppData\Roaming\postgresql\root.crt
* linux: /home/admin/.postgresql/root.crt
* windows必须设置APPDATA环境变量
*/
fun getDefaultTrustOptionsSSL(): PemTrustOptions {
val certName = "postgresql${File.separator}root.crt"
val os = System.getProperty("os.name")
val certPath = if (os != null && os.lowercase(Locale.getDefault()).startsWith("windows")) {
val tmpNoPrefix = System.getenv("APPDATA")
"${tmpNoPrefix}${File.separator}${certName}"
} else {
"${getUnixHome()}${File.separator}.${certName}"
}
return PemTrustOptions().addCertPath(certPath)
}
private fun getUnixHome():String {
return System.getProperty("user.home") ?: "~"
}
}
}
This is a very basic solution in my project that uses the default location of the generated root.crt certificate. Other related issues are not addressed such as:
To properly configure SSL for my Micronaut PostgreSQL connection, I would also need to address:
The current code only loads the root.crt certificate from a hardcoded absolute file path. It does not address the full scope of configuration options needed for a production-ready SSL connection.
Yes, that's basically similar. Custom factory I proposed replaces default factory (you should probably use @Replaces
as well, but that works too) and it is invoked when PgPool
instance is being created during startup. So, for your needs you might want to introduce some other config stuff you mentioned above and configure PgConnectOptions
as needed similar to this
private PgConnectOptions initPemTrustOptions(PgConnectOptions connectOptions) {
if (customPemTrustConfiguration != null) {
List<String> certPaths = customPemTrustConfiguration.getCertPaths();
if (CollectionUtils.isNotEmpty(certPaths)) {
PemTrustOptions pemTrustOptions = new PemTrustOptions();
certPaths.forEach(pemTrustOptions::addCertPath);
connectOptions.setPemTrustOptions(pemTrustOptions);
}
}
return connectOptions;
}
Expected Behavior
Micronaut 3.9.2 + jpa + reactive +vert.x +cockroachdb
throw exception code:
how can id config trustOptions ?look like this ? trust-options/pem-trust-options i hava the root ca file: certs/ca.crt
Actual Behaviour
No response
Steps To Reproduce
No response
Environment Information
windows jdk17
Example Application
https://github.com/jiliapp/micronaut-jpa-reactive-cockroachdb-demo
Version
3.9.2