If I have a self-signed certificate, as a good citizen, I will import it to my keystore and configure Kafka client with "ssl.truststore.location" and "ssl.truststore.type" in order to use it.
If expect that a Common Name from certificate's subject can differ from the host's address that presented it, I can turn off the endpoint validation with "ssl.endpoint.identification.algorithm".
What if I wanted to skip the SSL validation altogether, not just for the hostname, so that I no longer need to copy the certificates around? Analogous to the "-k" or "--insecure" setting in curl. Can I do it with a default Java client for Kafka?
There is one way to accomplish it however it's not so straightforward.
The idea is to implement the interface org.apache.kafka.common.security.auth.SslEngineFactory that will ignore the certificate validation. When you use it as a client it should be enough to implement just the createClientSslEngine method in a way similar to this:
import org.apache.kafka.common.security.auth.SslEngineFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.Set;
public static class MySslEngineFactory implements SslEngineFactory {
@Override
public SSLEngine createClientSslEngine(String peerHost, int peerPort, String endpointIdentification) {
try {
TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() { return null; }
public void checkClientTrusted(X509Certificate[] certs, String authType) { }
public void checkServerTrusted(X509Certificate[] certs, String authType) { }
}};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
SSLEngine sslEngine = sc.createSSLEngine(peerHost, peerPort);
sslEngine.setUseClientMode(true);
return sslEngine;
} catch (NoSuchAlgorithmException | KeyManagementException e) {
throw new RuntimeException(e);
}
}
@Override
public SSLEngine createServerSslEngine(String peerHost, int peerPort) {
return null;
}
@Override
public boolean shouldBeRebuilt(Map<String, Object> nextConfigs) {
return false;
}
@Override
public Set<String> reconfigurableConfigs() {
return null;
}
@Override
public KeyStore keystore() {
return null;
}
@Override
public KeyStore truststore() {
return null;
}
@Override
public void close() throws IOException {
}
@Override
public void configure(Map<String, ?> configs) {
}
}
After having this class finished you just configure it as a SSL_ENGINE_FACTORY_CLASS in kafka (producer or consumer) properties:
props.put(SslConfigs.SSL_ENGINE_FACTORY_CLASS, MySslEngineFactory.class);
or if you don't want to use the constant:
props.put("ssl.engine.factory.class", MySslEngineFactory.class);
Make sure you don't use this setup in production!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With