This article explains how to configure HiveMQ. Enterprise Security Extension to use X509 certificates for authentication. For example, the Client certificates include a subject common name that is used for authentication and role-based permissions for authorization.
Pre-requisites
Created Key-store and trust-stores certificates with subject common name configured. You can always refer to our documentation to know how to generate these certificates.
Running setup of database realm (here we are using PostgreSQL)
\uD83D\uDCD8 Instructions
The first step is to configure
<tls-tcp-listener>
in your hivemqconfig.xml
. Please refer following example.<hivemq> <listeners> <tls-tcp-listener> <port>8883</port> <bind-address>0.0.0.0</bind-address> <tls> <keystore> <path>/path/to/hivemq.jks</path> <password><your passsword></password> <private-key-password><your passsword></private-key-password> </keystore> <truststore> <path>/path/to/hivemq-trust-store.jks</path> <password><your passsword></password> </truststore> <client-authentication-mode>REQUIRED</client-authentication-mode> </tls> </tls-tcp-listener> </listeners>
Next step, make sure you have the database setup ready with the users, roles and permissions data.
Make sure you have
users.username
matching the client’s certificate's common name in order to work authentication successfully. For authorization, roles and permissions are configured correctly.Please check our documentation for database schema and how to use a helper tool to insert data.
Now configure ESE configuration file, i.e
enterprise-security-extension.xml
First configure the realm with your database type, name, host, password, db-username and db-password. For more details about different realms please check our documentation. Please refer to the following example of Postgres
<realms> <!-- a postgresql db--> <sql-realm> <name>postgres-backend</name> <enabled>true</enabled> <configuration> <db-type>POSTGRES</db-type> <db-name>hivemq-db</db-name> <db-host>localhost</db-host> <db-port>5432</db-port> <db-username>postgres</db-username> <db-password>hivemq</db-password> </configuration> </sql-realm> </realms>
Configure
<pipelines>
in order to authenticate and authorize the client before the client connection is accepted. You can also add preprocessors to do some modifications or processing to inputs before authentication and authorization happens.In the current scenario will be using
<x509-preprocessor>
to process and extract subject-common-name and set the ESE variable authentication-key for authentication.<x509-preprocessor prefix="{{" postfix="}}"> <x509-extractions> <x509-extraction> <x509-field>subject-common-name</x509-field> <ese-variable>authentication-key</ese-variable> </x509-extraction> </x509-extractions> </x509-preprocessor>
you can also add a logging preprocessor to debug the state of ESE variables. Please remember to add a logger in your
logback.xml
to see these log messages.
Example to add <logging-preprocessor>:<logging-preprocessor> <message>x509 The content of the authentication-key ESE-Variable: ${authentication-key}</message> <level>debug</level> <name>demo.ese.logger</name> </logging-preprocessor>
Example to add logger in logback.xml:
<logger name="demo.ese.logger" level="debug"/>
With the help of plain-preprocessor, set the authentication-byte-secret ESE variable from mqtt-password.
<plain-preprocessor> <transformations> <transformation encoding="UTF8"> <from>mqtt-password</from> <to>authentication-byte-secret</to> </transformation> </transformations> </plain-preprocessor>
Once pipelines with the help of preprocessor are configured, the Next step is to configure authentication managers i.e
<sql-authentication-manager>
. An authentication manager is defined in a pipeline and handles the authentication processes of connecting MQTT clients by using the content of the authentication variables. Configure the realm name (this was set in step 3-a.)
Example:<sql-authentication-manager> <realm>postgres-backend</realm> </sql-authentication-manager>
In the ESE, authorization is done by authorization managers. An authorization manager is defined in a pipeline and handles the authorization processes of connecting MQTT clients by using the content of the authorization variables. Configure the realm name (this was set in step 3-a.), <use-authorization-key> and <use-authorization-role-key>. Here we are using role-based permissions hence set <use-authorization-role-key> to true and use-authorization-key to false;
Example:<sql-authorization-manager> <realm>postgres-backend</realm> <use-authorization-key>false</use-authorization-key> <use-authorization-role-key>true</use-authorization-role-key> </sql-authorization-manager>
after configuring all the above steps final
enterprise-security-extension.xml
will be as<?xml version="1.0" encoding="UTF-8" ?> <enterprise-security-extension xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="enterprise-security-extension.xsd" version="1"> <realms> <!-- a postgresql db--> <sql-realm> <name>postgres-backend</name> <enabled>true</enabled> <configuration> <db-type>POSTGRES</db-type> <db-name>hivemq-db</db-name> <db-host>localhost</db-host> <db-port>5432</db-port> <db-username>postgres</db-username> <db-password>hivemq</db-password> </configuration> </sql-realm> </realms> <pipelines> <!-- secure access to the mqtt broker --> <listener-pipeline listener="ALL"> <!-- authenticate over a sql db --> <authentication-preprocessors> <x509-preprocessor prefix="{{" postfix="}}"> <x509-extractions> <x509-extraction> <x509-field>subject-common-name</x509-field> <ese-variable>authentication-key</ese-variable> </x509-extraction> </x509-extractions> </x509-preprocessor> <logging-preprocessor> <message>x509 The content of the authentication-key ESE-Variable: ${authentication-key}</message> <level>debug</level> <name>demo.ese.logger</name> </logging-preprocessor> <plain-preprocessor> <transformations> <transformation encoding="UTF8"> <from>mqtt-password</from> <to>authentication-byte-secret</to> </transformation> </transformations> </plain-preprocessor> <logging-preprocessor> <message>username The content of the authentication-key ESE-Variable: ${authentication-key} and passowrd: ${authentication-byte-secret}</message> <level>debug</level> <name>demo.ese.logger</name> </logging-preprocessor> </authentication-preprocessors> <sql-authentication-manager> <realm>postgres-backend</realm> </sql-authentication-manager> <!-- authorize over a sql db --> <sql-authorization-manager> <realm>postgres-backend</realm> <use-authorization-key>false</use-authorization-key> <use-authorization-role-key>true</use-authorization-role-key> </sql-authorization-manager> </listener-pipeline> <!-- secure access to the control center --> </pipelines> </enterprise-security-extension>
Run HiveMQ broker and look for the log messages which mention that HiveMq Broker and ESE is started successfully.
2022-12-14 15:34:21,020 INFO - Started HiveMQ in 14569ms ... 2022-12-14 15:34:59,346 INFO - Started HiveMQ Enterprise Security Extension successfully in 369ms.
You can quickly test your configurations with MQTT CLI.
Subscribe to the authorised topic:mqtt sub -p 8883 -t topic/# -pw <password> --cafile hivemq-server-cert.pem --cert mqtt-client-cert-sub1.pem --key mqtt-client-key-sub1.pem
Publish message to the authorised topic:
mqtt pub -p 8883 -m "test message" -t topic/test -pw <password> --cafile hivemq-server-cert.pem --cert mqtt-client-cert-pub1.pem --key mqtt-client-key-pub1.pem
You can also check
access.log
andhivemq.log
to see the log entries