I have ActiveMQ Artemis cluster, active-backup mode with shared store, version 2.17.0. SSL is used with this cluster.
I've taken keystore/truststore files from Kafka cluster that works totally fine with 2-way TLS. I re-use these files with Artemis and it also works perfectly fine. However, the issue comes when I enable needClientAuth=true in URL string.
Here is what documentation says:
needClientAuth
This property is only for an
acceptor. It tells a client connecting to this acceptor that 2-way SSL is required. Valid values aretrueorfalse. Default isfalse.
So if I want to achieve 2-way TLS, I must use this option. Then both - the server and the client must have it's own keystore/truststore pair. In my case it's identical for both server and the client.
When I have needClientAuth=true in acceptor URL string, I connect to Artemis cluster using Artemis CLI and that's what I get in CLI output:
Connection failed::Failed to create session factory
This is what Artemis instance says:
WARN [org.apache.activemq.artemis.core.server] AMQ222208: SSL handshake failed for client from /123.123.123.123:36788: javax.net.ssl.SSLHandshakeException: Empty client certificate chain.
As I said, mentioned keystore/truststore works fine with Kafka, no issues. However, it does not work with ActiveMQ Artemis. If I remove needClientAuth=true from acceptor URL string, everything works just fine.
Here is how I generate keystore/truststore:
# Generate private key and CSR
openssl req -new -newkey rsa:2048 -nodes -days 365 -subj '/CN=something.com/OU=XXX/O=Company/L=City/ST=City/C=XX' -keyout private.key -out mycsr.csr
# Upload CSR to magic website, get back CA and signed certificate.
# ...
# Since CA is chain, and you cannot import chain into keystore/truststore, split into multiple files: ca1.cer and ca2.cer.
# ...
# Create truststore.jks
keytool -importcert -noprompt -alias ca1 -file ca1.cer -keystore truststore.jks
keytool -importcert -noprompt -alias ca2 -file ca2.cer -keystore truststore.jks
# Because it's impossible to create JKS keystore out of private key, first generate PKCS12 keystore:
openssl pkcs12 -inkey private.key -in certificate.cer -export -out keystore.p12
# Now convert PKCS12 keystore to JKS keystore:
keytool -importkeystore -srckeystore keystore.p12 -srcstoretype pkcs12 -destkeystore keystore.jks -deststoretype jks
# Since above command added only a private key, we also need to add an issued certificate:
keytool -importcert -noprompt -alias certificate -file certificate.cer -keystore keystore.jks
# Some client's (in Kafka) does not work if CA is not added to keystore, so add it:
keytool -importcert -noprompt -alias ca1 -file ca1.cer -keystore keystore.jks
keytool -importcert -noprompt -alias ca2 -file ca2.cer -keystore keystore.jks
# End up with the following files:
keystore.jks
truststore.jks
---------
ca.cer
certificate.cer
private.key
Acceptor URL (with needClientAuth=true):
tcp://server.com:1234?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;amqpMinLargeMessageSize=102400;protocols=CORE,AMQP,STOMP,HORNETQ,MQTT,OPENWIRE;useEpoll=true;amqpCredits=1000;amqpLowCredits=300;amqpDuplicateDetection=true;sslEnabled=true;needClientAuth=true;keyStorePath=/opt/ssl/keystore.jks;keyStorePassword=123;trustStorePath=/opt/ssl/truststore.jks;trustStorePassword=123
When connecting using ActiveMQ Artemis CLI, I pass this URL:
tcp://server.com:1234?sslEnabled=true;keyStorePath=/opt/ssl/truststore.jks;keyStorePassword=123;trustStorePath=/opt/ssl/truststore.jks;trustStorePassword=123
What am I missing?
-Djavax.net.debug=sslto theJAVA_ARGSvariable defined in theartemis.profilefile. - Domenico Francesco Bruscino