In this post I’ll talk about a new exit (Installable Service) that can be used with an MQ 9.3 installation for recording queue manager object access requests. It can provide a level of reporting who is using what and when. I’ll show what it does, how it does it, and what the limitations are.
Introduction
Probably the quickest way to demonstrate what you can get from this service is to show some output (lightly reflowed for clarity):
{"action":"authenticate", "timeEpoch":1651652784,"timeString":"2022-05-04 09:26:24 BST", "queueManager":"OAMLOG", "identity":"admin","applicationName":"amqsput", "environment":"other","caller":"external", "cspAuthenticationType":"password", "cspUserId":"admin", "authenticationContext":"initialContext", "bindType":"sharedBinding", "applicationPid":2599105,"applicationTid":1, "connCorrel":"2599096.2599117"} {"action":"authorise", "timeEpoch":1651652784,"timeString":"2022-05-04 09:26:24 BST", "queueManager":"OAMLOG", "objectType":"qMgr","objectName":"OAMLOG", "identity":"admin", "authorityHex":"0x00000001","authorityString":["connect"], "connCorrel":"2599096.2599117"} {"action":"authorise", "timeEpoch":1651652784,"timeString":"2022-05-04 09:26:24 BST", "queueManager":"OAMLOG", "objectType":"queue","objectName":"DEV.QUEUE.0", "identity":"admin", "authorityHex":"0x00000008","authorityString":["put"], "connCorrel":"2599096.2599117"}
I can see that the user admin authenticated with a password, connected to the queue manager and opened the queue DEV.QUEUE.0
, expecting to PUT a message. The log is written as JSON records to simplify feeding it to analysis and reporting tools.
Using the Installable Service
This is another variation of the Installable Service module that I’ve written about before here and here. This one I’ve called oamok
as it is based around reporting successful calls to the standard MQ authorisation component, the OAM.
You can get the code from github:
$ git clone https://github.com/ibm-messaging/mq-exits $ cd mq-exits/instserv/oamok $ more README.md
This module uses a JSON library (rather than having to write my own formatter), so you might also need to install that component. You might also need to adjust the Makefile to point at the header files. On my systems, installing the JSON package is done with:
$ dnf install json-c json-c-devel
Then you can compile the code:
$ make -f Makefile.Linux
The build copies the compiled module to the default exits directory, and you need to edit the qm.ini
file to reference it. Add this stanza AFTER the regular OAM’s stanza (the one with amqzfu
in it):
ServiceComponent: Service=AuthorizationService Name=Auditing.Auth.Service Module=/var/mqm/exits64/oamok ComponentDataSize=0
The RUNME.sh
script also shows what you need to do: it calls the make process and will do some work with a queue manager called OAMLOG
which it assumes exists.
What does it do
The oamok
module hooks into the chain of authorisation services, expecting to be called after the normal OAM has done its job to check permissions. It only needs to implement a few functions from the Installable Service API. Unlike the the oamlog
module which records every call to every function, this one only needs to implement the actual authentication and authorisation pieces of the interface.
It logs the action only if the OAM permits the operation. The queue manager already reports rejections in the queue manager error log and by authorisation events so there’s no need for it here too (which is good, because the chain is ended by the failure so the reporting service doesn’t get called anyway).
Other OAM-related things that you might like to see include the explicit SETTING of authorities. But you can get those with command and configuration events and I don’t want this package to duplicate existing capabilities. Real queue manager events also have a lot more context available that an authorisation service does not see. So I’ve not implemented those functions in this service.
The logged information
You can see an example of the output at the top of this article. Within each record, it shows the key information about the call. For an authorisation request, what were the name and type of the object, along with what kind of access the application asked for. The requested authorities are given in both a hex format (the aggregated MQZAO_*
flags that you can see in cmqzc.h
) and in a converted text array.
The reported information is all that the OAM knows. In particular it does not see information such as the name of the channel associated with a client connection. You can tell from the environment
element when any authentication happened on behalf of a client, even though it doesn’t have the channel name. That element has the value mcaSvrConn
for client connections. If there is no authentication phase, then there is also no indication of a connection being from a client. It would be nice to include the application name for authorisation requests, because there might not have been authentication which does report it. But that too is not available. Some of that information is available to channel security exits, so you might be able to merge any information logged by such an exit into the data produced by this one.
Connection correlator
You can link all operations for a given connection by looking at the connCorrel
field. That’s not the application’s hConn
value, but a combination of a queue manager process and thread id. That value is unique for the lifetime of the connection, though the queue manager might reuse it after one application disconnects and another connects. You can spot where the break is, as a new connection may have an authenticate record and will definitely have an authorisation request which has the connect
flag.
The exit writes the output to a specific file – /var/mqm/audit/oamok.log. The code here uses locks to ensure there are no interleaved records. If environment variable AMQ_OAMAUDIT_MULTILINE
is set to any value when the queue manager is started, then the output gets printed across multiple lines. Otherwise each JSON record is a single line, which analytics tools tend to prefer.
Using logrotate
If you take no special action, the log file continues to grow. So you probably need to set up something like logrotate. I put a file in /etc/logrotate.d:
/var/mqm/audit/oamok.log { missingok daily create 0660 mqm mqm su mqm mqm minsize 1M rotate 3 copytruncate }
If you have SELinux enabled, then you may also need to permit logrotate to do its work in this non-default directory:
$ semanage fcontext -a -t var_log_t /var/mqm/audit $ restorecon -v /var/mqm/audit
Notes
- One important limitation is that this module only works on MQ 9.3 queue managers. The queue manager needed some tiny changes to enable a module to run after the regular OAM. Without those changes, this installable service never ran. This component can also only run on platforms where you can install and configure Installable Services (which rules out the MQ Appliance as one environment).
- Configuration of this module is a manual process. You can only do it after creating a queue manager.
- If the queue manager uses LDAP-based authorisations, then it does not report on the mapping to the full DN unless that is used as the
cspUserId
in an authentication operation. The derived shortname is what the queue manager passes, and we report later, for authorisation checking.
- Tests of this package used the regular OAM, and the
oamlog
module. If you use other authorisation services, they might not set flags suitably so that the chain to this component happens. In particular, I’ve seen some additional modules used specifically for authentication. When that check succeeds, the queue manager often then bypasses the rest of any configured chain for that operation. But since there’s very little use of other authorisation services, I don’t see this as a huge issue today.
- There’s a little bit of Windows-specific code in the module, but it is not complete. It needs more work to build and run it on that platform.
- Because this runs inside the queue manager processes, it has that level of operating system authority. So things like the output file do not need to be world-accessible; everything runs under the same id. Also, it can report on every application connecting – Java, .Net, C programs, whether local or client. All come through the same route without needing distinct configurations or different exits.
- There is no detailed documentation on how chaining authorisation services works for developers of these services! That was one of the reasons I wrote the original
oamlog
module. There are a huge number of comments in that exit’s source code to explain how different completion and reason code responses affect whether the queue manager calls subsequent services.
Possible enhancements
There are a number of things that might be interesting to add:
- Externalise the configuration such as the name of the output file and the multi or single-line output.
- Split the output file based on queue manager name. Though we already have the name as one of the fields in every record.
- Add an option to not record administrator authorisation requests (something like
if getruid() == identity
) as many checks for internal queue manager operations may not be interesting.
Since originally writing this exit, I’ve also thought of an alternative way it could be implemented that should be compatible with older versions of MQ. It might also possibly work with alternative authorisation service implementations . But it would likely mandate (rather then simply benefit from) some external configuration mechanism. It’s something I might return to in future, but it would still have similar restrictions in terms of reported data.
Summary
I know there is an existing RFE/Idea for the queue manager to provide auditing information about successful connections. If that shows up in the product, it would remove any requirement for this function. It would also not have anything like the same list of limitations.
But unless and until that happens, I hope people find this interesting and useful.
would also be great for MQonCloud and allow logging to a service
If “someone” (we know who you are) wanted to pick it up and merge it elsewhere like on the cloud container images, then I’m sure they know where to come! Especially if they have other auth services involved and need to discuss what was done in the qmgr to assist.
Would be nice to have the output as PCF “event” messages just like the output when the OAM says “no”.
Yes it would. But it’s not practical to call the MQI from the Installable Service environment. See https://marketaylor.synology.me/?p=763 where I tried. It would require much more invasive changes to the qmgr. Hence my comment about existing RFEs in this area, which would presumably result in real event messages.