KubeMQ
Client SDKsJavaHow-to guidesTLS

mTLS Setup

Configure mutual TLS authentication for Java client connections

Overview

Standard TLS only proves the server's identity — the server itself accepts any client that knows the address and client ID. Mutual TLS (mTLS) closes that gap: the client also presents a certificate, so the server verifies who is connecting before accepting the connection. That matters on zero-trust networks and in regulated environments where "reaches the port" isn't an acceptable authorization model — the certificate becomes the credential.

The builder's .tls(true), .caCertFile(), .tlsCertFile(), and .tlsKeyFile() (or the .caCertPem() / .tlsCertPem() / .tlsKeyPem() byte-array variants) wire in three artifacts at client construction: the CA certificate (to verify the server, same as one-way TLS) plus the client's own certificate and private key (for the server to verify in return). Verification happens during the handshake, before any messaging traffic flows.

Gotchas: the certificate and key must be a matched pair signed by a CA the server trusts — a mismatch fails the handshake outright; all three inputs must be valid, unexpired PEM, and expiry breaks connections with no warning; and the CA that signed the client cert isn't necessarily the CA that verifies the server — mixing them up causes "works with TLS, fails with mTLS" confusion.

Prerequisites

  • KubeMQ server running with mTLS enabled
  • Java SDK installed (Maven/Gradle dependency io.kubemq.sdk:kubemq-sdk-Java:3.1.1)
  • TLS certificates (client certificate, client key, and CA certificate)

Code

MtlsSetupExample.java
package io.kubemq.example.tls;

import io.kubemq.sdk.client.KubeMQClient;
import io.kubemq.sdk.common.ServerInfo;
import io.kubemq.sdk.queues.QueuesClient;

/**
 * Mutual TLS Setup Example
 *
 * Demonstrates establishing a mutual TLS (mTLS) connection to KubeMQ server
 * where both client and server authenticate each other with certificates.
 */
public class MtlsSetupExample {

    private static final String ADDRESS = "localhost:50001";
    private static final String CLIENT_ID = "java-tls-mtls-setup-client";
    private static final String CA_CERT_FILE = "/path/to/ca.pem";
    private static final String CLIENT_CERT_FILE = "/path/to/client.pem";
    private static final String CLIENT_KEY_FILE = "/path/to/client.key";

    public void connectWithMutualTLS() {
        System.out.println("=== Mutual TLS (mTLS) Connection ===\n");

        // Create a client with mTLS (client cert + key + CA cert)
        try (QueuesClient client = QueuesClient.builder()
                .address(ADDRESS)
                .clientId(CLIENT_ID)
                .tls(true)
                .caCertFile(CA_CERT_FILE)
                .tlsCertFile(CLIENT_CERT_FILE)
                .tlsKeyFile(CLIENT_KEY_FILE)
                .logLevel(KubeMQClient.Level.INFO)
                .build()) {

            // Verify mTLS connection
            ServerInfo serverInfo = client.ping();
            System.out.println("Connected with mTLS. Server: " + serverInfo);

        } catch (Exception e) {
            System.err.println("mTLS connection failed: " + e.getMessage());
        }
    }

    public void connectWithMutualTLSFromPemBytes() {
        System.out.println("=== Mutual TLS from PEM bytes ===\n");

        // Load certs from PEM bytes instead of files
        byte[] caCertPem = "-----BEGIN CERTIFICATE-----\n... CA cert ...\n-----END CERTIFICATE-----".getBytes();
        byte[] clientCertPem = "-----BEGIN CERTIFICATE-----\n... client cert ...\n-----END CERTIFICATE-----".getBytes();
        byte[] clientKeyPem = "-----BEGIN PRIVATE KEY-----\n... client key ...\n-----END PRIVATE KEY-----".getBytes();

        try (QueuesClient client = QueuesClient.builder()
                .address(ADDRESS)
                .clientId(CLIENT_ID + "-pem")
                .tls(true)
                .caCertPem(caCertPem)
                .tlsCertPem(clientCertPem)
                .tlsKeyPem(clientKeyPem)
                .build()) {

            ServerInfo serverInfo = client.ping();
            System.out.println("Connected with mTLS (PEM bytes). Server: " + serverInfo);

        } catch (Exception e) {
            System.err.println("mTLS PEM connection failed: " + e.getMessage());
        }
    }

    public static void main(String[] args) {
        MtlsSetupExample example = new MtlsSetupExample();
        example.connectWithMutualTLS();
        example.connectWithMutualTLSFromPemBytes();
    }
}

How It Works

  • The builder with .tls(true), .caCertFile(), .tlsCertFile(), and .tlsKeyFile() enables mutual TLS authentication.
  • The server verifies the client's certificate, and the client verifies the server's certificate, establishing bidirectional trust.
  • The SDK also supports loading certificates from PEM byte arrays via .caCertPem(), .tlsCertPem(), and .tlsKeyPem() for environments where certificates are stored in memory or secrets managers.
  • The try-with-resources pattern ensures the client is properly closed after use.

Was this page helpful?

On this page