'IBM-MQ: Configuring mutual TLS authentication between client and queue manager

I'm trying to set up TLS mutual authentication between client and IBM-MQ queue manager (using the ibmcom/mq Docker image). The certificates are self-signed and created according to this article. As stated in the docs, it should be possible to bake in the server's private key and both certificates into the image. My Dockerfile looks like this:

FROM ibmcom/mq

USER mqm
COPY --chown=mqm:mqm 20-config.mqsc /etc/mqm/ # creation of additional queues, no problems here
COPY --chown=mqm:mqm keys_mq1/key.key /etc/mqm/pki/keys/mykey/
COPY --chown=mqm:mqm keys_mq1/key.crt /etc/mqm/pki/keys/mykey/
COPY --chown=mqm:mqm keys_client/client.crt /etc/mqm/pki/trust/0/

The files can be found in the running container:

/etc/mqm/pki/keys/mykey
drwxr-xr-x 1 mqm mqm 4096 Feb 16 11:18 .
drwxr-xr-x 1 mqm mqm 4096 Feb 16 11:18 ..
-rwxr-xr-x 1 mqm mqm 1253 Feb 16 10:54 key.crt
-rwxr-xr-x 1 mqm mqm 1704 Feb 16 10:53 key.key

/etc/mqm/pki/trust/0
drwxr-xr-x 2 mqm mqm 4096 Feb 16 13:34 .
drwxr-xr-x 3 mqm mqm 4096 Feb 16 13:34 ..
-rwxr-xr-x 1 mqm mqm 1054 Feb 16 13:29 client.crt

One thing to notice is that, according to the docs, the channel details should now show the following entry: CERTLABL(mykey). In my case, it's just CERTLABL( ). However, I'm not sure if that's the problem here, authentication of the server without client authentication seems to be working (see below).

DISPLAY CHANNEL(DEV.APP.SVRCONN)
     1 : DISPLAY CHANNEL(DEV.APP.SVRCONN)
AMQ8414I: Display Channel details.
   CHANNEL(DEV.APP.SVRCONN)                CHLTYPE(SVRCONN)
   ALTDATE(2020-02-16)                     ALTTIME(13.34.47)
   CERTLABL( )                             COMPHDR(NONE)
   COMPMSG(NONE)                           DESCR( )
   DISCINT(0)                              HBINT(300)
   KAINT(AUTO)                             MAXINST(999999999)
   MAXINSTC(999999999)                     MAXMSGL(4194304)
   MCAUSER(app)                            MONCHL(QMGR)
   RCVDATA( )                              RCVEXIT( )
   SCYDATA( )                              SCYEXIT( )
   SENDDATA( )                             SENDEXIT( )
   SHARECNV(10)                            SSLCAUTH(OPTIONAL)
   SSLCIPH(ANY_TLS12)                      SSLPEER( )
   TRPTYPE(TCP)

On client side, I created two Java keystores (JKS), one with the server's certificate (truststore) and one with the client's keypair.

My connection attempts were as followed:

  1. Connecting to the default queue manager QM1 using the provided app user (no password) and DEV.APP.SVRCONN channel. The client application is an existing tool that perfectly works with the existing MQ infrastructure, I just exchanged the keystores and connection details.

Client exception: com.ibm.mq.MQException: JMSCMQ0001: WebSphere MQ call failed with compcode '2' ('MQCC_FAILED') reason '2035' ('MQRC_NOT_AUTHORIZED').

MQ log:

AMQ5534E: User ID 'app' authentication failed
AMQ5542I: The failed authentication check was caused by the queue manager CONNAUTH CHCKCLNT(REQDADM) configuration.
  1. Connecting using the provided admin user and DEV.ADMIN.SVRCONN channel via IBM MQ Explorer (in this scenario, I switched to admin because app has insufficient rights to be used with MQ Explorer, regardless of the authentication method). I checked the "no password" option, since I want to authenticate with the client's certificate.

MQ Explorer error message:

Access not permitted. You are not authorized to perform this operation. (AMQ4036)
  Explanation: The queue manager security mechanism has indicated that the userid associated with this request is not authorized to access the object.

MQ log:

AMQ5540E: Application 'MQ Explorer 8.0.0' did not supply a user ID and password
AMQ5541I: The failed authentication check was caused by the queue manager CONNAUTH CHCKCLNT(REQDADM) configuration.
AMQ9557E: Queue Manager User ID initialization failed for 'admin'.
  1. Same as 2., but omitting the client's keystore and providing the password instead. Works. The idea here was to verify that at least the server's certificate is configured correctly (on the other hand, I'm not sure if MQ Explorer is enforcing the check of the server's certificate against the truststore in the first place).

What am I missing?

edit: my actual goal is to use mutual authentication for the app user and DEV.APP.SVRCONN channel.



Solution 1:[1]

CHANNEL attribute CERTLABL

This attribute does not need to be set, unless you require to present a different certificate over this SVRCONN than all the other channels on the queue manager. If you do not have this requirement, leave CHANNEL attribute CERTLABL blank and just use the overall queue manager wide certificate. This is either following the default pattern of a certificate named ibmWebSphereMQ<qm-name> or uses the certificate label that you set using the following MQSC command:

ALTER QMGR CERTLABL(my-certificate-label)

Connection Authentication (MQ built-in Password checking)

A brand new queue manager created at V8 or above will have the Connection Authentication feature enabled, which means the queue manager will check any passwords you provide, and more importantly in your scenario, will demand that any privileged user id must supply one. The error message you report in connection attempt 1:

AMQ5542I: The failed authentication check was caused by the queue manager CONNAUTH CHCKCLNT(REQDADM) configuration.

and connection attempt 2/3:

AMQ5540E: Application 'MQ Explorer 8.0.0' did not supply a user ID and password
AMQ5541I: The failed authentication check was caused by the queue manager CONNAUTH CHCKCLNT(REQDADM) configuration.

... are telling you that connection authentication is mandating that your user id, which it considers privileged (i.e. member of mqm group or similar), has not supplied a password.

If you do not require password checking for any remotely connecting privileged user id, then you can turn this off with the following commands on the queue manager.

ALTER AUTHINFO(SYSTEM.DEFAULT.AUTHINFO.IDPWOS) AUTHTYPE(IDPWOS) CHCKCLNT(OPTIONAL)

REFRESH SECURITY TYPE(CONNAUTH)

Mutually Authenticated SSL/TLS

In order to ensure mutually authenticated SSL/TLS, you will eventually need to ensure that your CHANNEL attribute SSLCAUTH is set to REQUIRED. But the easiest way to achieve this is to start with it set to OPTIONAL, and get to the point where the client is authenticating the queue manager's certificate, and then get it sending it's own, and finally set SSLCAUTH(REQUIRED) to ensure that it will only work if the client continues to do so.

You will need to ensure that you have set SSLCIPH on both ends of the channel. You don't mention that in your question, but the instructions you reference use SSLCIPH(ANY_TLS12) so I assume you have done the same.

If you successfully make a connection and are not sure whether the client has sent a certificate to the queue manager, use the following MQSC command:-

DISPLAY CHSTATUS(DEV.ADMIN.SVRCONN) SSLPEER SSLCERTI

to see the Subject's DN and Issuer's DN of the certificate sent by the client. If blank, it did not sent a certificate.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Morag Hughson