7

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?

Dth
  • 1,916
  • 3
  • 23
  • 34
  • I found this https://stackoverflow.com/a/54517407/11226302 to be very useful for the same in java. – Shivam Puri Dec 13 '19 at 08:32
  • @ShivamPuri Yes, using the noop TrustManager does the job in Java, and I'm looking for a similar solution here. But Kafka client initialises itself and, as far as I'm concerned, I can only configure it with the settings it exposes, so I found no way of doing that. – Dth Dec 13 '19 at 08:43
  • 1
    If you're both skipping certification and hostname validation, it feels like you want to use PLAINTEXT instead of SSL – Mickael Maison Dec 13 '19 at 11:19
  • 8
    @MickaelMaison, SSL without auth can still be useful. Encrypted network traffic is a benefit even if you do not authenticate on either side of the connection. – jeremysprofile Jan 23 '20 at 22:29

2 Answers2

6

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.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.Set;

public class InsecureSslEngineFactory implements SslEngineFactory {

    private final TrustManager INSECURE_TRUST_MANAGER = new X509TrustManager() {

        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        public void checkClientTrusted(X509Certificate[] certs, String authType) {
            // empty
        }

        public void checkServerTrusted(X509Certificate[] certs, String authType) {
            // empty
        }
    };

    @Override
    public SSLEngine createClientSslEngine(String peerHost, int peerPort, String endpointIdentification) {
        TrustManager[] trustManagers = new TrustManager[]{ INSECURE_TRUST_MANAGER };
        try {
            SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustManagers, new SecureRandom());
            SSLEngine sslEngine = sslContext.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() {

    }

    @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, InsecureSslEngineFactory.class);

or if you don't want to use the constant:

props.put("ssl.engine.factory.class", InsecureSslEngineFactory.class);

Make sure you don't use this setup in production!

martinnemec3
  • 383
  • 6
  • 14
0

src/main/resources/application.yml

#Server host name verification is disabled by setting ssl.endpoint.identification.algorithm to an empty string
spring.kafka.properties.ssl.endpoint.identification.algorithm
ncowboy
  • 1,311
  • 2
  • 13
  • 19