In the previous example 10-idpw clients authenticate with userid and password.
In this example, the app1
client authenticates using its TLS certificate.
Open a terminal and login to the OpenShift cluster where you installed the CP4I MQ Operator.
If not already done, clone this repository and navigate to this directory:
git clone https://github.com/ibm-messaging/cp4i-mq-samples.git
cd cp4i-mq-samples/11-rest-tls
Delete the files and OpenShift resources created by this example:
./cleanup-qm11.sh
You can copy/paste the commands shown here, or run the script deploy-qm11-qmgr.sh.
Remember you must be logged in to your OpenShift cluster.
openssl req -newkey rsa:2048 -nodes -keyout app1.key -subj "/CN=app1" -x509 -days 3650 -out app1.crt
openssl pkcs12 -export -out app1.p12 -inkey app1.key -in app1.crt -password pass:password
This will be installed in the queue manager's container. It is used by the REST API server to authenticate the client.
keytool -importcert -file app1.crt -alias app1 -keystore trust.jks -storetype jks -storepass password -noprompt
oc create configmap example-11-app1-jks-configmap -n cp4i --from-file=trust.jks
cat > qm11-configmap.yaml << EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: example-11-qm11-configmap
data:
qm11.mqsc: |
DEFINE QLOCAL('Q1') REPLACE DEFPSIST(YES)
SET AUTHREC PRINCIPAL('app1') OBJTYPE(QMGR) AUTHADD(CONNECT,INQ)
SET AUTHREC PROFILE('Q1') PRINCIPAL('app1') OBJTYPE(QUEUE) AUTHADD(BROWSE,GET,INQ,PUT)
qm11.ini: |-
Service:
Name=AuthorizationService
EntryPoints=14
SecurityPolicy=UserExternal
EOF
#
cat qm11-configmap.yaml
oc apply -n cp4i -f qm11-configmap.yaml
cat > qm11-web-configmap.yaml << EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: example-11-qm11-web-configmap
namespace: cp4i
data:
mqwebuser.xml: |-
<?xml version="1.0" encoding="UTF-8"?>
<server>
<featureManager>
<feature>apiDiscovery-1.0</feature>
<feature>appSecurity-2.0</feature>
<feature>basicAuthenticationMQ-1.0</feature>
</featureManager>
<enterpriseApplication id="com.ibm.mq.console">
<application-bnd>
<security-role name="MQWebAdmin">
<group name="MQWebAdminGroup" realm="defaultRealm"/>
</security-role>
<security-role name="MQWebAdminRO">
<group name="MQWebAdminROGroup" realm="defaultRealm"/>
</security-role>
<security-role name="MQWebUser">
<special-subject type="ALL_AUTHENTICATED_USERS"/>
</security-role>
<security-role name="MFTWebAdmin">
<user name="mftadmin" realm="defaultRealm"/>
</security-role>
<security-role name="MFTWebAdminRO">
<user name="mftreader" realm="defaultRealm"/>
</security-role>
</application-bnd>
</enterpriseApplication>
<enterpriseApplication id="com.ibm.mq.rest">
<application-bnd>
<security-role name="MQWebAdmin">
<group name="MQWebAdminGroup" realm="defaultRealm"/>
</security-role>
<security-role name="MQWebAdminRO">
<user name="mqreader" realm="defaultRealm"/>
</security-role>
<security-role name="MQWebUser">
<special-subject type="ALL_AUTHENTICATED_USERS"/>
</security-role>
<security-role name="MFTWebAdmin">
<user name="mftadmin" realm="defaultRealm"/>
</security-role>
<security-role name="MFTWebAdminRO">
<user name="mftreader" realm="defaultRealm"/>
</security-role>
</application-bnd>
</enterpriseApplication>
<basicRegistry id="basic" realm="defaultRealm">
<user name="app1" password="{hash}ATAAAAAIGH/rX4J8t/JAAAAAIJyjgH3qpIZ115Lj1lWJ6ds7Pyw2T8ri5pfB+PFqPohV"/>
<user name="mqadmin" password="{hash}ATAAAAAIGH/rX4J8t/JAAAAAIJyjgH3qpIZ115Lj1lWJ6ds7Pyw2T8ri5pfB+PFqPohV"/>
<user name="mqreader" password="{hash}ATAAAAAIGH/rX4J8t/JAAAAAIJyjgH3qpIZ115Lj1lWJ6ds7Pyw2T8ri5pfB+PFqPohV"/>
<group name="MQWebAdminGroup">
<member name="mqadmin"/>
</group>
<group name="MQWebAdminROGroup">
<member name="mqreader"/>
</group>
</basicRegistry>
<variable name="httpHost" value="*"/>
<keyStore id="defaultKeyStore" location="key.jks" type="JKS" password="{aes}AKrGXpGH6tiYd/ZMMwL3T5ERy39DrTTUYHVyx7CIwI2q"/>
<keyStore id="defaultTrustStore" location="trust.jks" type="JKS" password="{aes}AKrGXpGH6tiYd/ZMMwL3T5ERy39DrTTUYHVyx7CIwI2q"/>
<ssl id="thisSSLConfig" clientAuthenticationSupported="true" keyStoreRef="defaultKeyStore" serverKeyAlias="default" trustStoreRef="defaultTrustStore" sslProtocol="TLSv1.2"/>
<sslDefault sslRef="thisSSLConfig"/>
<variable name="managementMode" value="externallyprovisioned"/>
</server>
EOF
As in the previous example, this is based on basic_registry.xml
, with changes necessary to enable TLS authentication.
These lines from basic_registry.xml
are uncommented:
<keyStore id="defaultKeyStore" location="key.jks" type="JKS" password="{aes}AKrGXpGH6tiYd/ZMMwL3T5ERy39DrTTUYHVyx7CIwI2q"/>
<keyStore id="defaultTrustStore" location="trust.jks" type="JKS" password="{aes}AKrGXpGH6tiYd/ZMMwL3T5ERy39DrTTUYHVyx7CIwI2q"/>
<ssl id="thisSSLConfig" clientAuthenticationSupported="true" keyStoreRef="defaultKeyStore" serverKeyAlias="default" trustStoreRef="defaultTrustStore" sslProtocol="TLSv1.2"/>
<sslDefault sslRef="thisSSLConfig"/>
The default password for the trust and key stores is password
, and has been encoded using the securityUtility
command (for details, see 10-rest-idpw).
oc apply -f qm11-web-configmap.yaml
cat > qm11-svc-route.yaml << EOF
kind: Service
apiVersion: v1
metadata:
name: example-11-qm11-rest-svc
spec:
ports:
- name: qmgr
protocol: TCP
port: 9443
targetPort: 9443
selector:
app.kubernetes.io/component: integration
app.kubernetes.io/instance: qm11
app.kubernetes.io/name: ibm-mq
type: ClusterIP
sessionAffinity: None
---
apiVersion: route.openshift.io/v1
kind: Route
metadata:
name: example-11-qm11-rest-route
spec:
to:
kind: Service
name: example-11-qm11-rest-svc
port:
targetPort: 9443
tls:
termination: passthrough
wildcardPolicy: None
EOF
#
cat qm11-svc-route.yaml
oc apply -f qm11-svc-route.yaml
cat > qm11-qmgr.yaml << EOF
apiVersion: mq.ibm.com/v1beta1
kind: QueueManager
metadata:
name: qm11
spec:
license:
accept: true
license: L-RJON-CD3JKX
use: NonProduction
queueManager:
name: QM11
ini:
- configMap:
name: example-11-qm11-configmap
items:
- qm11.ini
mqsc:
- configMap:
name: example-11-qm11-configmap
items:
- qm11.mqsc
storage:
queueManager:
type: ephemeral
version: 9.3.0.0-r2
template:
pod:
containers:
- env:
- name: MQ_ENABLE_EMBEDDED_WEB_SERVER
value: 'true'
ports:
- containerPort: 9443
protocol: TCP
volumeMounts:
- name: mqwebuser
readOnly: true
mountPath: "/etc/mqm/web/installations/Installation1/servers/mqweb/mqwebuser.xml"
subPath: mqwebuser.xml
- name: trustjks
readOnly: true
mountPath: "/etc/mqm/web/installations/Installation1/servers/mqweb/resources/security/trust.jks"
subPath: trust.jks
name: qmgr
volumes:
- name: mqwebuser
configMap:
name: example-11-qm11-web-configmap
items:
- key: mqwebuser.xml
path: mqwebuser.xml
defaultMode: 420
- name: trustjks
configMap:
name: example-11-app1-jks-configmap
items:
- key: trust.jks
path: trust.jks
defaultMode: 420
web:
enabled: false
EOF
#
cat qm11-qmgr.yaml
oc apply -n cp4i -f qm11-qmgr.yaml
We will perform the following tests:
-
Access the MQ Console in a browser.
-
Access the Swagger MQ REST API Explorer in a browser.
-
Basic admin (similar to the
dspmq
command). -
Put, browse and get messages.
You can copy/paste the commands shown below to a command line, or use these scripts:
- open-qm11-console.sh to open the MQ Console for this queue manager (login with
mqadmin
andpassw0rd
). Note: the script is written for Mac; it must be changed for Linux or Windows (details below). - open-qm11-api-explorer.sh to open the Swagger MQ REST API Explorer. Login with
mqadmin
andpassw0rd
to test administrative APIs, or withapp1
andpassw0rd
to test messaging APIs. Note: the script is written for Mac; it must be changed for Linux or Windows (details below). - run-qm11-rest-dspmq.sh to display the queue manager.
- run-qm11-rest-put.sh to put two test messages to the queue
Q1
. - run-qm11-rest-browse.sh to browse a message (read it but leave it on the queue).
- run-qm11-rest-get.sh to get a message (read it and remove it from the queue).
oc get qmgr -n cp4i qm11
Run dspmqweb
on the container:
oc exec qm11-ibm-mq-0 -- dspmqweb
You may see this for the first 1-2 minutes after the queue manager started:
MQWB1124I: Server 'mqweb' is running.
MQWB1123E: The status of the mqweb server applications cannot be determined.
A request was made to read the status of the deployed mqweb server applications, however the data appears corrupt. This may indicate that there is already an mqweb server started on this system, probably related to another IBM MQ instance.
Check the startup logs for the mqweb server, looking in particular for conflicting usage of network ports. Ensure that if you have multiple mqweb servers on a system, they are configured to use distinct network ports. Restart the mqweb server and ensure it started correctly. If the problem persists, seek assistance from IBM support.
command terminated with exit code 1
Try again until you see:
MQWB1124I: Server 'mqweb' is running.
URLS:
https://qm11-ibm-mq-0.qm.cp4i.svc.cluster.local:9443/ibmmq/console/
https://qm11-ibm-mq-0.qm.cp4i.svc.cluster.local:9443/ibmmq/rest/
rest_hostname=`oc get route -n cp4i example-11-qm11-rest-route -o jsonpath="{.spec.host}"`
echo $rest_hostname
Test (optional):
ping -c 3 $rest_hostname
The MQ Console URL is https://$rest_hostname/ibmmq/console
.
On a Mac:
open https://$rest_hostname/ibmmq/console
On Windows:
start https://$rest_hostname/ibmmq/console
On Linux:
xdg-open https://$rest_hostname/ibmmq/console
The browser will complain about an untrusted certificate; accept it.
Note: Chrome will display "Your connection is not private" and refuse to accept the MQ Console's self-signed certificate.** To accept the certificate and open the Console, type 'thisisunsafe'.
You'll be presented with the login screen. Login with mqadmin
and passw0rd
.
The MQ API Explorer URL is https://$rest_hostname/ibm/api/explorer
.
On a Mac:
open https://$rest_hostname/ibm/api/explorer
On Windows:
start https://$rest_hostname/ibm/api/explorer
On Linux:
xdg-open https://$rest_hostname/ibm/api/explorer
You'll be presented with a login prompt:
-
To try the adminstrative REST API (
.../admin/...
URLs), login withmqadmin
andpassw0rd
. -
To try the messaging REST API (
.../messaging/...
URLs), login withapp1
andpassw0rd
.
To display the running queue manager (this is similar to the dspmq
command):
curl -k https://$rest_hostname/ibmmq/rest/v2/admin/qmgr -u mqadmin:passw0rd
You should see:
{"qmgr": [{
"name": "QM11",
"state": "running"
}]}
On all REST API calls, you have to authenticate (with useris and password) using a basic HTTP header. The curl
command converts -u userid:password
to the appropriate header.
Note: the following REST API calls require that the HTTP header "ibm-mq-rest-csrf-token"
be present. It can have any value. We are using "ibm-mq-rest-csrf-token: blank"
, but any other value will also work (for example, "ibm-mq-rest-csrf-token: xx"
).
Put a test message:
curl -k -i https://$rest_hostname/ibmmq/rest/v2/messaging/qmgr/QM11/queue/Q1/message -H "Content-Type: text/plain;charset=utf-8" --cert app1.p12:password --cert-type p12 -H "ibm-mq-rest-csrf-token: blank" --data 'Test message 1 - put using MQ REST API'
You should see:
HTTP/1.1 201 Created
X-XSS-Protection: 1;mode=block
X-Content-Type-Options: nosniff
Content-Security-Policy: default-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; connect-src 'self'; img-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self'
X-Frame-Options: DENY
Cache-Control: no-cache, no-store, must-revalidate
Content-Language: en-US
Content-Length: 0
Content-Type: text/plain; charset=utf-8
ibm-mq-md-messageId: 414d5120514d31312020202020202020eaa2346202650040
Set-Cookie: LtpaToken2_...; Path=/; Secure; HttpOnly; SameSite=Strict
Date: Fri, 18 Mar 2022 16:43:57 GMT
Expires: Thu, 01 Dec 1994 16:00:00 GMT
If you omit -i
, the command (if it works) does not return anything.
Put another message:
curl -k -i https://$rest_hostname/ibmmq/rest/v2/messaging/qmgr/QM11/queue/Q1/message -H "Content-Type: text/plain;charset=utf-8" --cert app1.p12:password --cert-type p12 -H "ibm-mq-rest-csrf-token: blank" --data 'Test message 2 - put using MQ REST API'
You should see:
HTTP/1.1 201 Created
X-XSS-Protection: 1;mode=block
X-Content-Type-Options: nosniff
Content-Security-Policy: default-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; connect-src 'self'; img-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self'
X-Frame-Options: DENY
Cache-Control: no-cache, no-store, must-revalidate
Content-Language: en-US
Content-Length: 0
Content-Type: text/plain; charset=utf-8
ibm-mq-md-messageId: 414d5120514d31312020202020202020eaa2346203650040
Set-Cookie: LtpaToken2_...; Path=/; Secure; HttpOnly; SameSite=Strict
Date: Fri, 18 Mar 2022 16:44:43 GMT
Expires: Thu, 01 Dec 1994 16:00:00 GMT
curl -k https://$rest_hostname/ibmmq/rest/v2/messaging/qmgr/QM11/queue/Q1/message --cert app1.p12:password --cert-type p12 -H "ibm-mq-rest-csrf-token: blank"
You should see:
...
Test message 1 - put using MQ REST API
curl -k https://$rest_hostname/ibmmq/rest/v2/messaging/qmgr/QM11/queue/Q1/message -X DELETE --cert app1.p12:password --cert-type p12 -H "ibm-mq-rest-csrf-token: blank" ; echo
You should see:
...
Test message 1 - put using MQ REST API
curl -k https://$rest_hostname/ibmmq/rest/v2/messaging/qmgr/QM11/queue/Q1/message --cert app1.p12:password --cert-type p12 -H "ibm-mq-rest-csrf-token: blank"
You should see:
...
Test message 2 - put using MQ REST API
curl -k https://$rest_hostname/ibmmq/rest/v2/messaging/qmgr/QM11/queue/Q1/message -X DELETE --cert app1.p12:password --cert-type p12 -H "ibm-mq-rest-csrf-token: blank" ; echo
You should see:
...
Test message 2 - put using MQ REST API
curl -k https://$rest_hostname/ibmmq/rest/v2/messaging/qmgr/QM11/queue/Q1/message -X DELETE --cert app1.p12:password --cert-type p12 -H "ibm-mq-rest-csrf-token: blank" ; echo
You should see a blank response.
This deletes the queue manager and other objects created on OpenShift, and the files created by this example:
./cleanup-qm11.sh
The next example shows how to obtain a token at login. The token is then used for authentication on all subsequent calls. See 12-rest-token.