IBM-MQ:在客户端和队列管理器之间配置双向 TLS 认证

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

我正在尝试在客户端和 IBM-MQ 队列管理器之间设置 TLS 相互身份验证(使用 ibmcom/mq Docker image). The certificates are self-signed and created according to this article. As stated in the docs,应该可以将服务器的私钥和两个证书都烘焙到映像中。我的 Dockerfile 看起来像这样:

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/

可以在 运行 容器中找到这些文件:

/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

需要注意的一件事是,根据 docs,频道详细信息现在应显示以下条目:CERTLABL(mykey)。就我而言,它只是 CERTLABL( )。但是,我不确定这是否是这里的问题,没有客户端身份验证的服务器身份验证 似乎 可以正常工作(见下文)。

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)

在客户端,我创建了两个 Java 密钥库 (JKS),一个包含服务器的证书 (truststore),另一个包含客户端的密钥对。

我的连接尝试如下:

  1. 正在使用提供的 app 用户(无密码)和 DEV.APP.SVRCONN 通道连接到默认队列管理器 QM1。客户端应用程序是一个现有的工具,可以与现有的 MQ 基础设施完美配合,我只是交换了密钥库和连接细节。

客户端异常:com.ibm.mq.MQException: JMSCMQ0001: WebSphere MQ call failed with compcode '2' ('MQCC_FAILED') reason '2035' ('MQRC_NOT_AUTHORIZED').

MQ 日志:

AMQ5534E: User ID 'app' authentication failed
AMQ5542I: The failed authentication check was caused by the queue manager CONNAUTH CHCKCLNT(REQDADM) configuration.
  1. 通过 IBM MQ Explorer 使用提供的 admin 用户和 DEV.ADMIN.SVRCONN 通道进行连接(在这种情况下,我切换到 admin 因为 app 没有足够的权限与 MQ Explorer 一起使用,无论身份验证方法如何)。我检查了 "no password" 选项,因为我想使用客户端的证书进行身份验证。

MQ 资源管理器错误消息:

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 日志:

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. 与 2. 相同,但省略客户端的密钥库并提供密码。 有效。这里的想法是验证至少服务器的证书配置正确(另一方面,我不确定 MQ Explorer 是否首先强制检查服务器的证书与信任库)。

我错过了什么?

编辑:我的实际目标是对 app 用户和 DEV.APP.SVRCONN 频道使用相互身份验证。

CHANNEL 属性 CERTLABL

不需要设置此属性,除非您需要通过此 SVRCONN 提供与队列管理器上所有其他通道不同的证书。如果您没有此要求,请将 CHANNEL 属性 CERTLABL 留空并仅使用整个队列管理器范围的证书。这要么遵循名为 ibmWebSphereMQ<qm-name> 的证书的默认模式,要么使用您使用以下 MQSC 命令设置的证书标签:

ALTER QMGR CERTLABL(my-certificate-label)

连接认证(MQ内置密码校验)

在 V8 或更高版本创建的全新队列管理器将启用连接身份验证功能,这意味着队列管理器将检查您提供的任何密码,更重要的是在您的场景中,将要求任何特权用户 ID 必须供应一个。您在连接尝试 1 中报告的错误消息:

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

和连接尝试 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.

... 告诉您连接身份验证要求您的用户 ID(它认为是特权用户(即 mqm 组成员或类似成员))没有提供密码。

如果您不需要对任何远程连接的特权用户 ID 进行密码检查,那么您可以在队列管理器上使用以下命令将其关闭。

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

REFRESH SECURITY TYPE(CONNAUTH)

相互认证SSL/TLS

为了确保相互认证 SSL/TLS,您最终需要确保您的 CHANNEL 属性 SSLCAUTH 设置为 REQUIRED。但实现这一点的最简单方法是开始时将其设置为 OPTIONAL,然后到达客户端验证队列管理器证书的地步,然后让它发送自己的证书,最后设置 SSLCAUTH(REQUIRED) 以确保只有在客户端继续这样做时它才会起作用。

您需要确保在频道的两端都设置了 SSLCIPH。你没有在你的问题中提到这一点,但你引用的说明使用 SSLCIPH(ANY_TLS12) 所以我假设你已经做了同样的事情。

如果您成功建立连接但不确定客户端是否已将证书发送到队列管理器,请使用以下 MQSC 命令:-

DISPLAY CHSTATUS(DEV.ADMIN.SVRCONN) SSLPEER SSLCERTI

查看客户端发送的证书的Subject's DN和Issuer's DN。如果为空,则没有发送证书。