0

I have Strimzi's Kafka + KafkaConnect hosted in a local kubernetes cluster, and I'm trying to attach a Debezium connector that would connect to a remote mongo server through SSL.

I've tried a few different configurations and none of them seem to allow me to specify the path to a pem file that I would normally use to authenticate.

My mongo-connector.yaml for both tries:

apiVersion: kafka.strimzi.io/v1beta2
kind: KafkaConnector
metadata:
  name: debezium-mongo-connector
  labels:
    strimzi.io/cluster: my-connect-cluster 
spec:
  class: io.debezium.connector.mongodb.MongoDbConnector
  tasksMax: 1
  config:
    mongodb.hosts: test
    mongodb.name: test
    mongodb.user: username
    mongodb.password: password
    mongodb.ssl.enabled: true
    mongodb.ssl.invalid.hostname.allowed: true
    database.include.list: db-dev
    database.history.kafka.bootstrap.servers: my-cluster-kafka-bootstrap:9092
    collection.include.list: products

1. Connecting without configuring KafkaConnect certificates
kafka-connect.yaml:

apiVersion: kafka.strimzi.io/v1beta2
kind: KafkaConnect
metadata:
  name: my-connect-cluster
  annotations:
    strimzi.io/use-connector-resources: "true"
spec:
  version: 3.2.0
  replicas: 1
  bootstrapServers: my-cluster-kafka-bootstrap:9092
  image: strimzi-debezium-connector
  config:
    config.storage.replication.factor: -1
    offset.storage.replication.factor: -1
    status.storage.replication.factor: -1

This results in a pretty standard SSL handshake error because the certificate normally used in the connection isn't specified anywhere

com.mongodb.MongoSocketWriteException: Exception sending message
    at com.mongodb.internal.connection.InternalStreamConnection.translateWriteException(InternalStreamConnection.java:665)
    at com.mongodb.internal.connection.InternalStreamConnection.sendMessage(InternalStreamConnection.java:542)
    at com.mongodb.internal.connection.InternalStreamConnection.sendCommandMessage(InternalStreamConnection.java:368)
    at com.mongodb.internal.connection.InternalStreamConnection.sendAndReceive(InternalStreamConnection.java:317)
    at com.mongodb.internal.connection.CommandHelper.sendAndReceive(CommandHelper.java:88)
    at com.mongodb.internal.connection.CommandHelper.executeCommand(CommandHelper.java:36)
    at com.mongodb.internal.connection.InternalStreamConnectionInitializer.initializeConnectionDescription(InternalStreamConnectionInitializer.java:129)
    at com.mongodb.internal.connection.InternalStreamConnectionInitializer.startHandshake(InternalStreamConnectionInitializer.java:71)
    at com.mongodb.internal.connection.InternalStreamConnection.open(InternalStreamConnection.java:167)
    at com.mongodb.internal.connection.DefaultServerMonitor$ServerMonitorRunnable.lookupServerDescription(DefaultServerMonitor.java:195)
    at com.mongodb.internal.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:151)
    at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:654)
    at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.onCertificate(CertificateMessage.java:473)
    at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.consume(CertificateMessage.java:369)
    at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392)
    at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:443)
    at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:421)
    at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:183)
    at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:172)
    at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1506)
    at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1416)
    at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:456)
    at java.base/sun.security.ssl.SSLSocketImpl.ensureNegotiated(SSLSocketImpl.java:921)
    at java.base/sun.security.ssl.SSLSocketImpl$AppOutputStream.write(SSLSocketImpl.java:1291)
    at com.mongodb.internal.connection.SocketStream.write(SocketStream.java:99)
    at com.mongodb.internal.connection.InternalStreamConnection.sendMessage(InternalStreamConnection.java:539)
    ... 10 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:439)
    at java.base/sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:306)
    at java.base/sun.security.validator.Validator.validate(Validator.java:264)
    at java.base/sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:313)
    at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:222)
    at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:129)
    at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:638)
    ... 24 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at java.base/sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
    at java.base/sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
    at java.base/java.security.cert.CertPathBuilder.build(CertPathBuilder.java:297)
    at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:434)
    ... 30 more

2. Setting kafka-connect tls.trustedCertificates
kafka-connect.yaml:

apiVersion: kafka.strimzi.io/v1beta2
kind: KafkaConnect
metadata:
  name: my-connect-cluster
  annotations:
    strimzi.io/use-connector-resources: "true"
spec:
  version: 3.2.0
  replicas: 1
  bootstrapServers: my-cluster-kafka-bootstrap:9093
  image: strimzi-debezium-connector
  tls:
    trustedCertificates:
      - secretName: mongo-cert
        certificate: rds-combined-ca-bundle.pem
  config:
    config.storage.replication.factor: -1
    offset.storage.replication.factor: -1
    status.storage.replication.factor: -1

This results in a bad_certificate error when connecting to the cluster, I assume because including trustedCertificates forces authentication with Kafka.
This same connection works fine when connecting to the cluster's 9092(plain) port and trustedCertificates configuration is not included.

org.apache.kafka.connect.errors.ConnectException: Failed to connect to and describe Kafka cluster. Check worker's broker connection and security properties.
    at org.apache.kafka.connect.util.ConnectUtils.lookupKafkaClusterId(ConnectUtils.java:72)
    at org.apache.kafka.connect.util.ConnectUtils.lookupKafkaClusterId(ConnectUtils.java:53)
    at org.apache.kafka.connect.cli.ConnectDistributed.startConnect(ConnectDistributed.java:97)
    at org.apache.kafka.connect.cli.ConnectDistributed.main(ConnectDistributed.java:80)
Caused by: java.util.concurrent.ExecutionException: org.apache.kafka.common.errors.SslAuthenticationException: Failed to process post-handshake messages
    at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:395)
    at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1999)
    at org.apache.kafka.common.internals.KafkaFutureImpl.get(KafkaFutureImpl.java:165)
    at org.apache.kafka.connect.util.ConnectUtils.lookupKafkaClusterId(ConnectUtils.java:66)
    ... 3 more
Caused by: org.apache.kafka.common.errors.SslAuthenticationException: Failed to process post-handshake messages
Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:117)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:340)
    at java.base/sun.security.ssl.Alert$AlertConsumer.consume(Alert.java:293)
    at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:186)

Is it possible to specify the certificate for just the Debezium Mongo connector, or include the certificate in KafkaConnect's trustedCertificates while still connecting to the plain Kafka listener?

Mike H
  • 11
  • 2

1 Answers1

0

One possibility is to:

  1. Create a custom truststore that trusts your mongo CA

  2. Add the truststore to a secret like mongo-cert

  3. Use an ExternalConfiguration to mount in a volume into your KafkaConnect like:

apiVersion: kafka.strimzi.io/v1beta2
kind: KafkaConnect
...
spec:
  externalConfiguration:
    volumes:
      - name: mongo-cert
        secret:
          secretName: mongo-cert

Which will mount the certs into kafka connect under /opt/kafka/external-configuration/mongo-cert.

  1. Set jvmOptions for KafkaConnect so the JVM uses your custom truststore:
jvmOptions:
 javaSystemProperties:
   - name: javax.net.ssl.trustStore
     value: /opt/kafka/external-configuration/mongo-cert/mongodb-custom-truststore.jks
   - name: javax.net.ssl.trustStorePassword
     value: "123456"

Here's a repo where I've got an example going on minikube with mongo using mutual TLS and a debezium source connector on Strimzi (connecting to kafka without tls).

From what I could see the debezium mongo source connector doesn't have a way to configure a custom TLS certificate via the connector configuration. Contrast that with database.sslrootcert in the debezium postgres connector.

roby
  • 3,103
  • 1
  • 16
  • 14