这里写自定义目录标题
-
- 环境准备
-
- 关闭linuxse
- 打开防火墙端口
- 配置dnf
- 安装wget
- 安装tar
- 安装make
- 安装g++
- 安装openssl开发工具包
- 安装Mosquitto
-
- 下载编译
- 配置启动
- 设置开机启动
- 测试
- 安装mosquitto-go-auth
-
- 安装go环境
- 下载编译mosquitto-go-auth
- 准备MySQL
-
- 安装启动MySQL
- 修改root密码
- 准备数据库和表结构
- 准备测试账号
- 配置运行mosquitto-go-auth
-
- 关闭匿名访问
- 创建日志目录和配置日志设置
- 配置mosquitto-go-auth插件相关设置
- 测试一下
- 配置TLS
-
- 机器准备和命名
- 使用openssl生成相关证书
-
- 准备/etc/mosquitto/certs目录
- Certificate Authority
- Server
- Client
- TLS单向认证
-
- 修改配置
- 测试
- TLS单向认证下的多个broker桥接
- TLS双向认证
-
- 修改配置
- 测试
- TLS双向认证下的多个broker桥接
环境准备
查看系统版本
cat /etc/redhat-release
CentOS Linux release 8.2.2004 (Core)
关闭linuxse
临时关闭:
setenforce 0
永久关闭:修改/etc/selinux/config 文件将SELINUX=enforcing改为SELINUX=disabled,然后重启
查看状态:
getenforce
打开防火墙端口
firewall-cmd --zone=public --add-port=1883/tcp --permanent
firewall-cmd --zone=public --add-port=8883/tcp --permanent
firewall-cmd --reload
配置dnf
vi /etc/dnf/dnf.conf
再最下方加入一行
fastestmirror=True
保存退出之后执行:
dnf clean all
dnf makecache
安装wget
dnf install wget -y
安装tar
dnf install tar -y
安装make
dnf install make -y
安装g++
dnf install gcc-c++ -y
安装openssl开发工具包
dnf install openssl-devel -y
安装Mosquitto
下载编译
wget https://mosquitto.org/files/source/mosquitto-1.6.10.tar.gz
tar -zxvf mosquitto-1.6.10.tar.gz
cd mosquitto-1.6.10
make
make install
配置启动
cd /etc/mosquitto/
mv mosquitto.conf.example mosquitto.conf
mosquitto -c /etc/mosquitto/mosquitto.conf
出现如下错误:
1596531761: Error: Invalid user 'mosquitto'.
为解决此问题,需要给系统创建mosquitto用户和组:
groupadd mosquitto
useradd -g mosquitto mosquitto
chown -R mosquitto:mosquitto /etc/mosquitto/
创建完之后再次尝试启动,应该就能成功启动了。
如果要后台运行,则加入-d参数,完整命令如下:
mosquitto -c /etc/mosquitto/mosquitto.conf -d
-c参数是指定配置文件,-d参数是指定后台运行
设置开机启动
便携启动文件
vi /usr/lib/systemd/system/mosquittod.service
脚本内容如下
[Unit]
Description=Mosquitto 1.6.10 mqtt server
After=network.target
[Service]
Type=forking
User=mosquitto
Group=mosquitto
ExecStart=/usr/local/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf -d
# Give a reasonable amount of time for the server to start up/shut down
TimeoutSec=300
# Place temp files in a secure directory, not /tmp
PrivateTmp=true
[Install]
WantedBy=multi-user.target
修改文件权限:
chmod 644 /usr/lib/systemd/system/mosquittod.service
使配置生效:
systemctl daemon-reload
设为开机启动:
systemctl enable mosquittod.service
测试
订阅一个主题,如test:
出现如下错误:
mosquitto_sub: error while loading shared libraries: libmosquitto.so.1: cannot open shared object file: No such file or directory
解决办法,是创建一个符号链接:
ln -s /usr/local/lib/libmosquitto.so.1 /usr/lib/libmosquitto.so.1
ldconfig
然后再次执行
mosquitto_sub -t test
订阅test主题,应该就可以成功了。
再开一个终端窗口给test主题发布一条消息:
订阅的窗口将打印
hello
安装mosquitto-go-auth
安装go环境
dnf install golang -y
下载编译mosquitto-go-auth
wget https://github.com/iegomez/mosquitto-go-auth/archive/1.0.0.tar.gz -O ./mosquitto-go-auth-1.0.0.tar.gz
tar -zxvf mosquitto-go-auth-1.0.0.tar.gz
cd mosquitto-go-auth-1.0.0
export CGO_CFLAGS="-I/usr/local/include -fPIC"
export CGO_LDFLAGS="-shared"
make
make的时候可能出现如下这样的一个错:
go: github.com/brocaar/[email protected]+incompatible: Get https://proxy.golang.org/github.com/brocaar/lora-app-server/@v/v2.5.1+incompatible.mod: dial tcp 34.64.4.81:443: i/o timeout
make: *** [Makefile:2: all] Error 1
解决办法是设置代理
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct
make
准备MySQL
安装启动MySQL
wget https://dev.mysql.com/get/mysql80-community-release-el8-1.noarch.rpm
yum install mysql80-community-release-el8-1.noarch.rpm
yum install mysql-server
service mysqld start
修改root密码
登录MySQL并修改密码,刚刚安装好的是没有密码的,直接回车即可登录进去
mysql -uroot -p
ALTER USER 'root'@'localhost' IDENTIFIED BY '1234';
准备数据库和表结构
CREATE SCHEMA `mosquitto` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin ;
use mosquitto;
create table mosquitto_user(
id mediumint not null auto_increment,
username varchar(100) not null,
password_hash varchar(200) not null,
is_admin boolean not null,
primary key(id)
);
create table mosquitto_acl(
id mediumint not null auto_increment,
mosquitto_user_id mediumint not null,
topic varchar(200) not null,
rw int not null COMMENT '1:readonly, 2:writeonly ,3:readwrite ,4:subscribe ',
primary key(id),
foreign key(mosquitto_user_id) references mosquitto_user(id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
insert into mosquitto_user(username, password_hash,is_admin) values('admin','',1);
准备测试账号
使用mosquitto-go-auth编译出来的pw命令生成pbkdf2的密码,
cd ~/mosquitto-go-auth-1.0.0
./pw -l 64 -p 123456
生成的如下的字符串可以作为mosquitto用户的密码
PBKDF2$sha512$100000$ooBf5L/ANImpDrhOCiAMpg==$BzO004Rc5bT44/E/PMQluJ7Bobf7ffixw/Z3b9iB55No6c/QGy4VgQMBzsLOU9XTJx93qxd/1nKhdCa+HJm1Tw==
登录MySQL,创建测试用户
mysql -uroot -p1234
-- 插入一个管理员账号和两个普通账号
insert into mosquitto_user(username, password_hash,is_admin) values('admin','PBKDF2$sha512$100000$ooBf5L/ANImpDrhOCiAMpg==$BzO004Rc5bT44/E/PMQluJ7Bobf7ffixw/Z3b9iB55No6c/QGy4VgQMBzsLOU9XTJx93qxd/1nKhdCa+HJm1Tw==',1),('yuanpan1','PBKDF2$sha512$100000$ooBf5L/ANImpDrhOCiAMpg==$BzO004Rc5bT44/E/PMQluJ7Bobf7ffixw/Z3b9iB55No6c/QGy4VgQMBzsLOU9XTJx93qxd/1nKhdCa+HJm1Tw==',0),('yuanpan2','PBKDF2$sha512$100000$ooBf5L/ANImpDrhOCiAMpg==$BzO004Rc5bT44/E/PMQluJ7Bobf7ffixw/Z3b9iB55No6c/QGy4VgQMBzsLOU9XTJx93qxd/1nKhdCa+HJm1Tw==',0);
-- 给两个普通账号插入权限控制数据,管理员账号不需要插入
insert into mosquitto_acl(mosquitto_user_id, topic, rw) values(2,'/test/#',1),(2,'/test/#',2),(2,'/test/#',3),(2,'/test/#',4),(3,'/test/#',1),(3,'/test/#',2),(3,'/test/#',3),(3,'/test/#',4);
配置运行mosquitto-go-auth
关闭匿名访问
vi /etc/mosquitto/mosquitto.conf
# 将如下配置设置为false
allow_anonymous false
创建日志目录和配置日志设置
cd /var/log
mkdir mosquitto
chown -R mosquitto:mosquitto /var/log/mosquitto/
vi /etc/mosquitto/mosquitto.conf
# 将log_dest,log_type,connection_messages做如下设置
log_dest file /var/log/mosquitto/mosquitto.log
log_type all
connection_messages true
配置mosquitto-go-auth插件相关设置
cd /etc/mosquitto/
vi mosquitto.conf
# 到文件末尾配置
include_dir /etc/mosquitto/conf.d
mkdir plugins
cd plugins
cp ~/mosquitto-go-auth-1.0.0/go-auth.so .
cd ..
mkdir conf.d
vi mosquitto-go-auth.conf
# 写入如下数据到mosquitto-go-auth.conf文件
auth_plugin /etc/mosquitto/plugins/go-auth.so
auth_opt_backends mysql
# Cache
#auth_opt_cache true
#auth_opt_cache_type redis
#auth_opt_cache_reset true
#auth_opt_auth_cache_seconds 30
#auth_opt_acl_cache_seconds 30
#auth_opt_cache_host localhost
#auth_opt_cache_port 6379
#auth_opt_cache_password pwd
#auth_opt_cache_db 3
#Logging
auth_opt_log_level debug
auth_opt_log_dest file
auth_opt_log_file /var/log/mosquitto/mosquitto-go-auth.log
# Hashing
auth_opt_hasher pbkdf2
auth_opt_hasher_salt_size 16 # salt bytes length
auth_opt_hasher_iterations 100000 # number of iterations
auth_opt_hasher_keylen 64 # key length
auth_opt_hasher_algorithm sha512 # hashing algorithm, either sha512 (default) or sha256
auth_opt_hasher_salt_encoding base64 # salt encoding, either base64 (default) or utf-8
# MySQL
auth_opt_mysql_host localhost
auth_opt_mysql_port 3306
auth_opt_mysql_dbname mosquitto
auth_opt_mysql_user root
auth_opt_mysql_password 1234
auth_opt_mysql_allow_native_passwords true
auth_opt_mysql_userquery SELECT password_hash FROM mosquitto_user WHERE username = ? limit 1
auth_opt_mysql_superquery SELECT COUNT(1) FROM mosquitto_user WHERE username = ? AND is_admin = 1 LIMIT 1
auth_opt_mysql_aclquery SELECT topic FROM mosquitto_acl acl inner join mosquitto_user user on acl.mosquitto_user_id = user.id WHERE user.username = ? AND acl.rw = ?
以上配置完之后,运行下mosquitto试试
mosquitto -c /etc/mosquitto/mosquitto.conf
测试一下
订阅/test/1主题
mosquitto_sub -t /test/1 -u yuanpan1 -P 123456
给/test/1主题发送一个hello消息
mosquitto_pub -t /test/1 -m "hello" -u yuanpan2 -P 123456
配置TLS
机器准备和命名
这部分的内容将和mosquitto的桥接一起来写,准备3台虚拟机,配置其 /etc/hosts文件,来为虚拟机命名
192.168.20.200 server.mosquitto1.vm client.mosquitto1.vm ca.mosquitto1.vm
192.168.20.201 server.mosquitto2.vm client.mosquitto2.vm
192.168.20.202 server.mosquitto3.vm client.mosquitto3.vm
使用openssl生成相关证书
准备/etc/mosquitto/certs目录
在第一台虚拟机
server.mosquitto1.vm
上执行如下:
cd /etc/mosquitto/
mkdir certs
cd certs
Certificate Authority
Generate a certificate authority certificate and key.
openssl req -new -x509 -days 3650 -extensions v3_ca -keyout ca.key -out ca.crt
先输入两遍密码,剩下的可以参考如下:
Country Name : CN
State or Province Name : HuBei
Locality Name (eg, city) : WuHan
Organization Name (eg, company) : Test
Organizational Unit Name (eg, section) : CA
Common Name (eg, your name or your server’s hostname) : ca.mosquitto1.vm
Email Address : [email protected]
这里注意,Common Name 是ca.mosquitto1.vm
Server
Generate a server key.
openssl genrsa -out server.key 2048
Generate a certificate signing request to send to the CA.
openssl req -out server.csr -key server.key -new
先输入两遍密码,剩下的可以参考如下:
Country Name : CN
State or Province Name : HuBei
Locality Name (eg, city) : WuHan
Organization Name (eg, company) : Test
Organizational Unit Name (eg, section) : Server
Common Name (eg, your name or your server’s hostname) : server.mosquitto1.vm
Email Address : [email protected]
这里注意,Common Name,在第一台机器,填server.mosquitto1.vm,在第二台机器填server.mosquitto2.vm,第三台机器填server.mosquitto3.vm
Send the CSR to the CA, or sign it with your CA key:
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 3650
将虚拟机的证书放到
/ect/mosquitto/certs/server.mosquitto1.vm
目录下
mkdir server.mosquitto1.vm
mv server.crt server.mosquitto1.vm/
mv server.csr server.mosquitto1.vm/
mv server.key server.mosquitto1.vm/
继续执行上面生成Server证书的步骤来生成server.mosquitto2.vm的Server证书,并放入到目录下;生成server.mosquitto3.vm的Server证书,并放入到
/ect/mosquitto/certs/server.mosquitto1.vm
目录下
/ect/mosquitto/certs/server.mosquitto3.vm
mkdir server.mosquitto2.vm
mv server.crt server.mosquitto2.vm/
mv server.csr server.mosquitto2.vm/
mv server.key server.mosquitto2.vm/
mkdir server.mosquitto3.vm
mv server.crt server.mosquitto3.vm/
mv server.csr server.mosquitto3.vm/
mv server.key server.mosquitto3.vm/
Client
Generate a client key.
openssl genrsa -out client.key 2048
Generate a certificate signing request to send to the CA.
openssl req -out client.csr -key client.key -new
Country Name : CN
State or Province Name : HuBei
Locality Name (eg, city) : WuHan
Organization Name (eg, company) : Test
Organizational Unit Name (eg, section) : Client
Common Name (eg, your name or your server’s hostname) : client.mosquitto1.vm
Email Address : [email protected]
这里注意,Common Name,在第一台机器,填client.mosquitto1.vm,在第二台机器填client.mosquitto2.vm,第三台机器填client.mosquitto3.vm
Send the CSR to the CA, or sign it with your CA key:
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 3650
将虚拟机的证书放到
/ect/mosquitto/certs/client.mosquitto1.vm
目录下
mkdir client.mosquitto1.vm
mv client.crt client.mosquitto1.vm/
mv client.csr client.mosquitto1.vm/
mv client.key client.mosquitto1.vm/
继续执行上面生成Server证书的步骤来生成server.mosquitto2.vm的Server证书,并放入到目录下;生成server.mosquitto3.vm的Server证书,并放入到
/ect/mosquitto/certs/server.mosquitto1.vm
目录下
/ect/mosquitto/certs/server.mosquitto3.vm
mkdir client.mosquitto2.vm
mv client.crt client.mosquitto2.vm/
mv client.csr client.mosquitto2.vm/
mv client.key client.mosquitto2.vm/
mkdir client.mosquitto3.vm
mv client.crt client.mosquitto3.vm/
mv client.csr client.mosquitto3.vm/
mv client.key client.mosquitto3.vm/
TLS单向认证
修改配置
vi /etc/mosquitto/mosquitto.conf
# 修改如下配置
port 8883
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/server.mosquitto1.vm/server.crt
keyfile /etc/mosquitto/certs/server.mosquitto1.vm/server.key
require_certificate false
tls_version tlsv1.2
上面是虚拟机1的配置,在配置虚拟机2和3的时候注意修改证书文件路径
单向认证和双向认证的区别在于
require_certificate
这个配置项
配置完成之后三台机器都启动好mosquitto
测试
开启了TLS之后我用
mosquitto_sub
和
mosquitto_sub
命令都得到一个错误
Error: A TLS error occurred.
但是如果是使用工具,如MQTT.fx就没问题
这个问题弄清楚了,是因为证书的Common Name导致的。需要在mosquitto_sub命令的参数中指定 -h
参数跟证书的Common Name一致就可以了。
下面开始在第一台虚拟机上测试,先订阅一个
/test/1
的主题
mosquitto_sub -u yuanpan1 -P 123456 -t "/test/1" -p 8883 -h server.mosquitto1.vm --cafile "/etc/mosquitto/certs/ca.crt" --tls-version tlsv1.2
再向这个主题发布一个消息
mosquitto_pub -u yuanpan1 -P 123456 -t "/test/1" -m "hello" -p 8883 -h server.mosquitto1.vm --cafile "/etc/mosquitto/certs/ca.crt" --tls-version tlsv1.2
可以看到订阅的地方能收到hello的消息
如果是使用MQTT.fx工具测试,在SSL/TLS中选择CA certificate file ,选择ca.crt文件
TLS单向认证下的多个broker桥接
在server.mosquitto1.vm机器上配置
/etc/mosquitto/mosquitto.conf
,配置如下的内容:
connection bridge1
cleansession true
address server.mosquitto2.vm:8883
topic # both 0
bridge_cafile /etc/mosquitto/certs/ca.crt
remote_username admin
remote_password 123456
connection bridge2
cleansession true
address server.mosquitto3.vm:8883
topic # both 0
bridge_cafile /etc/mosquitto/certs/ca.crt
remote_username admin
remote_password 123456
注意cleansession的设置,如果设置为true,那么在桥接断开的时候,远程代理上订阅和主题会被清除,如果设置为false则不会清除。
配置玩之后重启虚拟机1上的mosquitto
测试的话,可以在任意两台机器上订阅一个主题如/test/1,然后在第三台机器上发布一个消息到这个主题
在虚拟机1和虚拟机2上订阅
mosquitto_sub -u yuanpan1 -P 123456 -t "/test/1" -p 8883 -h server.mosquitto1.vm --cafile "/etc/mosquitto/certs/ca.crt" --tls-version tlsv1.2
mosquitto_sub -u yuanpan1 -P 123456 -t "/test/1" -p 8883 -h server.mosquitto2.vm --cafile "/etc/mosquitto/certs/ca.crt" --tls-version tlsv1.2
在虚拟机3上发布:
mosquitto_pub -u yuanpan1 -P 123456 -t "/test/1" -m "单向TLS测试" -p 8883 -h server.mosquitto3.vm --cafile "/etc/mosquitto/certs/ca.crt" --tls-version tlsv1.2
在虚拟机1和2上都可以看到订阅的消息:单向TLS测试
TLS双向认证
单向认证和双向认证的区别在于 require_certificate
这个配置项
如果是一路走过来的,那么可以先将上面讲到的的桥接部分的配置在虚拟机1上先注释掉,再往下看。
修改配置
vi /etc/mosquitto/mosquitto.conf
# 修改如下配置
port 8883
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/server.mosquitto1.vm/server.crt
keyfile /etc/mosquitto/certs/server.mosquitto1.vm/server.key
require_certificate true
tls_version tlsv1.2
use_identity_as_username true
注意
use_identity_as_username
这个配置项,如果这个配置成了
true
,那么在认证的时候,会将客户端证书中的
Common Name
作为用户名来校验,当然,这个配置项是可以配置成
false
的。
测试
下面开始在第一台虚拟机上测试,先订阅一个
/test/1
的主题
mosquitto_sub -u yuanpan1 -P 123456 -t "/test/1" -p 8883 -h server.mosquitto1.vm --cafile "/etc/mosquitto/certs/ca.crt" --cert "/etc/mosquitto/certs/client.mosquitto1.vm/client.crt" --key "/etc/mosquitto/certs/client.mosquitto1.vm/client.key" --tls-version tlsv1.2
再向这个主题发布一个消息
mosquitto_pub -u yuanpan1 -P 123456 -t "/test/1" -m "双向TLS测试" -p 8883 -h server.mosquitto1.vm --cafile "/etc/mosquitto/certs/ca.crt" --cert "/etc/mosquitto/certs/client.mosquitto1.vm/client.crt" --key "/etc/mosquitto/certs/client.mosquitto1.vm/client.key" --tls-version tlsv1.2
可以看到订阅的地方能收到双向TLS测试的消息
如果是使用MQTT.fx工具测试,在SSL/TLS中选择Self signed certificates。
在CA File中选择ca.crt文件
在Client Certificate File中选择client.crt文件
在Client Key File中选择client.key文件
在Client Key Password中填写生成客户端证书时候的密码
勾选PEM Formatted
TLS双向认证下的多个broker桥接
在server.mosquitto1.vm机器上配置
/etc/mosquitto/mosquitto.conf
,配置如下的内容:
connection bridge1
cleansession true
address server.mosquitto2.vm:8883
topic # both 0
bridge_cafile /etc/mosquitto/certs/ca.crt
remote_username admin
remote_password 123456
connection bridge2
cleansession true
address server.mosquitto3.vm:8883
topic # both 0
bridge_cafile /etc/mosquitto/certs/ca.crt
remote_username admin
remote_password 123456
测试的话,可以在任意两台机器上订阅一个主题如/test/1,然后在第三台机器上发布一个消息到这个主题
在虚拟机1和虚拟机2上订阅
mosquitto_sub -u yuanpan1 -P 123456 -t "/test/1" -p 8883 -h server.mosquitto1.vm --cafile "/etc/mosquitto/certs/ca.crt" --cert "/etc/mosquitto/certs/client.mosquitto1.vm/client.crt" --key "/etc/mosquitto/certs/client.mosquitto1.vm/client.key" --tls-version tlsv1.2
mosquitto_sub -u yuanpan1 -P 123456 -t "/test/1" -p 8883 -h server.mosquitto2.vm --cafile "/etc/mosquitto/certs/ca.crt" --cert "/etc/mosquitto/certs/client.mosquitto2.vm/client.crt" --key "/etc/mosquitto/certs/client.mosquitto2.vm/client.key" --tls-version tlsv1.2
在虚拟机3上发布:
mosquitto_pub -u yuanpan1 -P 123456 -t "/test/1" -m "双向TLS测试" -p 8883 -h server.mosquitto3.vm --cafile "/etc/mosquitto/certs/ca.crt" --cert "/etc/mosquitto/certs/client.mosquitto3.vm/client.crt" --key "/etc/mosquitto/certs/client.mosquitto3.vm/client.key" --tls-version tlsv1.2
在虚拟机1和2上都可以看到订阅的消息:双向TLS测试