# Mosquitto server TLS加密連線
參考自https://www.itread01.com/content/1545349354.html
在Mosquitto中配置基於certificate的TLS/SSL

## 證書(CA)
首先要用openssl製作一個證書(CA),參考官方文件即可。
先把官方的過程列下來,後面我的過程也有
### 程序
1.建立ca.key、ca.crt
2.建立server.key、server.crt
3.建立client.key、client.crt
其中, server.crt中的CN, 必須與連線URL的FQDN相同, 例如連線URL為mqtts://iot.kh.edu.tw:8883, 則 server.crt 中的 CN 必須為 iot.kh.edu.tw。mosquitto1.6.10中不檢查憑證與連線URL是否相符, 但後面的版本就會檢查, 如果不相符就會出現`Error: A TLS error occurred.`
另外, ca.crt、server.crt、client.crt中的CN都必需不同。
### 建立 ca.key、ca.crt
```
openssl req -new -x509 -days <duration> -extensions v3_ca -keyout ca.key -out ca.crt
#<duration>指的是日數
```
## server(伺服端)
### 建立一個 server端的 Key
```
openssl genrsa -des3 -out server.key 2048
若不想加密碼, 則去掉 -des3 即可
openssl genrsa -out server.key 2048
```
### 用 server.key 去建立 server.csr
```
openssl req -out server.csr -key server.key -new
### 注意,當要求輸入CN(common name)的時候,請輸入你伺服器的域名或者IP
也可以將參數加入, 直接使用
openssl req -out server.csr -key server.key -new -subj "/C=TW/ST=TAIWAN/L=KAOHSIUNG/O=KH/OU=EDU/CN=alubasMQTT/emailAddress=alubas@gmail.com"
```
### 傳送CSR給CA, 或者用自己的CA key進行簽章(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 <duration>
```
## client(客戶端)
### 建立一個 client端的 key
```
openssl genrsa -des3 -out client.key 2048
若不想加密碼, 則去掉 -des3 即可
openssl genrsa -out client.key 2048
```
### 用 client.key 去建立 client.csr
```
openssl req -out client.csr -key client.key -new
系統會要求回答一些參數:
Country Name (2 letter code) [XX]:TW
State or Province Name (full name) []:Taiwan
Locality Name (eg, city) [Default City]:Kaohsiung
Organization Name (eg, company) [Default Company Ltd]:KH
Organizational Unit Name (eg, section) []:EDU
Common Name (eg, your name or your server's hostname) []:163.32.x.x
Email Address []:aluabs@gmail.com
也可以將參數加入, 直接使用
openssl req -out server.csr -key server.key -new -subj "/C=TW/ST=TAIWAN/L=KAOHSIUNG/O=KH/OU=EDU/CN=alubasMQTT/emailAddress=alubas@gmail.com"
```
### 傳送CSR給CA或者用自己的CA key簽名(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 <duration>
```
# 實作過程
首先建立ca.key和ca.crt,注意這裡有個坑,倒2行的Common Name,等等服務端和客戶端設定過程中也有這個,ca的Common Name 的值不能和客戶端和服務端的Common Name值一樣,否則無效
-days 我就設定365了,畢竟是測試用。
## 1.建立ca.key、ca.crt
```
[root@mqttSrv]# /etc/mosquitto# mkdir ca
[root@mqttSrv]# /etc/mosquitto# cd ca
[root@mqttSrv]# /etc/mosquitto/ca# openssl req -new -x509 -days 365 -extensions v3_ca -keyout ca.key -out ca.crt
Generating a 2048 bit RSA private key
............+++
...............................................................+++
writing new private key to 'ca.key'
Enter PEM pass phrase:<---輸入自訂密碼
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:TW
State or Province Name (full name) [Some-State]:TAIWAN
Locality Name (eg, city) []:KAOHSIUNG
Organization Name (eg, company) [Internet Widgits Pty Ltd]:KH
Organizational Unit Name (eg, section) []:EDU
# 就是這個,和後面的不能一樣
Common Name (e.g. server FQDN or YOUR name) []:mqttSrv
Email Address []:.
```
這步走完生成了兩個檔案
```
[root@mqttSrv]# /etc/mosquitto/ca# ll
total 16
drwxr-xr-x 2 root root 4096 Nov 11 17:27 ./
drwxr-xr-x 3 root root 4096 Nov 11 17:26 ../
-rw-r--r-- 1 root root 1285 Nov 11 17:27 ca.crt
-rw-r--r-- 1 root root 1834 Nov 11 17:27 ca.key
```
## 2. server 端
### 2.1 建立 server.key
```
[root@mqttSrv]# /etc/mosquitto/ca# openssl genrsa -des3 -out server.key 2048
Generating RSA private key, 2048 bit long modulus
.........+++
...................+++
e is 65537 (0x10001)
#### 注意~這裡設定的-des3就會設定使用server.key要提供密碼,啟動mosquitto服務要用到
Enter pass phrase for server.key: <---輸入自訂密碼
Verifying - Enter pass phrase for server.key:
```
### 2.2產生 server.csr
```
[root@mqttSrv]# /etc/mosquitto/ca# openssl req -out server.csr -key server.key -new
Enter pass phrase for server.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:TW
State or Province Name (full name) [Some-State]:TAIWAN
Locality Name (eg, city) []:KAOHSIUNG
Organization Name (eg, company) [Internet Widgits Pty Ltd]:KH
Organizational Unit Name (eg, section) []:EDU
# 這裡設定成主機的ip了,沒試過別的行不行
Common Name (e.g. server FQDN or YOUR name) []:192.168.193.128
Email Address []:.
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:lxy128server
An optional company name []:.
```
#### 最好不要設定密碼(即去掉-des3), 因為加上密碼後, 每次啟用mosquitto都要輸入密碼, 安全性雖較高,但不實際。
### 2.3 產生 server.crt(傳送CSR給CA或者用自己的CA key簽名)
```
[root@mqttSrv]# /etc/mosquitto/ca# openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365
Signature ok
subject=/C=TW/ST=TAIWAN/L=KAOHSIUNG/O=KH/OU=EDU/CN=192.168.193.128
Getting CA Private Key
Enter pass phrase for ca.key:
```
這步走完ca目錄下有這些檔案
```
[root@mqttSrv]# /etc/mosquitto/ca# ll
total 32
drwxr-xr-x 2 root root 4096 Nov 9 23:13 ./
drwxr-xr-x 4 root root 4096 Nov 9 23:06 ../
-rw-r--r-- 1 root root 1285 Nov 9 23:09 ca.crt
-rw-r--r-- 1 root root 1834 Nov 9 23:09 ca.key
-rw-r--r-- 1 root root 17 Nov 9 23:13 ca.srl
-rw-r--r-- 1 root root 1172 Nov 9 23:13 server.crt
-rw-r--r-- 1 root root 1029 Nov 9 23:12 server.csr
-rw-r--r-- 1 root root 1743 Nov 9 23:11 server.key
```
## 3.Client端
### 3.1 建立 client.key
```
[root@mqttSrv]# /etc/mosquitto/ca# openssl genrsa -des3 -out client.key 2048
Generating RSA private key, 2048 bit long modulus
......+++
......+++
e is 65537 (0x10001)
# 注意,這裡設定的是客戶端sub/pub的時候需要的密碼
Enter pass phrase for client.key:
Verifying - Enter pass phrase for client.key:
```
#### 最好不要設密碼(即去掉-des3),因為每次使用這個client.key都要輸入密碼,安全性高卻不實際。
### 3.2 產生 client.csr
```
[root@mqttSrv]# /etc/mosquitto/ca# openssl req -out client.csr -key client.key -new
Enter pass phrase for client.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:TW
State or Province Name (full name) [Some-State]:TAIWAN
Locality Name (eg, city) []:KAOHSIUNG
Organization Name (eg, company) [Internet Widgits Pty Ltd]:KH
Organizational Unit Name (eg, section) []:EDU
Common Name (e.g. server FQDN or YOUR name) []:192.168.193.128
Email Address []:.
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:.
An optional company name []:.
```
### 3.3 產生 client.crt
```
[root@mqttSrv]# /etc/mosquitto/ca# openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 365
Signature ok
subject=/C=cn/ST=fj/L=fz/O=wecon/OU=r3/CN=192.168.193.128
Getting CA Private Key
Enter pass phrase for ca.key:
```
#### 注意, 產生client.crt的過程中, 需要有ca.crt、ca.key, 因此, 如果製作過程不在mqttSrv上, 要記得把這兩個檔複製過去。
打完這一套,就有下面這些個檔案
[root@mqttSrv]# /etc/mosquitto/ca# ll
total 44
drwxr-xr-x 2 root root 4096 Nov 9 23:15 ./
drwxr-xr-x 4 root root 4096 Nov 9 23:06 ../
-rw-r--r-- 1 root root 1285 Nov 9 23:09 ca.crt
-rw-r--r-- 1 root root 1834 Nov 9 23:09 ca.key
-rw-r--r-- 1 root root 17 Nov 9 23:15 ca.srl
-rw-r--r-- 1 root root 1172 Nov 9 23:15 client.crt
-rw-r--r-- 1 root root 1029 Nov 9 23:14 client.csr
-rw-r--r-- 1 root root 1743 Nov 9 23:13 client.key
-rw-r--r-- 1 root root 1172 Nov 9 23:13 server.crt
-rw-r--r-- 1 root root 1029 Nov 9 23:12 server.csr
-rw-r--r-- 1 root root 1743 Nov 9 23:11 server.key
## 4.mosquitto.conf 設定
到mosquitto.conf中進行設定,我這裡直接加在最後面
```
port 8883
cafile /etc/mosquitto/ca/ca.crt
keyfile /etc/mosquitto/ca/server.key
certfile /etc/mosquitto/ca/server.crt
require_certificate true
use_identity_as_username false
# 如果要以帳號密碼登入, 則需再加上 pwfile.conf 密碼檔案
# password_file /etc/mosquitto/pwfile.conf
```
設定完重啟mosquitto
```
[root@mqttSrv]# systemctl restart mosquitto
```
應該會出現失敗, 因為前面的server.key, 有加上密碼(-des3), 在系統啟動時會要求輸入密碼, 當使用systemctl 這類啟動service的作法, 無法輸入密碼, 故而造成錯誤。因此, **必需重新產生不加密碼的 server.key**。
看到日誌沒有報錯,就成功了。
[root@mqttSrv]# systemctl start mosquitto
1541842331: mosquitto version 1.5.3 starting
1541842331: Config loaded from /etc/mosquitto/mosquitto.conf.
1541842331: Opening ipv4 listen socket on port 8883.
1541842331: Opening ipv6 listen socket on port 8883.
## 5.client端以TLS連線到mosquitto
### 訂閱 mosquitto_sub
```
[root@mqttSrv]# mosquitto_sub -h 192.168.193.128 -p 8883 \
-t "ssl/topic/#" \
--cafile /etc/mosquitto/ca/ca.crt \
--cert /etc/mosquitto/ca/client.crt \
--key /etc/mosquitto/ca/client.key \
-u alubas -P haha1234
```
-h 主機
-p 埠
-t 話題,訂閱 ssl/topic/下的所有主題
--cafile 指定ca.crt
--cert 客戶端的client.crt
--key 客戶端的client.key
如果mosquitto.conf 還設定使用password_file登入,則必需再帶上使用者名稱密碼,如果
這項 use_identity_as_username設為 true,那就不用了
-u alubas 帳號
-P haha1234 密碼
#### 系統日誌
```
1541842539: New connection from 192.168.193.128 on port 8883.
1541842543: New client connected from 192.168.193.128 as mosqsub|19778-ubuntu (c1, k60, u'alubas').
```
### 發佈 mosquitto_pub
```
[root@mqttSrv]# mosquitto_pub -h 192.168.193.128 -p 8883 \
-t "ssl/topic/128" \
--cafile /etc/mosquitto/ca/ca.crt \
--cert /etc/mosquitto/ca/client.crt \
--key /etc/mosquitto/ca/client.key \
-m "Hello world, I am a TLS client, and publishing msg to mqttSrv at port 8883" \
-u alubas -P haha1234
```
參數基本上和訂閱一樣,如果client.key有加密碼, 執行時也必需同步輸入。
#### 監聽端收到訊息了
```
[root@mqttSrv]# mosquitto_sub -h 192.168.193.128 -p 8883
-t "ssl/topic/#" \
--cafile /etc/mosquitto/ca/ca.crt \
--cert /etc/mosquitto/ca/client.crt \
--key /etc/mosquitto/ca/client.key \
-u alubas -P haha1234
Hello world, I am a TLS client, and publishing msg to mqttSrv at port 8883
```
## 6.好用的工具- [generate-CA](https://github.com/owntracks/tools/blob/master/TLS/generate-CA.sh)
一套自動化產生 server 端和 client 端所需全部檔案的工具, 基本上就是把前面所有的程序打包起來, 但我建議先一步一步敲指令, 等熟練後再使用 generate-CA, 以免不知其所以然~
使用前要先修改環境變數, 例如:
IPLIST="192.168.193.128"
HOSTLIST="mqttSrv.alubas.com"
執行 generate-CA.sh 可產生server 端所需檔案
執行 generate-CA.sh client pc1 可產生 client 端所需的檔案(pc1.key, pc1.crt, pc1.csr)
打完收工~
alubas@20211220