minio 8.4.4 使用自签名的https的api连接会报错证书错误
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
<dependency>
<groupId>io.miniogroupId>
<artifactId>minioartifactId>
<version>8.4.4version>
<exclusions>
<exclusion>
<groupId>com.squareup.okhttp3groupId>
<artifactId>okhttpartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>com.squareup.okhttp3groupId>
<artifactId>okhttpartifactId>
<version>4.10.0version>
dependency>
@Configuration
@EnableConfigurationProperties(MinioProperties.class)
public class MinioConfig {
@Bean
public MinioClient minioClient(MinioProperties properties){
properties.check();
return MinioClient.builder()
.endpoint(properties.getEndpoint())
.credentials(properties.getAccessKey(), properties.getSecretKey())
.build();
}
}
通常是因为MinIO默认情况下会验证服务器的TLS证书。在生产环境中,使用自签名证书并不推荐,因为它们不受信任的证书颁发机构(CA)签署,可能会导致安全问题。
为了在生产环境中确保安全性,建议获取一个受信任的SSL证书,可以从证书颁发机构(CA)购买,或者使用免费的证书颁发机构(例如Let’s Encrypt)获取SSL证书。
在MinIO客户端(例如mc命令行工具)中,可以使用–insecure选项来忽略证书验证。例如:
mc --insecure <command>
这会告诉MinIO客户端不要验证服务器的TLS证书。请注意,这种做法会降低安全性,不建议在生产环境中使用。
在使用Java SDK与自签名证书的服务器进行通信时,一般可以通过自定义SSLContext来忽略证书验证。
MinIO的Java SDK(version 8.0.6及以上)允许自定义OkHttpClient,我们可以使用httpClient方法传递一个自定义的OkHttpClient实例。以便在HTTP、正常HTTPS和自签名HTTPS之间实现兼容性
下面是如何使用自定义的OkHttpClient实现对HTTP、正常HTTPS和自签名HTTPS的兼容性
@Configuration
@EnableConfigurationProperties(MinioProperties.class)
public class MinioConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(MinioConfig.class);
@Bean
public MinioClient minioClient(MinioProperties properties){
properties.check();
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
// Do nothing (trust any client certificate)
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
// Do nothing (trust any server certificate)
}
}
};
// Install the all-trusting trust manager
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
} catch (Exception e) {
LOGGER.error("Install the all-trusting trust manager error:{}", e.getMessage());
}
// Create a custom OkHttpClient that trusts all certificates
OkHttpClient customHttpClient = new OkHttpClient.Builder()
.sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustAllCerts[0])
.hostnameVerifier((hostname, session) -> true)
.build();
// Set the custom SSLContext for MinioClient
return MinioClient.builder()
.endpoint(properties.getEndpoint())
.credentials(properties.getAccessKey(), properties.getSecretKey())
.httpClient(customHttpClient)
.build();
}
}
这种方法会将所有证书都视为受信任的,因此请仅在非生产环境中使用此方法,以确保通信的安全性和完整性。在生产环境中,建议使用受信任的SSL证书。
之前minioclient与服务器端交互使用默认的httpclient的客户端,请求没有打印详细日志. 既然上面自定义自己的httpclient那么可以补充自定义拦截器打印日志
public class CustomLoggingInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
long startTime = System.nanoTime();
System.out.println("Sending request " + request.url() + " on " + chain.connection() + "\n" + request.headers());
Response response = chain.proceed(request);
long endTime = System.nanoTime();
System.out.println("Received response for " + response.request().url() + " in " + ((endTime - startTime) / 1e6) + "ms\n" + response.headers());
MediaType contentType = response.body().contentType();
String content = response.body().string();
System.out.println("Response body:\n" + content);
ResponseBody wrappedBody = ResponseBody.create(contentType, content);
return response.newBuilder().body(wrappedBody).build();
}
}
修改MinioConfig增加okhttp拦截器
// Create a custom OkHttpClient that trusts all certificates
OkHttpClient customHttpClient = new OkHttpClient.Builder()
.sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustAllCerts[0])
.hostnameVerifier((hostname, session) -> true)
.addInterceptor(new CustomLoggingInterceptor()) // Add custom interceptor here
.build();
minio客户端本质使用httpclient与服务端交互,因此证书问题处理其实只是httpclient对证书的兼容处理。该处理方式可以运用到其他使用到httpclient的场景。
代码优化
@Configuration
@EnableConfigurationProperties(MinioProperties.class)
public class MinioConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(MinioConfig.class);
@Bean
public MinioClient minioClient(MinioProperties properties){
properties.check();
OkHttpClient customHttpClient = null;
if (properties.getEndpoint().startsWith("https://")) {
// 如果是HTTPS,使用自定义的OkHttpClient处理自签名的HTTPS请求
customHttpClient = createCustomOkHttpClient();
}
MinioClient minioClient;
if (customHttpClient != null) {
// 如果使用了自定义的OkHttpClient
minioClient = MinioClient.builder()
.endpoint(properties.getEndpoint())
.credentials(properties.getAccessKey(), properties.getSecretKey())
.httpClient(customHttpClient)
.build();
} else {
// 如果是普通HTTP,使用默认的OkHttpClient
minioClient = MinioClient.builder()
.endpoint(properties.getEndpoint())
.credentials(properties.getAccessKey(), properties.getSecretKey())
.build();
}
return minioClient;
}
/**
* Set the custom SSLContext for MinioClient
* @return
*/
private static OkHttpClient createCustomOkHttpClient() {
// 创建自定义的OkHttpClient,用于处理自签名的HTTPS请求
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
// Do nothing (trust any client certificate)
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
// Do nothing (trust any server certificate)
}
}
};
// Install the all-trusting trust manager
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
} catch (Exception e) {
LOGGER.error("Install the all-trusting trust manager error:{}", e.getMessage());
}
// Create a custom OkHttpClient that trusts all certificates
OkHttpClient customHttpClient = new OkHttpClient.Builder()
.sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustAllCerts[0])
.hostnameVerifier((hostname, session) -> true)
// 增加minio http请求日志打印
//.addInterceptor(new CustomLoggingInterceptor()) // Add custom interceptor here
.build();
return customHttpClient;
}
}