Looking for help with Keycloak and RabbitMQ or trying to understand why and how to use them together? I’m happy to bring you the answers with my mini-series of articles on connecting these two open-source applications together! We’re going to start with a small overview. In the end of each article you’ll find a link to another part of the series.
Here we go!
1. Overview
Nowadays, when microservice architecture is very popular and one client uses multiple applications at once, companies use central service to provide common authentication and authorization. Its main purpose is to authorize access to different resources while giving credentials only once, alongside with further passwordless authentication. If we decide to implement such pattern, in the end we will have:
- Database which stores all users’ credentials and access rules to all our services
- Management by graphic interface
- Management by API
- Possibility to perform authentication and authorization using one of protocols
If our system contains many services, there is often needed to provide reliable and fast communication between them. Software called message brokers is often used as an alternative to most common way of exposing service’s API. It allows all connected services to exchange messages according to configured rules in secure way using specific protocol. From this article perspective important feature is that such software often has its authentication and authorization mechanisms built in.
Main goal of this article would be to show a way to connect two applications:
- Keycloak – popular open-source identity management and access management software
- RabbitMQ – message broker
We would like to use Keycloak server as authentication and authorization method instead of internal RabbitMQ auth backend.
2. RabbitMQ
Let’s assume, that we have RabbitMQ instance running at keycloak-rabbit:5672. To access it we will use default AMQP protocol.
Create file definitions.json. It will be loaded by our message broker at the start and populate instance with described objects, so it’s kind of start state for it. As for password_hash field, please refer to RabbitMQ documentation how to generate correct value. This will create user admin, vhost keycloak_test and allow access this user to defined vhost.
//================================================
definitions.json
//================================================
{
"rabbit_version" : "3.7.8",
"policies" : [],
"parameters" : [],
"topic_permissions" : [],
"global_parameters" : [
{
"name" : "cluster_name",
"value" : "keycloak-rabbit"
}
],
"users" : [
{"name":"admin","password_hash":"…","hashing_algorithm":"rabbit_password_hashing_sha256","tags":"administrator"}
],
"permissions" : [
{
"user": "admin",
"vhost": "keycloak_test",
"configure": ".*",
"write": ".*",
"read": ".*"
}
],
"vhosts" : [
{
"name" : "keycloak_test"
}
],
"bindings" : [],
"queues": [],
"exchanges" : []
}
//================================================
Edit main configuration file of message broker rabbitmq.conf. We should tell RabbitMQ to load our definitions and also configure rabbitmq-auth-backend-http plugin (https://github.com/rabbitmq/rabbitmq-auth-backend-http). It allows us to switch default internal authentication and authorization backend for one based on external http API calls. When external client will try to access RabbitMQ, broker will make request to selected endpoint and according to received response it will allow or deny access. Let’s say that our external service will be located at keycloak-proxy:3000. To not disable possibility to access instance with internal credentials we set new plugin as second auth backend.
//================================================
rabbitmq.conf
//================================================
loopback_users.guest = false
listeners.tcp.default = 5672
default_pass = …
default_user = admin
default_vhost = keycloak_test
management.load_definitions = /srv/definitions.json
auth_backends.1 = http
auth_backends.2 = internal
auth_http.http_method = post
auth_http.user_path = http://keycloak-proxy:3000/user
auth_http.vhost_path = http://keycloak-proxy:3000/vhost
auth_http.resource_path = http://keycloak-proxy:3000/resource
auth_http.topic_path = http://keycloak-proxy:3000/topic
//================================================
Although rabbitmq-auth-backend-http plugin is added to RabbitMQ installation by default, we must turn it on in the command line manually.
Rabbitmq-plugins enable –offline rabbitmq_auth_backend_http
At this point our RabbitMQ instance will try to authenticate and authorize each access to resource by sending requests to defined endpoints:
POST http://keycloak-proxy:3000/user
POST http://keycloak-proxy:3000/vhost
POST http://keycloak-proxy:3000/resource
POST http://keycloak-proxy:3000/topic
In response it expects plain string with status 200:
- allow
- deny
- allow <tag> - only in case of user endpoint, when selected user have tag attached.
Part two of the series
I'm already working on the next parts of the series so stay tuned - they're coming soon!