Tag Archives: IBM MQ

IBM MQ: Add a server certificate to queue manager without an CSR

At my workplace we request SSL certificates based on the server and not on queue manager. Often are these servers populated with more services than MQ so a CSR from MQ might not be possible. In this case we need to get the certificate and key into the queue manager keystore without an CSR. Here is how we usually do it

Through of of this example I am going to use the ikeycmd program, normally found here: /opt/mqm/java/jre64/jre/bin/ikeycmd in the MQ installation on Linux, and openssl which can be found in most Linux systems. We will call the queue manager MYQM01 in this example.

First we need to create a kdb file to hold our certificates

ikeycmd -keydb -create -db "/var/mqm/qmgrs/MYQM01/ssl/key.kbd" -pw changeit -type cms -stash

Where:
db is the path to the queue managers key.kdb file
stash tells ikeycmd to stash the password in a file in the same location as the key.kdb file. This is needed so that MQ later can open the key.kdb file and read its contents

It is now time to add the root cert and all its intermediate certificates (if any). It is important that this is done in the correct order: From root and down to your certificate
Add root cert:

ikeycmd -cert -add -db "/var/mqm/qmgrs/MYQM01/ssl/key.kbd" -pw changeit -label rootca -file DigicertRoot.crt -format ascii

Add ca cert/s:

ikeycmd -cert -add -db "/var/mqm/qmgrs/MYQM01/ssl/key.kbd" -pw changeit -label intermediateca -file DigiCertCA.crt -format ascii

And now to the magic. There are probably many ways to do this but I found creating a p12 file with the certificate and the key to be the simplest
Create the p12 file

openssl pkcs12 -export -in my.host.com.crt -inkey my.host.com.key -out my.host.com.p12 -name "ibmwebspheremqmyqm01"

Import the p12 into the queue manager keystore

ikeycmd -cert -import -db my.host.com.p12 -pw changeit -target "/var/mqm/qmgrs/MYQM01/ssl/key.kbd"

Now set the the new certificate as default

ikeycmd -cert -setdefault -db "/var/mqm/qmgrs/MYQM01/ssl/key.kbd" -stashed -label "ibmwebspheremqmyqm01"

Make sure the key* files has the correct permissions

chmod 640 key.*

Troubleshooting tips

# List personal and ca certificate in the kbd file 
/opt/mqm/java/jre64/jre/bin/ikeycmd -cert -list personal -db "/var/mqm/qmgrs/MYQM01/ssl/key.kbd" -pw changeit
/opt/mqm/java/jre64/jre/bin/ikeycmd -cert -list ca -db "/var/mqm/qmgrs/MYQM01/ssl/key.kbd" -pw changeit

# List default all signers for this installation
/opt/mqm/java/jre64/jre/bin/ikeycmd -cert -listsigners

# Check that a certificate is presented on connect
openssl s_client -connect my.host.com:1414

Tested on MQ 9.0.5.0, Red Hat Linux 7.5 and OpenSSL 1.0.2k-fips

IBM MQ: Setup a dedicated “client” queue manager using cluster technology

I am in this post going to show how I setup a dedicated “clients” queue manager where all queue managers are on the same machine. This can be useful when you want clients to connect to you in a dev or test environment and you do not want them to interfere with your work, and still easily be able to help them with messages.
This example will also show you have to setup any cluster since the tasks are pretty much the same.

We are going to need two queue managers. The one that we are working on (WORK01), and one for the clients to connect to (CLIENTDEV01). To enable sending messages between them we are going to setup a small cluster

We start with making our WORK01 queue manager a full repository and start the cluster there. All commands are for the runmqsc interpreter but can be done via MQExplorer if you like a GUI better

ALTER QMGR REPOS(CLIENTS)

This puts our WORK01 queue manager into a cluster named CLIENTS (which only contains one queue manager at this time)

Now we need a listener for communication…

DEFINE LISTENER(CLUSTER.LISTENER) TRPTYPE(TCP) CONTROL(QMGR) PORT(1420)
START LISTENER(CLUSTER.LISTENER)

This creates a listener for port 1420 and it is started/stopped with the queue manager. This way we don’t have to worry about forgetting to start it

…and channels for messages

DEFINE CHANNEL(TO.WORK01) CHLTYPE(CLUSRCVR) TRPTYPE(TCP) CONNAME('127.0.0.1(1420))') CLUSTER(CLIENTS) DESCR('TCP Cluster-receiver channel for queue manager WORK01')

Create a cluster receiver channel pointing to our listener and a part of the CLIENTS cluster

Now we are done with our WORK01 queue manager. Time to move on to our CLIENTDEV01 queue manager. This queue manager is not going to be a full repository so we do not need to put the queue manager into the CLIENTS cluster. We can here instead choose what objects (queues, topics and so on) to be part of the cluster

We create a listener for communication with the cluster

DEFINE LISTENER(CLUSTER.LISTENER) TRPTYPE(TCP) CONTROL(QMGR) PORT(1421)
START LISTENER(CLUSTER.LISTENER)

Standard TCP listener on port 1421, just as that one for there WORK01 queue manager

A few channels to send messages over

DEFINE CHANNEL(TO.CLIENTDEV01) CHLTYPE(CLUSRCVR) TRPTYPE(TCP) CONNAME('127.0.0.1(1421))') CLUSTER(CLIENTS) DESCR('TCP Cluster-receiver channel for the CLIENTDEV01 queue manager')

This channel points to the listener and is meant to receive messages from the cluster CLIENTS

DEFINE CHANNEL(TO.WORK01) CHLTYPE(CLUSSDR) TRPTYPE(TCP) CONNAME('127.0.0.1(1420)') CLUSTER(CLIENTS) DESCR('Cluster-sender channel from CLIENTDEV01 to the repo WORK01')

Now this needs a little more explaining:
* Cluster sender channel to the full repository on WORK01
* Port (1420) needs to be the same as the listener on the WORK01 queue manager
* Channel name (TO.WORK01) has to have the same name as the cluster receiver channel on the WORK01 queue manager
* Cluster sender channels should ONLY point to full repositories, so we are not going to point any cluster sender channel to our CLIENTSDEV1 queue manager which is a partial repository, only containing the object we define in it
* Cluster channels does not need to be started, they are started automatically

Done!

To test you can now define a queue alias on CLIENTDEV01 queue manager that points to a queue in the CLIENTS cluster on WORK01 and see if messages gets through

Troubleshooting tips:

# Ping remote queue manager through it's cluster receiver channel
runmqsc: PING CHANNEL(<remote qmanager cluster receiver channel>)
# Display channel status on all channels - here you can see the status of the cluster sender/receiver channels
runmqsc: DIS CHSTATUS(*)
# Displays all cluster qmanagers (full or partial) and their clusters names
runmqsc: DIS CLUSQMGR(*)

Tested on MQ7.1.0.1 (RHEL 6.8) and MQ9.0.5.0(RHEL 7.5)

Setup IBM MQ v9 AMQP with Java MQLight client over SSL

This “tutorial” will show how I set up a IBM MQ v9 AMQP channel with two-way self-signed SSL certificate. Since it was quite the pain to get to work I will describe the steps here so that I do not have to figure them out again later. Through this tutorial I will use the iKeyman program (<mqserver>/java/jre64/jre/bin/ikeycmd) for handling keystores and certificates. iKeyman is bundled with IBM MQ v9 (and other versions).

A. We start with creating the keystore and certificate needed for the MQ server.
NOTE: The place for the kdb file can be found (and set) in the queue manager setting SSLKEYR (default: /var/mqm/qmgrs/<queue manager name>/ssl/key)

1. ikeycmd -keydb -create -db key.kdb -type cms -pw mysecret -stash
2. ikeycmd -cert -create -db key.kdb -pw mysecret -label ibmwebspheremqmyqm01 -dn "CN=server,O=IBM,C=US" -size 2048
3. ikeycmd -cert -extract -db key.kdb -pw mysecret -label ibmwebspheremqmyqm01 -target server.arm

A word about the label and the keystore name above.The label the server uses can be found in the CERTLABL setting on the channel OR queue manager depending on your setup. I used used the label on the queue manager for this. Default CERTLABL follows the pattern: ibmwebspheremq<queue manager name> all lower case (labels are case-sensitive)
The keystore name comes from the last part of the SSLKEYR setting. In my case the last part is “key” which gives us that the “kbd” file should be named “key.kbd”

B. Create client SSL key and certificate

1. ikeycmd -keydb -create -db client.jks -type jks -pw mysecret -stash
2. ikeycmd -cert -create -db clinet.jks -pw mysecret -label user -dn "CN=user,O=IBM,C=SE" -size 2048
3. ikeycmd -cert -extract -db client.jks -pw mysecret -label user -target client.arm

C. Exchange certificates between client and server

1. ikeycmd -cert -add -db client.jks -pw mysecret -label server -file server.arm
2. ikeycmd -cert -add -db key.kdb -pw mysecret -label user -file client.arm

D. Time to create a new user that the client can use to connect with
* This user needs to be created on OS level since this is what IBM MQ uses to authorise users
* This user should NOT be a member of the mqm group since it would make him a privileged user and privileged users are blocked by default. It is also a good practise to have users that can only interact with specific objects
* The user DOES NOT need login privileges on OS level (/sbin/nologin)

For this example I create a user:

Login 'client1' 
Password: 'password1'

E. Now we need to grant this user some basic privileges, like connect and pub/sub
I am here going to use the setmqaut program but you can also use MQExplorer if you like a GUI

setmqaut -m MYQM01 -t topic -n TOP.CLIENT1.ACCOUNT.PROCESS.SRV0112 -p client1 -all +pub +sub
setmqaut -m MYQM01 -t qmgr -p client1 -all +connect

Now it is time to set up the AMQP service and the channel to access it

F. Start the AMQP service (using runmqsc <queue manager>)

START SERVICE(SYSTEM.AMQP.SERVICE)

G. Create a AMQP channel to use

DEFINE CHANNEL(AMQP.CLIENT1) CHLTYPE(AMQP) MCAUSER('client1') PORT(9090) SSLCIPH(TLS_RSA_WITH_AES_128_CBC_SHA)

This creates a AMQP enabled channel. The channel allows only one user and for this example I will use port 9090 instead of the default 5672. I have also defined the cipher to use for SSL

H. Start the newly created channel

START CHANNEL(AMQP.CLIENT1)

Time to test the setup. For this I use one of the sample programs in the MQLight bundle, namely the ‘Send’ program. Use the following options

mqlight-samples/send -s "amqps://client1:password1@localhost:9090" -t "Account/" --keystore=client.jks --keystore-passphrase=mysecret --no-verify-name

Explanation
* the -s option is simply the connection string. Note that I am using amqps. The ‘s’ at the end enables SSL protected transport using the cipher set earlier and the certificates created
* the -t options defines that we are publishing to a topic called ‘Account’
* then we simply point out the jks to use
* –no-verify-name is needed because of the self-signed certificate

A few troubleshooting tips

* List user personal and signer certificates in jks
  - ikeycmd -cert -list personal -db client.jks -pw mysecret
  - ikeycmd -cert -list ca -db client.jks -pw mysecret
  - ikeycmd -cert -list personal -db key.kdb -pw mysecret
  - ikeycmd -cert -list ca -db key.kdb -pw mysecret
* Make sure all kdb and jks files have 660 rights
* Make sure to restart the AMQP service if changing chiper
* If you have problem with more users able to access the channel then that one specified in MCUSER, check so that CHLAUTH is enabled on the queue manager
* If passwords are not checked by MQ, check the SYSTEM.DEFAULT.AUTHINFO.IDPWOS setting CHCKCLNT - this needs to be REQUIRED for password checks on unprivileged users

Tested on Red Hat Enterprise Linux Server release 7.5 (Maipo), IBM MQ v9.0.5.0 and MQLight library v1.0.2016062300