EMQ百萬級MQTT消息服務(ACL鑑權)

雖然EMQ已經搭建起來了,可是投入到業務使用中還面臨着一些問題,固然MQTT設計之初也考慮了這一點,好比不是任何一個客戶端都能連接到服務器和限制客戶端可以對topic操做的權限html

附上:mysql

喵了個咪的博客:w-blog.cn EMQ官方地址:http://emqtt.com/ EMQ中文文檔:http://emqtt.com/docs/v2/guide.htmlsql

1.ACL鑑權

先說實際場景,咱們須要監聽每一臺設備的連接和斷開事件等EMQ的系統行爲,這樣的事件固然不是任何一個鏈接到服務器的終端,這樣的限制就是ACL鑑權,官方也提供了默認的鑑權,在 /usr/local/emqttd/etc/acl.conf 下,默認值容許127.0.0.1的IP地址連接監聽系統主題編程

%% 容許'dashboard'用戶訂閱 '$SYS/#'
{allow, {user, "dashboard"}, subscribe, ["$SYS/#"]}.
%% 容許本機用戶發佈訂閱所有主題
{allow, {ipaddr, "127.0.0.1"}, pubsub, ["$SYS/#", "#"]}.
%% 拒絕用戶訂閱'$SYS#'與'#'主題
{deny, all, subscribe, ["$SYS/#", {eq, "#"}]}.

規則以下:vim

容許|拒絕  用戶|IP地址|ClientID  發佈|訂閱  主題列表

## 訪問控制規則採用 Erlang 元組格式,訪問控制模塊逐條匹配規則:
         ---------              ---------              ---------
Client -> | Rule1 | --nomatch--> | Rule2 | --nomatch--> | Rule3 | --> Default
          ---------              ---------              ---------
              |                      |                      |
            match                  match                  match
             \|/                    \|/                    \|/
        allow | deny           allow | deny           allow | deny

這個時候若是在外網連接EMQ定於以下主題,當客戶端連接的時候是沒法獲取消息的安全

$SYS/brokers/+/clients/+/connected
$SYS/brokers/+/clients/+/disconnected

可是隻須要修改acl配置文件以下而後重啓節點:(全部節點都須要修改)bash

> vim /usr/local/emqttd/etc/acl.conf
## 修改
# {allow, {ipaddr, "127.0.0.1"}, pubsub, ["$SYS/#", "#"]}.
{allow, {ipaddr, 你的外網IP}, pubsub, ["$SYS/#", "#"]}.

從新監聽當客戶端連接的時候就能夠得到以下信息服務器

{"clientid":"V10115125355235","username":"cline","ipaddress":"116.192.34.23","clean_sess":true,"protocol":4,"connack":0,"ts":1521689797}
{"clientid":"V10115125355235","username":"cline","reason":"normal","ts":1521689801}

2.MYSQL實時配置ACL

通常來講咱們不會使用外網IP來進行限制,有限會選擇用戶來進行限制行爲,官方提供以下方式來進行用戶和ACL驗證的存儲: (對應的配置方式能夠參考官網文檔)app

  • 配置文件和命令
  • LDAP
  • HTTP
  • MySQL
  • Postgre
  • Redis
  • MongoDB

筆者這裏採用你們常常用到的MYSQL做爲鑑權的數據來源,首先先關閉匿名認證(默認是開啓的誰都可以登陸)ide

vim /usr/local/emqttd/etc/emq.conf 

## Allow Anonymous authentication
mqtt.allow_anonymous = false

重啓服務器以後不論是誰都會被連接拒絕,咱們須要準備好用於檢查用戶和權限的mysql表:

CREATE TABLE `mqtt_user` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(100) DEFAULT NULL,
  `password` varchar(100) DEFAULT NULL,
  `salt` varchar(20) DEFAULT NULL,
  `is_superuser` tinyint(1) DEFAULT 0,
  `created` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `mqtt_username` (`username`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;


CREATE TABLE `mqtt_acl` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `allow` int(1) DEFAULT NULL COMMENT '0: deny, 1: allow',
  `ipaddr` varchar(60) DEFAULT NULL COMMENT 'IpAddress',
  `username` varchar(100) DEFAULT NULL COMMENT 'Username',
  `clientid` varchar(100) DEFAULT NULL COMMENT 'ClientId',
  `access` int(2) NOT NULL COMMENT '1: subscribe, 2: publish, 3: pubsub',
  `topic` varchar(100) NOT NULL DEFAULT '' COMMENT 'Topic Filter',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


-- 創建ACL默認訪問控制
INSERT INTO `mqtt_acl` (`id`, `allow`, `ipaddr`, `username`, `clientid`, `access`, `topic`)
VALUES
    (1,1,NULL,'$all',NULL,2,'#'),
    (2,0,NULL,'$all',NULL,1,'$SYS/#'),
    (3,0,NULL,'$all',NULL,1,'eq #'),
    (5,1,'127.0.0.1',NULL,NULL,2,'$SYS/#'),
    (6,1,'127.0.0.1',NULL,NULL,2,'#'),
    (7,1,NULL,'dashboard',NULL,1,'$SYS/#');

修改mysql配置文件

> vim /usr/local/emqttd/etc/plugins/emq_auth_mysql.conf

auth.mysql.server = xxxxxxxxx:3306
auth.mysql.username = root
auth.mysql.password = xxxxxxxx
auth.mysql.database = emq

創建用戶

# 用戶名 server 密碼 server 密碼默認是sha256
insert `mqtt_user`(`username`,`password`) values('server','b3eacd33433b31b5252351032c9b3e7a2e7aa7738d5decdf0dd6c62680853c06');
# 用戶名 cline 密碼 cline
insert `mqtt_user`(`username`,`password`) values('cline','84829dbd815311888f0e3d85822e9b07d14be89a480a3c09ee67353f0e806e3b');

能夠配置超級管理員(超級管理員會無視ACL規則對全部的topic都有訂閱和推送的權限)

update `mqtt_user` set `is_superuser`=1 where `id`=1;

注意:能夠註釋掉acl.conf的默認規則(也能夠結合使用)
注意:emq任何配置文件的變更都須要重啓服務(能夠在UI上直接修改配置不須要重啓)
注意:若是是在集羣下集羣中每個節點都須要執行命令

> emqttd stop
ok
> emqttd start
emqttd 2.3.5 is started successfully!
## 打開mysql鑑權
> emqttd_ctl plugins load emq_auth_mysql
Start apps: [emq_auth_mysql]
Plugin emq_auth_mysql loaded successfully.

在插件中就能夠看到對應的mysql鑑權插件已經打開了

3 總結

這個時候在連接的時候配置用戶名和密碼就能夠順利連接上了,而且ACL的配置能夠動態的變動誰能作什麼事情,在不一樣的業務需求場景下這樣的功能可讓程序作到更加安全又利於編程

注:筆者能力有限有說的不對的地方但願你們可以指出,也但願多多交流!

相關文章
相關標籤/搜索