mTLS Setup
Configure mutual TLS (mTLS) for a KubeMQ Kotlin client with file-based or PEM-bytes certificates.
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 tls { } builder block's caCertFile, certFile, and keyFile (or the caCertPem / certPem / keyPem 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
- Kotlin SDK installed (
implementation("io.kubemq.sdk:kubemq-sdk-kotlin:1.0.1")) - CA certificate, client certificate, and client private key files
Code
package io.kubemq.sdk.examples.tls
import io.kubemq.sdk.client.KubeMQClient
import kotlinx.coroutines.runBlocking
private const val ADDRESS = "localhost:50001"
private const val CLIENT_ID = "kotlin-tls-mtls-setup"
private const val CA_CERT_FILE = "/path/to/ca.pem"
private const val CLIENT_CERT_FILE = "/path/to/client.pem"
private const val CLIENT_KEY_FILE = "/path/to/client.key"
fun main() = runBlocking {
connectWithMutualTls()
connectWithMutualTlsFromPemBytes()
println("mTLS setup examples completed.")
}
private fun connectWithMutualTls() {
println("=== Mutual TLS (mTLS) Connection ===\n")
// Create a client with mTLS (client cert + key + CA cert)
try {
val client = KubeMQClient.queues {
address = ADDRESS
clientId = CLIENT_ID
tls {
caCertFile = CA_CERT_FILE
certFile = CLIENT_CERT_FILE
keyFile = CLIENT_KEY_FILE
}
}
println("mTLS client configured with file paths:")
println(" CA: $CA_CERT_FILE")
println(" Cert: $CLIENT_CERT_FILE")
println(" Key: $CLIENT_KEY_FILE")
// Uncomment when mTLS server is available:
// client.use { println("Connected: ${it.ping().host}") }
client.close()
} catch (e: Exception) {
println("mTLS connection failed: ${e.message}")
}
}
private fun connectWithMutualTlsFromPemBytes() {
println("\n=== Mutual TLS from PEM bytes ===\n")
// Load certs from PEM bytes instead of files
val caBytes = "-----BEGIN CERTIFICATE-----\n... CA cert ...\n-----END CERTIFICATE-----".toByteArray()
val certBytes = "-----BEGIN CERTIFICATE-----\n... client cert ...\n-----END CERTIFICATE-----".toByteArray()
val keyBytes = "-----BEGIN PRIVATE KEY-----\n... client key ...\n-----END PRIVATE KEY-----".toByteArray()
try {
val client = KubeMQClient.queues {
address = ADDRESS
clientId = "$CLIENT_ID-pem"
tls {
caCertPem = caBytes
certPem = certBytes
keyPem = keyBytes
}
}
println("mTLS client configured with PEM bytes.")
// Uncomment when mTLS server is available:
// client.use { println("Connected: ${it.ping().host}") }
client.close()
} catch (e: Exception) {
println("mTLS PEM connection failed: ${e.message}")
}
}How It Works
- mTLS requires three components: CA certificate, client certificate, and client private key.
- File-based configuration: Use
caCertFile,certFile, andkeyFilewith file paths. - PEM-bytes configuration: Use
caCertPem,certPem, andkeyPemwith byte arrays loaded from any source. - The PEM-bytes approach is useful when certificates come from secrets managers, environment variables, or Kubernetes secrets.
- Both client and server verify each other's certificates for mutual authentication.
Related
Was this page helpful?