MQTT Gateway is a VerneMQ plugin with token based (OAuth2 Bearer Token) authentication. Authorization for publish/subscribe operations is based conventions and dynamic rules.
Name | Type | Default | Description |
---|---|---|---|
MQTT_CLIENT_ID | String | required | ${AGENT_LABEL}.${ACCOUNT_LABEL}.${AUDIENCE} |
MQTT_PASSWORD | String | required | JSON Web Token. Token is required if auhentification is enabled. |
MQTT_USERNAME | String | optional | The value is ignored |
To build and start playing with the application, execute following shell commands within different terminal tabs:
## To build container locally
docker build -t netology-group/mqtt-gateway -f docker/Dockerfile .
## Running a container with VerneMQ and the plugin
docker run -ti --rm \
-e APP_AUTHN_ENABLED=0 \
-e APP_AUTHZ_ENABLED=0 \
-e APP_DYNSUB_ENABLED=0 \
-e APP_STAT_ENABLED=0 \
-e APP_RATE_LIMIT_ENABLED=0 \
-e APP_ACCOUNT_ID=mqtt-gateway.svc.example.org \
-e APP_AGENT_LABEL=alpha \
-p 1883:1883 \
netology-group/mqtt-gateway
## Subscribing to messages
mosquitto_sub \
-i 'test-sub.john-doe.usr.example.net' \
-u 'v2::default' \
-t 'foo' | jq '.'
## Publishing a message
mosquitto_pub -V 5 \
-i 'test-pub.john-doe.usr.example.net' \
-t 'foo' \
-D connect user-property 'connection_version' 'v2' \
-D connect user-property 'connection_mode' 'default' \
-D publish user-property 'label' 'ping' \
-D publish user-property 'local_timestamp' "$(date +%s000)" \
-m '{}'
## Authnentication should be enabled in 'App.toml'
docker run -ti --rm \
-v "$(pwd)/App.toml.sample:/app/App.toml" \
-v "$(pwd)/data/keys/iam.public_key.pem.sample:/app/data/keys/iam.public_key.pem.sample" \
-v "$(pwd)/data/keys/svc.public_key.pem.sample:/app/data/keys/svc.public_key.pem.sample" \
-e APP_CONFIG='/app/App.toml' \
-p 1883:1883 \
netology-group/mqtt-gateway
## Subscribing to messages
ACCESS_TOKEN='eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJzdmMuZXhhbXBsZS5vcmciLCJpc3MiOiJzdmMuZXhhbXBsZS5vcmciLCJzdWIiOiJhcHAifQ.zevlp8zOKY12Wjm8GBpdF5vvbsMRYYEutJelODi_Fj0yRI8pHk2xTkVtM8Cl5KcxOtJtHIshgqsWoUxrTvrdvA' \
APP='app.svc.example.org' \
&& mosquitto_sub \
-i "test.${APP}" \
-P "${ACCESS_TOKEN}" \
-u 'v2::service' \
-t "agents/+/api/v1/out/${APP}" | jq '.'
## Publishing a message
ACCESS_TOKEN='eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ1c3IuZXhhbXBsZS5uZXQiLCJpc3MiOiJpYW0uc3ZjLmV4YW1wbGUubmV0Iiwic3ViIjoiam9obi1kb2UifQ.CjwC4qMT9nGt9oJALiGS6FtpZy3-nhX3L3HyM34Q1sL0P73-7X111A56UlbpQmuu5tGte9-Iu0iMJEYlD5XuGA' \
USER='john-doe.usr.example.net' \
APP='app.svc.example.org' \
&& mosquitto_pub -V 5 \
-i "test.${USER}" \
-P "${ACCESS_TOKEN}" \
-u 'ignore' \
-t "agents/test.${USER}/api/v1/out/${APP}" \
-D connect user-property 'connection_version' 'v2' \
-D connect user-property 'connection_mode' 'default' \
-D publish user-property 'label' 'ping' \
-D publish user-property 'local_timestamp' "$(date +%s000)" \
-m '{}'
## Running a container with VerneMQ and the plugin
docker run -ti --rm \
-v "$(pwd)/App.toml.sample:/app/App.toml" \
-e APP_CONFIG='/app/App.toml' \
-e APP_AUTHN_ENABLED=0 \
-e APP_AUTHZ_ENABLED=0 \
-e APP_DYNSUB_ENABLED=0 \
-e APP_RATE_LIMIT_ENABLED=0 \
-p 1883:1883 \
netology-group/mqtt-gateway
## Subscribing to messages
OBSERVER='devops.svc.example.org' \
BROKER='mqtt-gateway.svc.example.org' \
&& mosquitto_sub \
-i "test-1.${OBSERVER}" \
-t "apps/${BROKER}/api/v2/audiences/+/events" \
-P "${ACCESS_TOKEN}" \
-u 'v2::observer' \
| jq '.'
## Publishing a message
mosquitto_pub -V 5 \
-i 'test-pub.john-doe.usr.example.net' \
-t 'foo' \
-D connect user-property 'connection_version' 'v2' \
-D connect user-property 'connection_mode' 'default' \
-D publish user-property 'label' 'ping' \
-D publish user-property 'local_timestamp' "$(date +%s000)" \
-n
## Authorization should be enabled in 'App.toml'
docker run -ti --rm \
-v "$(pwd)/App.toml.sample:/app/App.toml" \
-e APP_CONFIG='/app/App.toml' \
-e APP_AUTHN_ENABLED=0 \
-e APP_STAT_ENABLED=0 \
-e APP_RATE_LIMIT_ENABLED=0 \
-e APP_ACCOUNT_ID=mqtt-gateway.svc.example.org \
-e APP_AGENT_LABEL=alpha \
-p 1883:1883 \
netology-group/mqtt-gateway
## Subscribing to the topic of user's incoming messages
USER='john.usr.example.net' \
APP='app.svc.example.org' \
&& mosquitto_sub \
-i "test.${USER}" \
-t "agents/test.${USER}/api/v1/in/${APP}" \
-u 'v2::default' \
| jq '.'
## Subscribing to the topic of app's incoming responses
OBSERVER='devops.svc.example.org' \
APP='app.svc.example.org' \
&& mosquitto_sub \
-i "test-1.${OBSERVER}" \
-t "agents/alpha.${APP}/api/v1/in/+" \
-D connect user-property 'connection_version' 'v2' \
-D connect user-property 'connection_mode' 'observer' \
| jq '.'
## Subscribing to the topic of app's incoming multicast events
OBSERVER='devops.svc.example.org' \
APP='app.svc.example.org' \
&& mosquitto_sub \
-i "test-2.${OBSERVER}" \
-t "agents/+/api/v1/out/${APP}" \
-D connect user-property 'connection_version' 'v2' \
-D connect user-property 'connection_mode' 'observer' \
| jq '.'
## Subscribing to the topic of broker's incoming multicast requests
OBSERVER='devops.svc.example.org' \
BROKER='mqtt-gateway.svc.example.org' \
&& mosquitto_sub \
-i "test-3.${OBSERVER}" \
-t "agents/+/api/v1/out/${BROKER}" \
-D connect user-property 'connection_version' 'v2' \
-D connect user-property 'connection_mode' 'observer' \
| jq '.'
## Creating a dynamic subscription
APP='app.svc.example.org' \
USER='john.usr.example.net' \
BROKER='mqtt-gateway.svc.example.org' \
&& mosquitto_pub -V 5 \
-i "test.${APP}" \
-t "agents/test.${APP}/api/v1/out/${BROKER}" \
-D connect user-property 'connection_version' 'v2' \
-D connect user-property 'connection_mode' 'service' \
-D publish user-property 'type' 'request' \
-D publish user-property 'method' 'subscription.create' \
-D publish response-topic "agents/alpha.${APP}/api/v1/in/${BROKER}" \
-D publish correlation-data 'foobar' \
-m "{\"object\": [\"rooms\", \"ROOM_ID\", \"events\"], \"subject\": \"test.${USER}\"}"
## Publishing an event
APP='app.svc.example.org' \
&& mosquitto_pub -V 5 \
-i "test.${APP}" \
-t "apps/${APP}/api/v1/rooms/ROOM_ID/events" \
-D connect user-property 'connection_version' 'v2' \
-D connect user-property 'connection_mode' 'service' \
-D publish user-property 'type' 'event' \
-D publish user-property 'label' 'room.create' \
-m '{}'
## Deleting the dynamic subscription
APP='app.svc.example.org' \
USER='john.usr.example.net' \
BROKER='mqtt-gateway.svc.example.org' \
&& mosquitto_pub -V 5 \
-i "test.${APP}" \
-t "agents/test.${APP}/api/v1/out/${BROKER}" \
-D connect user-property 'connection_version' 'v2' \
-D connect user-property 'connection_mode' 'service' \
-D publish user-property 'type' 'request' \
-D publish user-property 'method' 'subscription.delete' \
-D publish response-topic "agents/test.${USER}/api/v1/in/${APP}" \
-D publish correlation-data 'foobar' \
-m "{\"object\": [\"rooms\", \"ROOM_ID\", \"events\"], \"subject\": \"test.${USER}\"}"
%% We can verify that the subscription was created from the VerneMQ terminal
mqttgw_dynsub:list(<<"test.john.usr.example.net">>).
%% [{[<<"apps">>,<<"app.svc.example.org">>,<<"api">>,<<"v1">>,
%% <<"rooms">>,<<"ROOM_ID">>,<<"events">>],
%% #{app => <<"app.svc.example.org">>,
%% object => [<<"rooms">>,<<"ROOM_ID">>,<<"events">>],
%% version => <<"v1">>}}]
MQTT Gateway should be built using the same release version of Erlang/OTP as VerneMQ.
The source code is provided under the terms of the MIT license.