Connecting containerized IBM MQ to LDAP(S)

Ivan Slavka
11 min readJun 13, 2023

--

Table of Contents

  1. Introduction
  2. Preparation of LDAP
    2.1 Importing LDIF
    2.2 Creating a domain
    2.3 Create mqldapuser user
    2.4 Create mqadmins group
    2.5 Create mqexplorer user
  3. Clean MQ image build
  4. Create MQ server SSL certificate
  5. Configuration script files
    5.1 mq_qmgr_ldap.mqsc
    5.2 mq-ssl-setup.sh
    5.3 mq-auth-setup.sh
    5.4 icc-shift.sh
    5.5 Dockerfile
  6. Building Dockerfile and additional configuration
  7. Conclusion

1. Introduction

In order to connect IBM MQ to LDAP, we will require a ldap domain (medium-examples) this will be our organization, a user (mqldapuser) that IBM MQ will use to connect to LDAP, a user (mqexplorer) that we will be using for IBM MQ administration via MQ Explorer and an administration role (mqadmins) which will have all the necessary permission to perform MQ administration.

2. Preparation of LDAP

If you haven’t set up your LDAP yet, follow my guide on how to do it before continuing.

Once you have LDAP up and running, it’s time to return to Apache Directory Studio.

2.1 Importing LDIF

In case you are in hurry and don’t want to create domain nor users in Apache Directory Studio, you can use the LDIF file that I have exported. Just save the contents into regular file and use studio import function.

Update: I noticed that import will work only if you have already created a partition, even though it’s “kind of” specified in LDIF. So before importing you need to do at least step 1.

version: 1

dn: uid=mqldapuser,o=medium-examples
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
objectClass: uidObject
cn: mqldapuser
sn: mqldapuser
uid: mqldapuser
userPassword:: e1NTSEF9Z2k4a0lFUDU5S2c5a3NaT3dKNnliU3JYR05kQkx3d2VHcEVFSkE9P
Q==

dn: o=medium-examples
objectclass: domain
objectclass: extensibleObject
objectclass: top
dc: medium-examples
o: medium-examples

dn: cn=mqadmins,o=medium-examples
objectClass: groupOfNames
objectClass: top
cn: mqadmins
member: uid=mqexplorer,cn=mqadmins,o=medium-examples

dn: o=medium-examples
objectclass: domain
objectclass: extensibleObject
objectclass: top
dc: medium-examples
o: medium-examples

dn: uid=mqexplorer,cn=mqadmins,o=medium-examples
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
objectClass: uidObject
cn: mqexplorer
sn: mqexplorer
uid: mqexplorer
userPassword:: e1NTSEF9U2ZVd2dNYWxEdkFnR1ArTEsvcnMxUG5MRll2M2VoUnhLNmNFSHc9P
Q==

2.2 Creating a domain

First, let’s open LDAP configuration. Right click on LDAP connection to open context menu.

Click on partitions. Partitions contain a complete entry tree, also referred to as a DIT. Contents are disconnected from each other, meaning that changes to entries in partition A would never affect entries in partition B.

Next, click Add, and configure only ID and Suffix as it’s shown on the picture below. This will represent our organization domain called medium-examples. Finally, don’t forget to save your changes.

At this point, we have set up a new partition, but it’s not visible yet in DIT.

We need to restart our LDAP server each time a new partition is created. Go to your terminal which you have used to start LDAP server and execute the following command.

service apacheds-2.0.0.AM26-default restart

Don’t forget to close and open connection in your Apache Directory Studio. Once reconnected, you will see the new partition.

2.3 Create mqldapuser user

At this point, we are ready to configure users and a role. Right-click on our new partition (o=medium-examples), and then New -> New Entry…

This will open a new dialog window. Choose Create entry from scratch and then Next.

At Object Classes window, start typing “inet” into available object classes. This will filter the necessary class. Once filtered, add inetOrgPerson class by clicking Add button.

Do this for uidObject class as well. Other classes will be added automatically. Click Next.

At distinguished name dialog, choose uid for RDN, and assign mqldapuser value. Click Next.

At Attributes dialog, fill in mqldapuser value for cn and sn attributes. In addition, click New Attribute… button. We’ll assign password for this user.

At new attribute dialog, fill in userPassword as Attribute type and click Finish.

Password editor dialog will pop up. Fill in both, the password and confirm password. For the purpose of this tutorial, I’ll be using username as password. So in this case, the password will be mqldapuser. Click OK.

Confirm that you have userPassword attribute and click Finish.

2.4 Create mqadmins group

The process of creating a group is similar as with creating a user. A difference is that instead of choosing inetOrgPerson class, you choose groupOfNames class.

And at distinguished name, instead of using uid, we’ll be using cn with value mqadmins.

A DN Editor dialog will appear, click on Browse… and choose o=medium-examples. Click OK.

Confirm cn attribute has value mqadmins and click Finish.

This will put mqadmins group under our organization.

2.5 Create mqexplorer user

Right click on newly created group in order to access its context menu, then New -> New Entry… Follow the same process as with mqldapuser user. Only this time use mqexplorer as username and password.

Once created, you should see mqexplorer entry under mqadmins group.

Unfortunately, this doesn’t mean that our mqexplorer user belongs to that group. In order to assign mqexplorer to mqadmins group. Left-click on the mqadmins group and then click on New Attribute…

At attribute dialog, type member for Attribute type, and then click Finish.

This will again open the DN Editor, only this time when you click Browse, select our mqexplorer user under mqadmins group. Click OK.

Verify that mqexplorer is a member of mqadmins group. In addition, click on o=medium-examples member attribute and then Delete value. This was only a temporary placeholder.

Your mqadmins group attributes should look like this.

With this, we have finished configuring LDAP server part. Now it’s time to configure MQ to connect to LDAP, and use mqexplorer user for administration.

3. Clean MQ image build

My MQ docker image is based on clean MQ installation. If you don’t have it yet prepared, check out my previous article, to get it up and running.

4. Create MQ server SSL certificate

However, before we get to MQ configuration, first it’s necessary to prepare SSL certificates which we’ll use to connect to LDAP server. At the beginning of this article, there is a link to the guide on how to set up LDAP for SSL communication. The reason I’m referring you to that link is, the fact that in that guide we created a Certificate Authority certificate (CN=my-ca), which was then used to create a certificate for LDAP server. This same Certificate Authority certificate will be added here to MQ truststore, as well as to create certificate for our MQ server.

If you haven’t yet, create a folder with the name ssl, inside your working folder and copy your CAPrivate.key and CAPrivate.pem files into it. Then, inside that folder, execute the following commands in order to create MQ server certificate.

openssl genrsa -out MyMqPrivate.key 2048
openssl req -new -key MyMqPrivate.key -out MyMqRequest.csr -subj "/CN=my-mq-server"
openssl x509 -req -in MyMqRequest.csr -CA CAPrivate.pem -CAkey CAPrivate.key -CAcreateserial -out MyMqCertificate.crt -days 3650 -sha256 -passin LenovoLenovo123
openssl pkcs12 -export -out MyMqCertificate.pfx -inkey MyMqPrivate.key -in MyMqCertificate.crt

5. Configuration script files

In addition to SSL certificate, we’ll require several configuration scripts that will set up LDAP and SSL communication on our MQ server. Please create these files inside your working folder or download them from my github.

5.1 mq_qmgr_ldap.mqsc

This file provides LDAP configuration of MQ server. If you followed this guide to the letter, the only parameter you should change is CONNAME, as it holds IP address of LDAP server. Queue Manager kdb keystore is also configured by this script.

ALTER AUTHINFO('SYSTEM.DEFAULT.AUTHINFO.IDPWLDAP') +
AUTHTYPE(IDPWLDAP) +
CONNAME('172.18.0.2(10636)') +
LDAPUSER('uid=mqldapuser,o=medium-examples') +
LDAPPWD('mqldapuser') +
SHORTUSR('uid') +
ADOPTCTX(YES) +
USRFIELD('uid') +
BASEDNU('o=medium-examples') +
CHCKCLNT(REQUIRED) +
CHCKLOCL(NONE) +
CLASSUSR('inetOrgPerson') +
AUTHORMD(SEARCHGRP) +
BASEDNG('o=medium-examples') +
FINDGRP(member) +
GRPFIELD('cn') +
CLASSGRP('groupOfNames') +
SECCOMM(YES)

ALTER QMGR CONNAUTH('SYSTEM.DEFAULT.AUTHINFO.IDPWLDAP') SSLKEYR('/home/mqm/ssl/key')

5.2 mq-ssl-setup.sh

This script will generate MQ server kdb keystore, and populate it with CA certificate as well as MQ server certificate. It generates a kdb keystore password, which is then stored in kdb.password file. Lastly, it configures MQ server with LDAP by passing mq_qmgr_ldap.mqsc file into runmqsc.

#!/bin/bash
setup() {
local sslPath='/home/mqm/ssl'
local keyDbPath=${sslPath}/key.kdb
local keyDbPassword="$(tr -dc A-Za-z0-9 </dev/urandom | head -c 13 ; echo '')"
local caCertificatePath=$1
local mqCertificatePath=$2
local mqCertificatePassword=$3
local qmgrName=$4
local qmgrNameLowerCase="$(echo "$4" | tr '[:upper:]' '[:lower:]')"
local mqAdminsGroup=$5

su - mqm -c "mkdir -p ${sslPath}"
su - mqm -c "strmqm ${qmgrName}"

runmqckm -keydb -create -db ${keyDbPath} -pw ${keyDbPassword} -type cms -stash
runmqckm -cert -add -db ${keyDbPath} -file ${caCertificatePath} -pw ${keyDbPassword}
runmqckm -cert -import -file ${mqCertificatePath} -pw ${mqCertificatePassword} -type pkcs12 -target ${keyDbPath} -target_pw ${keyDbPassword} -target_type cms
runmqckm -cert -rename -db ${keyDbPath} -pw ${keyDbPassword} -label 1 -new_label ibmwebpsheremq${qmgrNameLowerCase}

chown mqm:mqm ${sslPath}/*

echo ${keyDbPassword} > /home/mqm/ssl/kdb.password
runmqsc ${qmgrName} < /home/mqm/mq_qmgr_ldap.mqsc
}

setup $1 $2 $3 $4 $5

5.3 mq-auth-setup.sh

Script responsible to set up necessary permissions for our mqadmins group. Inside this script, I’m restarting MQ server. Reason for this is execution of mq-ssl-setup.sh, which changes AUTHINFO configuration.

#!/bin/bash
setup() {
local qmgrName=$1
local mqAdminsGroup=$2

su - mqm -c "endmqm ${qmgrName}"
sleep 4
su - mqm -c "strmqm ${qmgrName}"

su - mqm -c "setmqaut -m ${qmgrName} -t qmgr -g ${mqAdminsGroup} +connect +inq +dsp +chg"
su - mqm -c ". /opt/mqm/samp/bin/amqauthg.sh ${qmgrName} ${mqAdminsGroup}"
}
setup $1 $2

5.4 icc-shift.sh

This environment variable is necessary on AMD processors in order to create and open MQ kdb keystore.

# can solve problem for creating keystore on AMD processors. https://github.com/ibm-messaging/mq-container/issues/462
export ICC_SHIFT=3

5.5 Dockerfile

Dockerfile is rather simple. It takes a previously created clean MQ image and extends it with SSL and LDAP configurations via configuration scripts.

FROM {your docker hub username}/{your docker hub repository}:my-mq

# can solve problem for creating keystore on AMD processors. https://github.com/ibm-messaging/mq-container/issues/462
ENV ICC_SHIFT=3

COPY --chmod=400 ./ssl/CAPrivate.pem /home/mqm/CAPrivate.pem
COPY --chmod=400 ./ssl/MyMqCertificate.pfx /home/mqm/MyMqCertificate.pfx
COPY --chmod=500 mq-ssl-setup.sh /home/mqm/mq-ssl-setup.sh
COPY --chmod=500 mq-auth-setup.sh /home/mqm/mq-auth-setup.sh
COPY --chmod=400 mq_qmgr_ldap.mqsc /home/mqm/mq_qmgr_ldap.mqsc
COPY --chmod=544 icc-shift.sh /etc/profile.d/icc-shift.sh

RUN ["/home/mqm/mq-ssl-setup.sh", "/home/mqm/CAPrivate.pem", "/home/mqm/MyMqCertificate.pfx", "{your pfx file password}", "QMgr01", "mqadmins"]

ENTRYPOINT ["/home/mqm/mq-start.sh", "QMgr01"]

6. Building Dockerfile and additional configuration

Finally, we are ready to build Dockerfile and run container. In order to do that, execute the following scripts inside your working folder. Two important things will happen. One your docker network will display IP address of your QM1 container which we’ll use in MQ Explorer and you will immediately end in container shell.

docker container stop QM1
docker container rm QM1
docker image rm {your dockerhub username}/{your dockerhub repository}:my-mq-with-ldaps
docker build --tag={your dockerhub username}/{your dockerhub repository}:my-mq-with-ldaps .
docker run -dt --name QM1 {your dockerhub username}/{your dockerhub repository}:my-mq-with-ldaps
docker network connect my-network QM1
docker network inspect my-network
docker exec -ti QM1 bash

It may be a good idea to pack these commands into a single executable shell script.

Once inside the container shell, there is one last configuration to be done. Unfortunately, I haven’t figured out why it doesn’t work through Dockerfile. Basically, we need to execute a script that will set up permission for our mqadmins LDAP group. Execute the following command inside container shell.

. /home/mqm/mq-auth-setup.sh QMgr01 mqadmins

Output:

(mq:9.0)root@5b5b4d4b76ae:/# . /home/mqm/mq-auth-setup.sh QMgr01 mqadmins
Quiesce request accepted. The queue manager will stop when all outstanding work
is complete.
IBM MQ queue manager 'QMgr01' starting.
The queue manager is associated with installation 'Installation1'.
6 log records accessed on queue manager 'QMgr01' during the log replay phase.
Log replay for queue manager 'QMgr01' complete.
Transaction manager state recovered for queue manager 'QMgr01'.
Plain text communication is enabled.
IBM MQ queue manager 'QMgr01' started using V9.2.5.0.
The setmqaut command completed successfully.
The setmqaut command completed successfully.
The setmqaut command completed successfully.
The setmqaut command completed successfully.
The setmqaut command completed successfully.
The setmqaut command completed successfully.
The setmqaut command completed successfully.
The setmqaut command completed successfully.
The setmqaut command completed successfully.
The setmqaut command completed successfully.
The setmqaut command completed successfully.
The setmqaut command completed successfully.
The setmqaut command completed successfully.
The setmqaut command completed successfully.
The setmqaut command completed successfully.
(mq:9.0)root@5b5b4d4b76ae:/#

Once this script has finished setting up permissions, use MQ Explorer to connect to the MQ server. Of course, you can now create additional users in similar fashion as mqexplorer in your LDAP under mqadmins group, and all of them will have access to Queue Manager.

7. Conclusion

Please be advised, what was set up in this tutorial is only SSL communication between LDAP and MQ server, however communication on administration channel SYSTEM.ADMIN.SVRCONN is not secured. This needs to be set up independently on each channel and currently is out of scope of this tutorial.

References

--

--