Camel-K: handle self-signed server certificates as a client

Companies sometimes use self-signed certificates internally in their systems. When building a Camel-K application we need to tell Camel to trust those certificates. I’m here going to show one solution in Java for this, using a truststore.

MyHTTPClient.java

import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.support.jsse.*;

public class MyHTTPClient extends RouteBuilder {

    @Override
    public void configure() throws Exception {
        registerSslContextParameter(); // 4.

        from("timer:mytimer?repeatCount=1")
            .to("https://my.server.com/person?
                       sslContextParameters=#mySSLContextParameters") // 5.
            .log("${body}");
    }

    private void registerSslContextParameter() throws Exception { // 1.
        KeyStoreParameters tsp = new KeyStoreParameters();
        tsp.setResource("/etc/ssl/truststore.jks"); // 2.
        tsp.setPassword("password");

        TrustManagersParameters tmp = new TrustManagersParameters();
        tmp.setKeyStore(tsp);

        SSLContextParameters sslContextParameters = new SSLContextParameters();
        sslContextParameters.setTrustManagers(tmp);

        this.getContext()
            .getRegistry()
                 .bind("mySSLContextParameters", sslContextParameters); // 3.
    }
}

The important parts:

  1. We need a place to create our SSL context – I like to put it in a separate function
  2. Path to the truststore that contain the self-signed certificate
  3. Register our new SSL context in the Camel register
  4. Call our function to set the new SSL context before our Camel flow
  5. Now we need to tell the Camel HTTP-component to use our new SSL context via the components url parameters

Run parameters

kamel run --resource file:truststore.jks@/etc/ssl/truststore.jks MyHTTPClient.java

Lastly we need to import the truststore into the Camle-K pod. Note that we place the truststore in /etc/ssl/ which is the same as above path (bullet point 2)

Tested on Apache Camel 3.19.0, Minikube v1.29.0 in Ubuntu 20.04 and Java 1.8.0_352

Camel + SpringBoot: How to use custom properties in routes

Spring and Camel makes this quite easy (same solution can be used in Camel-K too). Here is an example of the use of custom property in a route

appilcation.properties

# Greeting
greeting = Hello World

# Timer
timer.period = 2000

Example route with the above properties

from("timer:hello?period={{timer.period}}")
     .log("{{greeting}}");

The route will now print out “Hello World” every 2 seconds

Tested on Apache Camel 3.20.0, SpringBoot 2.7.6, Java 11.0.18 and Ubuntu 20.04.4 LTS

Simple JMS Producer

Here is a JMS Producer template to use when I forget how to write them. It uses ActiveMQ as JMS provider and JNDI for connection propereties:

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.Message;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.naming.InitialContext;

public class Producer {

    public static void main(String[] args) throws Exception {

        InitialContext context = new InitialContext();
        ConnectionFactory factory = 
                 (ConnectionFactory) context.lookup("ConnectionFactory");

        Connection connection = factory.createConnection();
        connection.start();

        // Start a non-transacted session for sending messages
        Session session = 
               connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

        Destination destination = (Destination) context.lookup("test");
        MessageProducer consumer = session.createProducer(destination);

        // Create text message
        Message message = session.createTextMessage("Hello World");

        // Send 10 "Hello World" messages to queue
        for (int i = 0; i < 10; i++) {
            consumer.send(message);
        }

        // Clean up
        session.close();
        connection.close();
        context.close();

    }
}

jndi.properties:

java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory

# Use the following property to configure the default connector
java.naming.provider.url = tcp://localhost:61616

# Register some queues in JNDI using the form
# queue.[jndiName] = [physicalName]
queue.test = NIKLAS.TEST

ActiveMQ Client lib dependency pom:

<dependency>
     <groupid>org.apache.activemq</groupid>
     <artifactid>activemq-client</artifactid>
     <version>5.7.0</version>
</dependency>

Tested on Windows 10, Maven 3.8.4, Java 11.0.18 and ActiveMQ Client 5.7.0