mirror of
https://github.com/mainflux/mainflux.git
synced 2025-04-26 13:48:53 +08:00
MF-651 - X509 Mutual TLS authentication (#676)
* Use NginX njs module for mutual authentication Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Add Makefile for cert management Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Move certificates make context to scripts dir Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Move nginx.conf to separate directory Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Choose between two NginX configurations Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Move certs Makefile to docker/ssl/ Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Use default key-based authentication Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Add mTLS docs Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Update Makefile Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Add check if Authorization is present Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Add check if Will Flag is 1 Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Return MQTT over WS Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Fix docker-compose.yml volume mapping Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Rename security section in docs Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Add message type check before message parsing Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Remove double comments Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Remove s.AGAIN in return Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Update Makefile Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Remove CSR and key from the root Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Drop TLS version below 1.2 Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Add comments for cert and key paths Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>
This commit is contained in:
parent
bc49f6a543
commit
f9b17d5f24
@ -14,12 +14,14 @@ networks:
|
||||
|
||||
services:
|
||||
nginx:
|
||||
image: nginx:1.14.2-alpine
|
||||
image: nginx:1.14.2
|
||||
container_name: mainflux-nginx
|
||||
restart: on-failure
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf
|
||||
- ./nginx/nginx-${AUTH-key}.conf:/etc/nginx/nginx.conf
|
||||
- ./ssl/authorization.js:/etc/nginx/authorization.js
|
||||
- ./ssl/certs/mainflux-server.crt:/etc/ssl/certs/mainflux-server.crt
|
||||
- ./ssl/certs/ca.crt:/etc/ssl/certs/ca.crt
|
||||
- ./ssl/certs/mainflux-server.key:/etc/ssl/private/mainflux-server.key
|
||||
- ./ssl/dhparam.pem:/etc/ssl/certs/dhparam.pem
|
||||
ports:
|
||||
|
@ -1,16 +1,11 @@
|
||||
###
|
||||
# Mainflux NGINX Conf
|
||||
#
|
||||
# Taken for /etc/nginx/nginx.conf on Debian machine
|
||||
# and https://github.com/nginxinc/docker-nginx/blob/master/mainline/alpine/nginx.conf
|
||||
###
|
||||
# Copyright (c) 2018
|
||||
# Mainflux
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# This is the default Mainflux NGINX configuration.
|
||||
|
||||
##
|
||||
# User:
|
||||
# - 'www-data' on Debian
|
||||
# - 'nginx' on Alpine
|
||||
##
|
||||
#user www-data;
|
||||
user nginx;
|
||||
worker_processes auto;
|
||||
pid /run/nginx.pid;
|
||||
@ -18,77 +13,37 @@ include /etc/nginx/modules-enabled/*.conf;
|
||||
|
||||
events {
|
||||
worker_connections 768;
|
||||
# multi_accept on;
|
||||
}
|
||||
|
||||
###
|
||||
# HTTP
|
||||
###
|
||||
http {
|
||||
|
||||
##
|
||||
# Basic Settings
|
||||
##
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
# server_tokens off;
|
||||
|
||||
# server_names_hash_bucket_size 64;
|
||||
# server_name_in_redirect off;
|
||||
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
##
|
||||
# SSL Settings
|
||||
##
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
##
|
||||
# Logging Settings
|
||||
##
|
||||
access_log /var/log/nginx/access.log;
|
||||
error_log /var/log/nginx/error.log;
|
||||
|
||||
##
|
||||
# Virtual Host Configs
|
||||
##
|
||||
|
||||
# HTTPS
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
# SSL configuration
|
||||
#
|
||||
listen 443 ssl http2 default_server;
|
||||
listen [::]:443 ssl http2 default_server;
|
||||
|
||||
#
|
||||
# Note: You should disable gzip for SSL traffic.
|
||||
# See: https://bugs.debian.org/773332
|
||||
#
|
||||
# Read up on ssl_ciphers to ensure a secure configuration.
|
||||
# See: https://bugs.debian.org/765782
|
||||
#
|
||||
# Self signed certs generated by the ssl-cert package
|
||||
# Don't use them in a production server!
|
||||
#
|
||||
# include snippets/snakeoil.conf;
|
||||
|
||||
# Certificates
|
||||
# These paths are set to its default values as
|
||||
# a volume in the docker/docker-compose.yml file.
|
||||
ssl_certificate /etc/ssl/certs/mainflux-server.crt;
|
||||
ssl_certificate_key /etc/ssl/private/mainflux-server.key;
|
||||
ssl_dhparam /etc/ssl/certs/dhparam.pem;
|
||||
|
||||
|
||||
# from https://cipherli.st/
|
||||
# and https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
|
||||
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
|
||||
ssl_ecdh_curve secp384r1;
|
||||
@ -98,15 +53,12 @@ http {
|
||||
resolver 8.8.8.8 8.8.4.4 valid=300s;
|
||||
resolver_timeout 5s;
|
||||
|
||||
# Disable preloading HSTS for now. You can use the commented out header line that includes
|
||||
# the "preload" directive if you understand the implications.
|
||||
#add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
|
||||
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
|
||||
add_header X-Frame-Options DENY;
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
add_header Access-Control-Allow-Origin '*';
|
||||
add_header Access-Control-Allow-Methods '*';
|
||||
add_header Access-Control-Allow-Headers "*";
|
||||
add_header Access-Control-Allow-Headers '*';
|
||||
|
||||
server_name localhost;
|
||||
|
||||
@ -200,8 +152,8 @@ http {
|
||||
return 200;
|
||||
}
|
||||
}
|
||||
|
||||
# Proxy pass to mainflux-mqtt-adapter
|
||||
|
||||
# Proxy pass to mainflux-mqtt-adapter over WS
|
||||
location /mqtt {
|
||||
proxy_redirect off;
|
||||
proxy_set_header Host $host;
|
||||
@ -244,21 +196,17 @@ http {
|
||||
|
||||
# MQTT
|
||||
stream {
|
||||
# MQTT
|
||||
server {
|
||||
listen 8883 ssl;
|
||||
listen [::]:8883 ssl;
|
||||
|
||||
# Certificates
|
||||
# These paths are set to its default values as
|
||||
# a volume in the docker/docker-compose.yml file.
|
||||
ssl_certificate /etc/ssl/certs/mainflux-server.crt;
|
||||
ssl_certificate_key /etc/ssl/private/mainflux-server.key;
|
||||
ssl_dhparam /etc/ssl/certs/dhparam.pem;
|
||||
|
||||
|
||||
# from https://cipherli.st/
|
||||
# and https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
|
||||
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
|
||||
ssl_ecdh_curve secp384r1;
|
259
docker/nginx/nginx-x509.conf
Normal file
259
docker/nginx/nginx-x509.conf
Normal file
@ -0,0 +1,259 @@
|
||||
#
|
||||
# Copyright (c) 2018
|
||||
# Mainflux
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# This is the Mainflux NGINX configuration for mututal authentication based on X.509 certifiactes.
|
||||
|
||||
user nginx;
|
||||
worker_processes auto;
|
||||
pid /run/nginx.pid;
|
||||
load_module /etc/nginx/modules/ngx_stream_js_module.so;
|
||||
load_module /etc/nginx/modules/ngx_http_js_module.so;
|
||||
include /etc/nginx/modules-enabled/*.conf;
|
||||
|
||||
events {
|
||||
worker_connections 768;
|
||||
}
|
||||
|
||||
http {
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
js_include authorization.js;
|
||||
js_set $auth_key setKey;
|
||||
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
listen 443 ssl http2 default_server;
|
||||
listen [::]:443 ssl http2 default_server;
|
||||
|
||||
# These paths are set to its default values as
|
||||
# a volume in the docker/docker-compose.yml file.
|
||||
ssl_certificate /etc/ssl/certs/mainflux-server.crt;
|
||||
ssl_certificate_key /etc/ssl/private/mainflux-server.key;
|
||||
ssl_client_certificate /etc/ssl/certs/ca.crt;
|
||||
ssl_verify_client optional;
|
||||
ssl_verify_depth 2;
|
||||
ssl_dhparam /etc/ssl/certs/dhparam.pem;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
|
||||
ssl_ecdh_curve secp384r1;
|
||||
ssl_session_tickets off;
|
||||
ssl_stapling off;
|
||||
ssl_stapling_verify on;
|
||||
resolver 8.8.8.8 8.8.4.4 valid=300s;
|
||||
resolver_timeout 5s;
|
||||
|
||||
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
|
||||
add_header X-Frame-Options DENY;
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
add_header Access-Control-Allow-Origin '*';
|
||||
add_header Access-Control-Allow-Methods '*';
|
||||
add_header Access-Control-Allow-Headers '*';
|
||||
|
||||
server_name localhost;
|
||||
|
||||
# Proxy pass to users service
|
||||
location ~ ^/(users|tokens) {
|
||||
proxy_redirect off;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_pass http://users:8180;
|
||||
|
||||
# Allow OPTIONS method CORS
|
||||
if ($request_method = OPTIONS ) {
|
||||
add_header Content-Length 0;
|
||||
add_header Content-Type text/plain;
|
||||
return 200;
|
||||
}
|
||||
}
|
||||
|
||||
# Proxy pass to things service
|
||||
location ~ ^/(things|channels) {
|
||||
proxy_redirect off;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
add_header Access-Control-Expose-Headers Location;
|
||||
proxy_pass http://things:8182;
|
||||
|
||||
# Allow OPTIONS method CORS
|
||||
if ($request_method = OPTIONS ) {
|
||||
add_header Content-Length 0;
|
||||
add_header Content-Type text/plain;
|
||||
return 200;
|
||||
}
|
||||
}
|
||||
|
||||
location /version {
|
||||
proxy_redirect off;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_pass http://things:8182;
|
||||
|
||||
# Allow OPTIONS method CORS
|
||||
if ($request_method = OPTIONS ) {
|
||||
add_header Content-Length 0;
|
||||
add_header Content-Type text/plain;
|
||||
return 200;
|
||||
}
|
||||
}
|
||||
|
||||
# Proxy pass to mainflux-http-adapter
|
||||
location /http/ {
|
||||
if ($ssl_client_verify != SUCCESS) {
|
||||
return 403;
|
||||
}
|
||||
if ($auth_key = '') {
|
||||
return 403;
|
||||
}
|
||||
|
||||
proxy_redirect off;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header Authorization $auth_key;
|
||||
proxy_pass http://http-adapter:8185/;
|
||||
|
||||
# Allow OPTIONS method CORS
|
||||
if ($request_method = OPTIONS ) {
|
||||
add_header Content-Length 0;
|
||||
add_header Content-Type text/plain;
|
||||
return 200;
|
||||
}
|
||||
}
|
||||
|
||||
# Proxy pass to mainflux-ws-adapter
|
||||
location /ws/ {
|
||||
if ($ssl_client_verify != SUCCESS) {
|
||||
return 403;
|
||||
}
|
||||
if ($auth_key = '') {
|
||||
return 403;
|
||||
}
|
||||
|
||||
proxy_redirect off;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
proxy_connect_timeout 7d;
|
||||
proxy_send_timeout 7d;
|
||||
proxy_read_timeout 7d;
|
||||
proxy_pass http://ws-adapter:8186/;
|
||||
|
||||
# Allow OPTIONS method CORS
|
||||
if ($request_method = OPTIONS ) {
|
||||
add_header Content-Length 0;
|
||||
add_header Content-Type text/plain;
|
||||
return 200;
|
||||
}
|
||||
}
|
||||
|
||||
# Proxy pass to mainflux-mqtt-adapter over WS
|
||||
location /mqtt {
|
||||
if ($ssl_client_verify != SUCCESS) {
|
||||
return 403;
|
||||
}
|
||||
if ($auth_key = '') {
|
||||
return 403;
|
||||
}
|
||||
|
||||
proxy_redirect off;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
proxy_connect_timeout 7d;
|
||||
proxy_send_timeout 7d;
|
||||
proxy_read_timeout 7d;
|
||||
proxy_pass http://mqtt-adapter:8880/;
|
||||
|
||||
# Allow OPTIONS method CORS
|
||||
if ($request_method = OPTIONS ) {
|
||||
add_header Content-Length 0;
|
||||
add_header Content-Type text/plain;
|
||||
return 200;
|
||||
}
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_redirect off;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_pass http://ui:3000/;
|
||||
|
||||
# Allow OPTIONS method CORS
|
||||
if ($request_method = OPTIONS ) {
|
||||
add_header Content-Length 0;
|
||||
add_header Content-Type text/plain;
|
||||
return 200;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
error_log info.log info;
|
||||
error_log error.log error;
|
||||
error_log warn.log warn;
|
||||
}
|
||||
|
||||
# MQTT
|
||||
stream {
|
||||
js_include authorization.js;
|
||||
server {
|
||||
listen 8883 ssl;
|
||||
listen [::]:8883 ssl;
|
||||
|
||||
# These paths are set to its default values as
|
||||
# a volume in the docker/docker-compose.yml file.
|
||||
ssl_certificate /etc/ssl/certs/mainflux-server.crt;
|
||||
ssl_certificate_key /etc/ssl/private/mainflux-server.key;
|
||||
ssl_client_certificate /etc/ssl/certs/ca.crt;
|
||||
ssl_verify_client on;
|
||||
ssl_verify_depth 2;
|
||||
ssl_dhparam /etc/ssl/certs/dhparam.pem;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
|
||||
ssl_ecdh_curve secp384r1;
|
||||
ssl_session_tickets off;
|
||||
resolver 8.8.8.8 8.8.4.4 valid=300s;
|
||||
resolver_timeout 5s;
|
||||
js_preread authenticate;
|
||||
|
||||
proxy_pass mqtt-adapter:1883;
|
||||
}
|
||||
}
|
||||
|
||||
error_log info.log info;
|
||||
error_log error.log error;
|
||||
error_log warn.log warn;
|
42
docker/ssl/Makefile
Normal file
42
docker/ssl/Makefile
Normal file
@ -0,0 +1,42 @@
|
||||
CRT_LOCATION = certs
|
||||
KEY = default
|
||||
O = Mainflux
|
||||
OU = mainflux
|
||||
EA = info@mainflux.com
|
||||
CN = localhost
|
||||
CRT_FILE_NAME = thing
|
||||
|
||||
all: clean_certs ca server_crt
|
||||
|
||||
# CA name and key is "ca".
|
||||
ca:
|
||||
openssl req -newkey rsa:2048 -x509 -nodes -sha512 -days 1095 \
|
||||
-keyout $(CRT_LOCATION)/ca.key -out $(CRT_LOCATION)/ca.crt -subj "/CN=localhost/O=Mainflux/OU=IoT/emailAddress=info@mainflux.com"
|
||||
|
||||
# Server cert and key name is "mainflux-server".
|
||||
server_cert:
|
||||
# Create mainflux server key and CSR.
|
||||
openssl req -new -sha256 -newkey rsa:4096 -nodes -keyout $(CRT_LOCATION)/mainflux-server.key \
|
||||
-out $(CRT_LOCATION)/mainflux-server.csr -subj "/CN=$(CN)/O=$(O)/OU=$(OU)/emailAddress=$(EA)"
|
||||
|
||||
# Sign server CSR.
|
||||
openssl x509 -req -days 1000 -in $(CRT_LOCATION)/mainflux-server.csr -CA $(CRT_LOCATION)/ca.crt -CAkey $(CRT_LOCATION)/ca.key -CAcreateserial -out $(CRT_LOCATION)/mainflux-server.crt
|
||||
|
||||
# Remove CSR.
|
||||
rm $(CRT_LOCATION)/mainflux-server.csr
|
||||
|
||||
thing_cert:
|
||||
# Create mainflux server key and CSR.
|
||||
openssl req -new -sha256 -newkey rsa:4096 -nodes -keyout $(CRT_LOCATION)/$(CRT_FILE_NAME).key \
|
||||
-out $(CRT_LOCATION)/$(CRT_FILE_NAME).csr -subj "/CN=$(KEY)/O=$(O)/OU=$(OU)/emailAddress=$(EA)"
|
||||
|
||||
# Sign client CSR.
|
||||
openssl x509 -req -days 730 -in $(CRT_LOCATION)/$(CRT_FILE_NAME).csr -CA $(CRT_LOCATION)/ca.crt -CAkey $(CRT_LOCATION)/ca.key -CAcreateserial -out $(CRT_LOCATION)/$(CRT_FILE_NAME).crt
|
||||
|
||||
# Remove CSR.
|
||||
rm $(CRT_LOCATION)/$(CRT_FILE_NAME).csr
|
||||
|
||||
clean_certs:
|
||||
rm -r $(CRT_LOCATION)/*.crt
|
||||
rm -r $(CRT_LOCATION)/*.key
|
||||
rm -r $(CRT_LOCATION)/*.srl
|
176
docker/ssl/authorization.js
Normal file
176
docker/ssl/authorization.js
Normal file
@ -0,0 +1,176 @@
|
||||
var clientKey = '';
|
||||
|
||||
// Check certificate MQTTS.
|
||||
function authenticate(s) {
|
||||
if (!s.variables.ssl_client_s_dn || !s.variables.ssl_client_s_dn.length ||
|
||||
!s.variables.ssl_client_verify || s.variables.ssl_client_verify != "SUCCESS") {
|
||||
s.deny();
|
||||
return
|
||||
}
|
||||
|
||||
s.on('upload', function (data) {
|
||||
if (data == '') {
|
||||
return;
|
||||
}
|
||||
|
||||
var packet_type_flags_byte = data.codePointAt(0);
|
||||
// First MQTT packet contain message type and flags. CONNECT message type
|
||||
// is encoded as 0001, and we're not interested in flags, so only values
|
||||
// 0001xxxx (which is between 16 and 32) should be checked.
|
||||
if (packet_type_flags_byte < 16 || packet_type_flags_byte >= 32) {
|
||||
s.off('upload');
|
||||
s.allow();
|
||||
return;
|
||||
}
|
||||
|
||||
if (clientKey === '') {
|
||||
clientKey = parseCert(s.variables.ssl_client_s_dn, 'CN');
|
||||
}
|
||||
|
||||
var pass = parsePackage(s, data);
|
||||
|
||||
if (!clientKey.length || pass !== clientKey) {
|
||||
s.error('Cert CN (' + clientKey + ') does not match client password');
|
||||
s.off('upload')
|
||||
s.deny();
|
||||
return;
|
||||
}
|
||||
|
||||
s.off('upload');
|
||||
s.allow();
|
||||
})
|
||||
}
|
||||
|
||||
function parsePackage(s, data) {
|
||||
// An explanation of MQTT packet structure can be found here:
|
||||
// https://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#msg-format.
|
||||
|
||||
// CONNECT message is explained here:
|
||||
// https://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#connect.
|
||||
|
||||
/*
|
||||
0 1 2 3
|
||||
7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| TYPE | RSRVD | REMAINING LEN | PROTOCOL NAME LEN |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| PROTOCOL NAME |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
|
||||
| VERSION | FLAGS | KEEP ALIVE |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
|
||||
| Payload (if any) ... |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
First byte with remaining length represents fixed header.
|
||||
Remaining Length is the length of the variable header (10 bytes) plus the length of the Payload.
|
||||
It is encoded in the manner described here:
|
||||
http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/errata01/os/mqtt-v3.1.1-errata01-os-complete.html#_Toc442180836.
|
||||
|
||||
Connect flags byte looks like this:
|
||||
| 7 | 6 | 5 | 4 3 | 2 | 1 | 0 |
|
||||
| Username Flag | Password Flag | Will Retain | Will QoS | Will Flag | Clean Session | Reserved |
|
||||
|
||||
The payload is determined by the flags and comes in this order:
|
||||
1. Client ID (2 bytes length + ID value)
|
||||
2. Will Topic (2 bytes length + Will Topic value) if Will Flag is 1.
|
||||
3. Will Message (2 bytes length + Will Message value) if Will Flag is 1.
|
||||
4. User Name (2 bytes length + User Name value) if User Name Flag is 1.
|
||||
5. Password (2 bytes length + Password value) if Password Flag is 1.
|
||||
|
||||
This method extracts Password field.
|
||||
*/
|
||||
|
||||
// Extract variable length header. It's 1-4 bytes. As long as continuation byte is
|
||||
// 1, there are more bytes in this header. This algorithm is explained here:
|
||||
// http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/errata01/os/mqtt-v3.1.1-errata01-os-complete.html#_Toc442180836
|
||||
var len_size = 1;
|
||||
for (var remaining_len = 1; remaining_len < 5; remaining_len++) {
|
||||
if (data.codePointAt(remaining_len) > 128) {
|
||||
len_size += 1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// CONTROL(1) + MSG_LEN(1-4) + PROTO_NAME_LEN(2) + PROTO_NAME(4) + PROTO_VERSION(1)
|
||||
var flags_pos = 1 + len_size + 2 + 4 + 1;
|
||||
var flags = data.codePointAt(flags_pos);
|
||||
|
||||
// If there are no username and password flags (11xxxxxx), return.
|
||||
if (flags < 192) {
|
||||
s.error('MQTT username or password not provided');
|
||||
return '';
|
||||
}
|
||||
|
||||
// FLAGS(1) + KEEP_ALIVE(2)
|
||||
var shift = flags_pos + 1 + 2;
|
||||
|
||||
// Number of bytes to encode length.
|
||||
var len_bytes_num = 2;
|
||||
|
||||
// If Wil Flag is present, Will Topic and Will Message need to be skipped as well.
|
||||
var shift_flags = 196 <= flags ? 5 : 3;
|
||||
var len_msb, len_lsb, len;
|
||||
|
||||
for (var i = 0; i < shift_flags; i++) {
|
||||
len_msb = data.codePointAt(shift).toString(16);
|
||||
len_lsb = data.codePointAt(shift + 1).toString(16);
|
||||
len = calcLen(len_msb, len_lsb);
|
||||
shift += len_bytes_num;
|
||||
if (i != shift_flags - 1) {
|
||||
shift += len;
|
||||
}
|
||||
}
|
||||
|
||||
var password = data.substring(shift, shift + len);
|
||||
return password;
|
||||
}
|
||||
|
||||
// Check certificate HTTPS and WSS.
|
||||
function setKey(r) {
|
||||
if (clientKey === '') {
|
||||
clientKey = parseCert(r.variables.ssl_client_s_dn, 'CN');
|
||||
}
|
||||
|
||||
var auth = r.headersIn['Authorization'];
|
||||
if (auth.length && auth != clientKey) {
|
||||
r.error('Authorization header does not match certificate');
|
||||
return '';
|
||||
}
|
||||
|
||||
if (r.uri.startsWith('/ws') && !auth.length) {
|
||||
var a;
|
||||
for (a in r.args) {
|
||||
if (a == 'authorization' && r.args[a] === clientKey) {
|
||||
return clientKey;
|
||||
}
|
||||
}
|
||||
|
||||
r.error('Authorization param does not match certificate');
|
||||
return '';
|
||||
}
|
||||
|
||||
return clientKey;
|
||||
}
|
||||
|
||||
function calcLen(msb, lsb) {
|
||||
if (lsb < 2) {
|
||||
lsb = '0' + lsb;
|
||||
}
|
||||
|
||||
return parseInt(msb + lsb, 16);
|
||||
}
|
||||
|
||||
function parseCert(cert, key) {
|
||||
if (cert.length) {
|
||||
var pairs = cert.split(',');
|
||||
for (var i = 0; i < pairs.length; i++) {
|
||||
var pair = pairs[i].split('=');
|
||||
if (pair[0].toUpperCase() == key) {
|
||||
return pair[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
@ -1,21 +1,22 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
5Yq2
|
||||
-----END CERTIFICATE-----
|
||||
|
28
docker/ssl/certs/ca.key
Normal file
28
docker/ssl/certs/ca.key
Normal file
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCq6O4PHwgGOmEa
|
||||
fjea5KocG80GYSYbvN37ums6fQ1wcmCxn8LtZek8WkfJS2NQQPDvn8QWRY7aUkTA
|
||||
W7cEB4vxpT25bevP7KJNFAS8XZO7NTfF8fscJS+YWSXzVS0OFZ2YuqTnjCiqWf5m
|
||||
vjAkkXBGIYq+k2ONM1tHlEA0lzbLun2a9H/XarCG+znjpfYpW6R08zFzXyGb4sI2
|
||||
pyYpP7iZLla7PTSZTt9h6jkY3qqMDhEHhPdlXDhO1O9/lA8yWMO9vKCzC7ngDXnV
|
||||
99Nl+tFhp9z9VkTUveLMuN9+riDJRfP25fOzHuRYzmsRemYjD1NvSgsvFqSbFDVX
|
||||
B8kcyrXPAgMBAAECggEAbp/el0MKup1HBRL1gvjHcvI7vwla1VFmje2YQn93F3Wx
|
||||
SMeUMH1qfnohRRXa7rNaQIA1OAVF9eKSRcAXsjAAUSUX0tJndGpCk4mFlzcqzF4h
|
||||
/6olU45uRDpP6jUTuK4dGCKXYpjCKaGenXo1RzYsafiECd707Qx05Nv8ww2tlifN
|
||||
HtUR0xCZfVGDZfmNMZVrksUIZ1XHwZNtNLWQW6MBl3RhFaA0Wz/RfFMi2FzacEbj
|
||||
75IqE6PLic1fin6P3GouzKamtZ6YPTyR5PqxCOCw97oZDCUGy2qGyAuPUi9O2HKB
|
||||
fQgSyIxuR73S2korvxAmvekubjBFAqhan2oEjZs6oQKBgQDT28COlC33BSrpr2+V
|
||||
pZIL4Bb1rGHreTi1M/4n9nP3GOZ9gqnSUsWXyxYVoZ2YfixorjZhUzHyx4SfZ2E9
|
||||
p5PkIJ0wOiHLlKQ36vEVN9ZO1UyNCYUgs3seW40xnsAiMNczZjufIZrsejO3tc2j
|
||||
Jhgp+B/9Bt5A8us2ewhz3LlQowKBgQDOhQmZAfL/xAjYBCUS73t/YO60i5e1yg2J
|
||||
i6jXeKjd5gRZ32upkBzQ8UBvAGSQGqrcCnqIzrU5TeeD046bZzkokg7iKwHwQDrL
|
||||
SXTthUB6ABZddP/VXCEUVBer3FEnUgJm9jw08RzmPyNEPjfp91FDmJ9GYcbdo/nL
|
||||
hBPHh3lc5QKBgQCJYZ0yWACeiKlVNECFqAJW1Q/Oa+RrkAYn6vlK7NQyTeFZTlvV
|
||||
WXtsfXNqv4y0kE037JCy+AIRzzO/MoiqNHsAme2Ukn3LyC3dXOrMuZKtOEAVzTCZ
|
||||
Dgoum2up26n4AffrCsZq4J3X7z6OSMR6oX9V5+LGb6e8Mko43/uRNnatRQKBgEMH
|
||||
bQkLV+ppnxE1ry7JKcU7Gd7hm9j1/pTRDnj5AZ4b5Peii1ganS+3zdj5QKqA7UnD
|
||||
4Od8Z9d0kJr51EReKXAgj9IacWOgBTUr31akNDwkwR2ONubyIw5tCM3QEUr41CzE
|
||||
6N+qDl4wyeqBYzZ9/hM5eyCl5ZzUduP2N1FAiER9AoGAW2T0OeM5ZsPABMKu9eEN
|
||||
FB9bVysqWT1tExB34OGWrZvNEzsHTqvr/D3KSWv0PS1pM46M1XkVbybOzRmPrzab
|
||||
AGMDJXgGhMuk2UtDA/s9mgqTOeDXpvmaFyThVkoH162j6GMuX2SwxHnH9D42zgMR
|
||||
3LEZ/5Q5HMJ4jwEM880jvP4=
|
||||
-----END PRIVATE KEY-----
|
1
docker/ssl/certs/ca.srl
Normal file
1
docker/ssl/certs/ca.srl
Normal file
@ -0,0 +1 @@
|
||||
27207EA9519D3D252E08AFA38D23BF2928FD5E20
|
@ -1,29 +1,25 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFDDCCA/SgAwIBAgIJANUB7oWmhqk8MA0GCSqGSIb3DQEBDQUAMFcxEjAQBgNV
|
||||
BAMMCWxvY2FsaG9zdDERMA8GA1UECgwITWFpbmZsdXgxDDAKBgNVBAsMA0lvVDEg
|
||||
MB4GCSqGSIb3DQEJARYRaW5mb0BtYWluZmx1eC5jb20wHhcNMTgxMTAyMTc1MzQ0
|
||||
WhcNMzIxMDI5MTc1MzQ0WjBdMRgwFgYDVQQDDA9tYWluZmx1eC1zZXJ2ZXIxETAP
|
||||
BgNVBAoMCE1haW5mbHV4MQwwCgYDVQQLDANJb1QxIDAeBgkqhkiG9w0BCQEWEWlu
|
||||
Zm9AbWFpbmZsdXguY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
|
||||
ovtHVZacXvf5m7iyhLdGqBaoTwUMSWR+LDaHyeUAcqLy4AHe2TGdJmbrsSKJOb94
|
||||
Winru0dgQyBE1a/I+MOPYVNbYmShOoUSH6/a2Ph3DM8C7PjaFsc+uKd6NiVRmFid
|
||||
c+3pQ62Um9mgJ5jD6kFB2uO5Bk9zxlDRGZz2BYvMFGcbhDZzf28O/Wwitfjb3dek
|
||||
8kohknaIgHy50qstxt/GRFVHpqK0B+PVubC3Dr1Ext+lZORqM44o36jdUyVhnFXf
|
||||
f8Fj/g4whrJfq3AOHeMsxm1VLqKeQb9CxpWvUi396w/bEXOuKXyoP5hyMUAvXEoE
|
||||
pw2+M/CPHuCzj/ELafjWjQIDAQABo4IB0zCCAc8wDAYDVR0TAQH/BAIwADARBglg
|
||||
hkgBhvhCAQEEBAMCBkAwCwYDVR0PBAQDAgXgMCoGCWCGSAGG+EIBDQQdFhtNYWlu
|
||||
Zmx1eCBTZXJ2ZXIgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFDRwdZDGidKOpuJ29hXz
|
||||
RWRFD8YkMIGIBgNVHSMEgYAwfoAUMmE/LCiFwPSKXDSAQvcRF/9yM56hW6RZMFcx
|
||||
MIIEOjCCAyICFCcgfqlRnT0lLgivo40jvyko/V4fMA0GCSqGSIb3DQEBCwUAMFcx
|
||||
EjAQBgNVBAMMCWxvY2FsaG9zdDERMA8GA1UECgwITWFpbmZsdXgxDDAKBgNVBAsM
|
||||
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
|
||||
-----END CERTIFICATE-----
|
||||
|
@ -1,27 +1,52 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEAovtHVZacXvf5m7iyhLdGqBaoTwUMSWR+LDaHyeUAcqLy4AHe
|
||||
2TGdJmbrsSKJOb94Winru0dgQyBE1a/I+MOPYVNbYmShOoUSH6/a2Ph3DM8C7Pja
|
||||
Fsc+uKd6NiVRmFidc+3pQ62Um9mgJ5jD6kFB2uO5Bk9zxlDRGZz2BYvMFGcbhDZz
|
||||
f28O/Wwitfjb3dek8kohknaIgHy50qstxt/GRFVHpqK0B+PVubC3Dr1Ext+lZORq
|
||||
M44o36jdUyVhnFXff8Fj/g4whrJfq3AOHeMsxm1VLqKeQb9CxpWvUi396w/bEXOu
|
||||
KXyoP5hyMUAvXEoEpw2+M/CPHuCzj/ELafjWjQIDAQABAoIBACZM2KmjWCH1MkJG
|
||||
+CS6ES+lC25uaEHDDOeE9Qob96v44QyFRAJUZ3LD0vVwgUEB3t2JZm0/S77akXKJ
|
||||
+beD9WjQtvP7Y+wlo2mw4MQGN6vZ5f0cSdv6fKHWMaERygf8IxxAN4YA/6BUVw+X
|
||||
FcsyBLDUvQFfoHxlN45GVYZeINpWNJEM5NkQpoz5JJmWplfRREtRDiFfdFvh8l25
|
||||
nOeYaZkD9IAPW5k7ukzzUM4voNOKoutCV3h30AbD8zNMPblatLTrT9ZRtjEiofDn
|
||||
iNT6DR2Ge4WWN8e+9h9CEklhhCwBULNlCg2mdNKsiU3q74oBExiKNrtJGxZXlhny
|
||||
PIpciL0CgYEA01HmmXG1z82QmcvoMZBoHu9wNNl5krt5YsYUF9TWXTPijw6zxnLB
|
||||
b0ef997KzMt1ZGRSq8Zae6YdMRXCvQJh1SMbhBTMfOwzbx+cqCcInmia47jAXgaV
|
||||
agAc7im3gULeTnXtNRdo9cj2ilHmlJNFI0N0rl9NJxpYACEeSFaR6YMCgYEAxXD4
|
||||
Z0+Boo+wsIvcxYWkYWpvhJfqqdETZJ5RdgkWLFG7OA2SWPgqIyWxPTnQRsK5ryjw
|
||||
xyxNv7L9Ddd/+yCNsiuUIEdhLPtoIfBQ96722IJMTOxr9eWUXVngANBeMUypv/3q
|
||||
v3AeD8MfTgJJPZ5F3zfLAeBPUxUx6JUIRxjFEq8CgYEAh+3q01EdjinAle1f0mH9
|
||||
V8jU+GnbldMZ5btcOWgi65jwZu0iHsi6PIZqE9svwEQvowAVXYEduuPDa0uAFGxv
|
||||
2dXXYUKvtruI6jX/YvqYxKys1UaGFvVNLv4bnecfrvoAXZ/lkX0ZeuBmFdtQ4slI
|
||||
c8J0T6Xlzv1XFd43yHhHK1kCgYEAwwc0V9hRVSJahgmhqfq4xQE95tupENVVMq6w
|
||||
CMgw/tY8+MFvLjL0bINu7+uLsFno0Py/2f4JTrKfBG06HfWqAbTKPJhFhQlRczTO
|
||||
xdouOu96LwHaIqsEQrHkculgIZJ4mw1WNIOrLiavZX8cmaEdo8CY5uGLeaYWBogw
|
||||
BQqSoEECgYEAuNXFrwDzUoqiFo9+7gjzT4pjQgh/zNTIODaXwIVBjTRe6Z4bQayd
|
||||
Jel5Gf1IHu9iik6pvaVfK8tMc8eQisEC8F9U9l6mqw/Q4bpQ5k6CQtGe0roBEj2H
|
||||
qJIQ/1TjMAOkOx7YiqTuFP4vs9LhCRAflQQ/Tg0fcHsMWBlPpWlEkRs=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
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
|
||||
eFet28DEMzSifudXY3LYE5N0Vl6g+A==
|
||||
-----END PRIVATE KEY-----
|
||||
|
25
docker/ssl/certs/thing.crt
Normal file
25
docker/ssl/certs/thing.crt
Normal file
@ -0,0 +1,25 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEODCCAyACFCcgfqlRnT0lLgivo40jvyko/V4gMA0GCSqGSIb3DQEBCwUAMFcx
|
||||
EjAQBgNVBAMMCWxvY2FsaG9zdDERMA8GA1UECgwITWFpbmZsdXgxDDAKBgNVBAsM
|
||||
A0lvVDEgMB4GCSqGSIb3DQEJARYRaW5mb0BtYWluZmx1eC5jb20wHhcNMTkwNDAx
|
||||
MDkyNzEyWhcNMjEwMzMxMDkyNzEyWjBaMRAwDgYDVQQDDAdkZWZhdWx0MREwDwYD
|
||||
VQQKDAhNYWluZmx1eDERMA8GA1UECwwIbWFpbmZsdXgxIDAeBgkqhkiG9w0BCQEW
|
||||
EWluZm9AbWFpbmZsdXguY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
|
||||
AgEAuNyXOzUfhH4WOvXgaOIV+ViqXEXO/VfjxPBE4EOYxxk1S5N1tAM5STontEqJ
|
||||
kv8sSInZkYPPPjcqv8yEh1q5GyZrsI3Th5wqovFQEKUwAP2m0bluJYwY0oqo8dcZ
|
||||
vPhcMdEdJu1hzRI0LOiBv5EgkT6KT5z97CfDtV16uaVISywnQmo1TcY7tT0tQs2S
|
||||
znc4kg6mbfGnbmkEHfiV5aOj4ahULd5grdPh+8YcnWXNE/maSZJLOKz2PIMuySS7
|
||||
TmmmgJC6uMpsT5rCGI+WzNwYy8X6731zy/DVaMQ752QJfS0rUPwHa7KiEQNKAyrZ
|
||||
NbYxiILKnbvd/JrN2iW6yllQDQn+XTft1aAui4fQcw/aBQZ5zbiedJeeDtKuve9+
|
||||
X23PVhRumsI4Wfo4CzKBsdH6fT5oGOqmL8WFVCQl/p93vqPRbhadEeEqGgdE2om/
|
||||
1SaA5nl7W4rbfo9beLpmi3KE+oldlLh5/mgH+7vWQQmmidC633AFaY7TabxU/59+
|
||||
38Kzo6eAJauVoHFdXGCIgg/SemNS1KWo3t+pwBHJIPHdsLlWsRVtV5Vt8QW+MlD1
|
||||
ODkApTstom0rtLvBoqBkI+2z29J+i07R4C2K/ZFdhv8Exf/MxUZeET+AznUwLHTE
|
||||
SNxCsI/7wWQVyLVb1AwWLaBbt1cYd4YGVWe+QcslxNNayMkCAwEAATANBgkqhkiG
|
||||
9w0BAQsFAAOCAQEAi7jvvUUMH2yVXfYgLUuBB8jRmwQcYKJo0jbPKZew07F+L3xM
|
||||
WdYP+pDhdkyF79l99/fZS0Xs8dwYtAgU2tVkVoT6p/6vCvnqodgKgZJWi2dNCdG7
|
||||
ftIJR9dkusHIy3cpSHNb+A/hYLvj1nY9IAmRiY1fBNrRflmQe73gUuIjuoqDQ8wV
|
||||
5jteUUt33rH0wYhbMf4z9HFSDBK1Ti+Mw27ybDYnYb79FZjUnXAKR/Gb0QyyGQyI
|
||||
N5sVboXyBEK6KlJ4xBQZ0gEvmhN0ZGgmje4u7+2E3pJxo3zRN8Qm5Poqyll+3Omd
|
||||
3rPdUhkTrQhKC3iMi+hXr4ZjNSlcgF5f+zvRIA==
|
||||
-----END CERTIFICATE-----
|
52
docker/ssl/certs/thing.key
Normal file
52
docker/ssl/certs/thing.key
Normal file
@ -0,0 +1,52 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
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
|
||||
hqHUM7qo5k3nI6/dSdWQ1gBdmv104g==
|
||||
-----END PRIVATE KEY-----
|
@ -84,7 +84,7 @@ The most of the notifications received from the Adapter are non-confirmable. By
|
||||
|
||||
> Server must send a notification in a confirmable message instead of a non-confirmable message at least every 24 hours. This prevents a client that went away or is no longer interested from remaining in the list of observers indefinitely.
|
||||
|
||||
CoAP Adapter sends these notifications every 12 hours. To configure this period, please check [adapter documentation](../coap/README.md) If the client is no longer interested in receiving notifications, the second scenario described above can be used to unsubscribe
|
||||
CoAP Adapter sends these notifications every 12 hours. To configure this period, please check (adapter documentation)[https://www.github.com/mainflux/mainflux/tree/master/coap/README.md) If the client is no longer interested in receiving notifications, the second scenario described above can be used to unsubscribe
|
||||
|
||||
## Subtopics
|
||||
|
||||
|
131
docs/security.md
Normal file
131
docs/security.md
Normal file
@ -0,0 +1,131 @@
|
||||
# **SECURING COMMUNICATION**
|
||||
|
||||
By default gRPC communication is not secure as Mainflux system is most often run in a private network behind the reverse proxy.
|
||||
|
||||
However, TLS can be activated and configured.
|
||||
|
||||
# Server configuration
|
||||
|
||||
## Securing PostgreSQL connections
|
||||
|
||||
By default, Mainflux will connect to Postgres using insecure transport.
|
||||
If a secured connection is required, you can select the SSL mode and set paths to any extra certificates and keys needed.
|
||||
|
||||
`MF_USERS_DB_SSL_MODE` the SSL connection mode for Users.
|
||||
`MF_USERS_DB_SSL_CERT` the path to the certificate file for Users.
|
||||
`MF_USERS_DB_SSL_KEY` the path to the key file for Users.
|
||||
`MF_USERS_DB_SSL_ROOT_CERT` the path to the root certificate file for Users.
|
||||
|
||||
`MF_THINGS_DB_SSL_MODE` the SSL connection mode for Things.
|
||||
`MF_THINGS_DB_SSL_CERT` the path to the certificate file for Things.
|
||||
`MF_THINGS_DB_SSL_KEY` the path to the key file for Things.
|
||||
`MF_THINGS_DB_SSL_ROOT_CERT` the path to the root certificate file for Things.
|
||||
|
||||
Supported database connection modes are: `disabled` (default), `required`, `verify-ca` and `verify-full`.
|
||||
|
||||
## Securing gRPC
|
||||
|
||||
### Users
|
||||
|
||||
If either the cert or key is not set, the server will use insecure transport.
|
||||
|
||||
`MF_USERS_SERVER_CERT` the path to server certificate in pem format.
|
||||
|
||||
`MF_USERS_SERVER_KEY` the path to the server key in pem format.
|
||||
|
||||
### Things
|
||||
|
||||
If either the cert or key is not set, the server will use insecure transport.
|
||||
|
||||
`MF_THINGS_SERVER_CERT` the path to server certificate in pem format.
|
||||
|
||||
`MF_THINGS_SERVER_KEY` the path to the server key in pem format.
|
||||
|
||||
## Client configuration
|
||||
|
||||
If you wish to secure the gRPC connection to `things` and `users` services you must define the CAs that you trust. This does not support mutual certificate authentication.
|
||||
|
||||
### HTTP Adapter
|
||||
|
||||
`MF_HTTP_ADAPTER_CA_CERTS` - the path to a file that contains the CAs in PEM format. If not set, the default connection will be insecure. If it fails to read the file, the adapter will fail to start up.
|
||||
|
||||
### Things
|
||||
|
||||
`MF_THINGS_CA_CERTS` - the path to a file that contains the CAs in PEM format. If not set, the default connection will be insecure. If it fails to read the file, the service will fail to start up.
|
||||
|
||||
# Mutual authentication
|
||||
|
||||
In the most of the cases, HTTPS, WSS, MQTTS or secure CoAP are secure enough. However, sometimes you might need even more secure connection. Mainflux supports mutual TLS authentication (_mTLS_) based on (X.509 certificates)[https://tools.ietf.org/html/rfc5280]. By default the TLS protocol only proves the identity of the server to the client using X.509 certificate and the authentication of the client to the server is left to the application layer. TLS also offers client-to-server authentication using client-side X.509 authentication. This is called two-way or mutual authentication. Mainflux currently supports mTLS over HTTP, WS, and MQTT protocols. In order to run Docker composition with mTLS turned on, you can execute following command from the project root:
|
||||
|
||||
```bash
|
||||
AUTH=x509 docker-compose -f docker/docker-compose.yml up -d
|
||||
```
|
||||
|
||||
Mutual authentication includes client side certificates. Certificates can be generated using simple script provided (here)[http://www.github.com/mainflux/mainflux/tree/master/docker/ssl/Makefile]. In order to create a valid certificate, you need to create Mainflux thing using the process described in the [provisioning section](provisioning.md). After that, you need to fetch created thing key. Thing key will be used to create x.509 certificate for corresponding thing. TO create certificate, execute following commands:
|
||||
|
||||
```bash
|
||||
cd docker/ssl
|
||||
make ca
|
||||
make server_cert
|
||||
make thing_cert KEY=<thing_key> CRT_FILE_NAME=<cert_name>
|
||||
```
|
||||
These commands use (OpenSSL)[https://www.openssl.org/] tool, so please make sure that you have it installed and set up before running these commands.
|
||||
|
||||
- Command `make ca` wil generate self-signed certificate that will later be used as a CA to sign other generated certificates. CA will expire in 3 years.
|
||||
- Command `make server_cert` will generated and sign (with previously created CA) server cert, which will expire after 1000 days. This cert is used as a Mainflux server-side certificate in usual TLS flow to establish HTTPS, WSS, or MQTTS connection.
|
||||
- Command `make thing_cert` wil finally generate and sign client-side certificate and private key for the thing.
|
||||
|
||||
In this example `<thing_key>` represents key of the thing, and `<cert_name>` represents name of the certificate and key file which will be saved in `docker/ssl/certs` directory. Generated Certificate will expire after 2 years. The key must be stored in the x.509 certificate "CN" field. This script is created for the testing purposes and is not meant to be used in production. We strongly recommend avoiding self-signed certificates and using certificate management tool such as (Vault)[https://www.vaultproject.io/] for the production.
|
||||
|
||||
Once you have created CA and server-side cert, you can spin the composition using:
|
||||
|
||||
```bash
|
||||
AUTH=x509 docker-compose -f docker/docker-compose.yml up -d
|
||||
```
|
||||
|
||||
Then, you can create user and provision things and channels. Now, in order to send a message from the specific thing to the channel, you need to connect thing to the channel and generate corresponding client certificate using aforementioned commands. To publish a message to the channel, thing should send following request:
|
||||
|
||||
_HTTPS:_
|
||||
```bash
|
||||
curl -s -S -i --cacert docker/ssl/certs/ca.crt --cert docker/ssl/certs/<thing_cert_name>.crt --key docker/ssl/certs/<thing_cert_key>.key --insecure -X POST -H "Content-Type: application/senml+json" https://localhost/http/channels/<channel_id>/messages -d '[{"bn":"some-base-name:","bt":1.276020076001e+09, "bu":"A","bver":5, "n":"voltage","u":"V","v":120.1}, {"n":"current","t":-5,"v":1.2}, {"n":"current","t":-4,"v":1.3}]'
|
||||
```
|
||||
|
||||
_MQTTS_:
|
||||
|
||||
###### PUBLISH
|
||||
```bash
|
||||
mosquitto_pub -u <thing_id> -P <thing_key> -t channels/<channel_id>/messages -h localhost --cafile docker/ssl/certs/ca.crt --cert docker/ssl/certs/<thing_cert_name>.crt --key docker/ssl/certs/<thing_cert_key>.key -m '[{"bn":"some-base-name:","bt":1.276020076001e+09, "bu":"A","bver":5, "n":"voltage","u":"V","v":120.1}, {"n":"current","t":-5,"v":1.2}, {"n":"current","t":-4,"v":1.3}]'
|
||||
```
|
||||
###### SUBSCRIBE
|
||||
```
|
||||
mosquitto_sub -u <thing_id> -P <thing_key> --cafile docker/ssl/certs/ca.crt --cert docker/ssl/certs/<thing_cert_name>.crt --key docker/ssl/certs/<thing_cert_key>.key -t channels/<channel_id>/messages -h localhost
|
||||
```
|
||||
|
||||
_WSS:_
|
||||
```javascript
|
||||
const WebSocket = require('ws');
|
||||
|
||||
// Do not verify self-signed certificates if you are using one.
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
|
||||
|
||||
// Replace <channel_id> and <thing_key> with real values.
|
||||
const ws = new WebSocket('wss://localhost/ws/channels/<channel_id>/messages?authorization=<thing_key>',
|
||||
// This is ClientOptions object that contains client cert and client key in the form of string. You can easily load these strings from cert and key files.
|
||||
{
|
||||
cert: `-----BEGIN CERTIFICATE-----....`,
|
||||
key: `-----BEGIN RSA PRIVATE KEY-----.....`
|
||||
})
|
||||
|
||||
ws.on('open', () => {
|
||||
ws.send('something')
|
||||
})
|
||||
|
||||
ws.on('message', (data) => {
|
||||
console.log(data)
|
||||
})
|
||||
ws.on('error', (e) => {
|
||||
console.log(e)
|
||||
})
|
||||
```
|
||||
|
||||
As you can see, `Authorization` header does not have to be present in the the HTTP request, since the key is present in the certificate. However, if yoy pass `Authorization` header, it _must be the same as the key in the cert_. In the case of MQTTS, `password` filed in CONNECT message _must match the key from the certificate_. In the case of WSS, `Authorization` header or `authorization` query parameter _must match cert key_.
|
50
docs/tls.md
50
docs/tls.md
@ -1,50 +0,0 @@
|
||||
By default gRPC communication is not secure as Mainflux system is most often run in a private network behind the reverse proxy.
|
||||
|
||||
However, TLS can be activated and configured.
|
||||
|
||||
## Server configuration
|
||||
|
||||
### Securing PostgreSQL connections
|
||||
|
||||
By default, Mainflux will connect to Postgres using insecure transport.
|
||||
If a secured connection is required, you can select the SSL mode and set paths to any extra certificates and keys needed.
|
||||
|
||||
`MF_USERS_DB_SSL_MODE` the SSL connection mode for Users.
|
||||
`MF_USERS_DB_SSL_CERT` the path to the certificate file for Users.
|
||||
`MF_USERS_DB_SSL_KEY` the path to the key file for Users.
|
||||
`MF_USERS_DB_SSL_ROOT_CERT` the path to the root certificate file for Users.
|
||||
|
||||
`MF_THINGS_DB_SSL_MODE` the SSL connection mode for Things.
|
||||
`MF_THINGS_DB_SSL_CERT` the path to the certificate file for Things.
|
||||
`MF_THINGS_DB_SSL_KEY` the path to the key file for Things.
|
||||
`MF_THINGS_DB_SSL_ROOT_CERT` the path to the root certificate file for Things.
|
||||
|
||||
Supported database connection modes are: `disabled` (default), `required`, `verify-ca` and `verify-full`
|
||||
|
||||
### Users
|
||||
|
||||
If either the cert or key is not set, the server will use insecure transport.
|
||||
|
||||
`MF_USERS_SERVER_CERT` the path to server certificate in pem format.
|
||||
|
||||
`MF_USERS_SERVER_KEY` the path to the server key in pem format.
|
||||
|
||||
### Things
|
||||
|
||||
If either the cert or key is not set, the server will use insecure transport.
|
||||
|
||||
`MF_THINGS_SERVER_CERT` the path to server certificate in pem format.
|
||||
|
||||
`MF_THINGS_SERVER_KEY` the path to the server key in pem format.
|
||||
|
||||
## Client configuration
|
||||
|
||||
If you wish to secure the gRPC connection to `things` and `users` services you must define the CAs that you trust. This does not support mutual certificate authentication.
|
||||
|
||||
### HTTP Adapter
|
||||
|
||||
`MF_HTTP_ADAPTER_CA_CERTS` - the path to a file that contains the CAs in PEM format. If not set, the default connection will be insecure. If it fails to read the file, the adapter will fail to start up.
|
||||
|
||||
### Things
|
||||
|
||||
`MF_THINGS_CA_CERTS` - the path to a file that contains the CAs in PEM format. If not set, the default connection will be insecure. If it fails to read the file, the service will fail to start up.
|
@ -33,7 +33,7 @@ pages:
|
||||
- Messaging: messaging.md
|
||||
- Storage: storage.md
|
||||
- LoRa: lora.md
|
||||
- TLS: tls.md
|
||||
- Security: security.md
|
||||
- CLI: cli.md
|
||||
- Bootstrap: bootstrap.md
|
||||
- Developer's Guide: dev-guide.md
|
||||
|
Loading…
x
Reference in New Issue
Block a user