diff --git a/cmd/docker/main.go b/cmd/docker/main.go index d5c0a90a..9ecd9906 100644 --- a/cmd/docker/main.go +++ b/cmd/docker/main.go @@ -1,10 +1,11 @@ // SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 mochi-mqtt -// SPDX-FileContributor: dgduncan, mochi-co +// SPDX-FileContributor: dgduncan, mochi-co, kevinta893 package main import ( + "crypto/tls" "flag" "github.com/mochi-mqtt/server/v2/config" "log" @@ -40,6 +41,21 @@ func main() { log.Fatal(err) } + for i, listenerConfig := range options.Listeners { + if listenerConfig.TLSCert != nil && listenerConfig.TLSCert.CertFile != nil && listenerConfig.TLSCert.KeyFile != nil && *listenerConfig.TLSCert.CertFile != "" && *listenerConfig.TLSCert.KeyFile != "" { + cert, err := tls.LoadX509KeyPair(*listenerConfig.TLSCert.CertFile, *listenerConfig.TLSCert.KeyFile) + if err != nil { + log.Fatal(err) + } + + options.Listeners[i].TLSConfig = &tls.Config{ + Certificates: []tls.Certificate{cert}, + } + + slog.Info("loaded listener tls cert", "id", listenerConfig.ID, "protocol", listenerConfig.Type, "address", listenerConfig.Address) + } + } + server := mqtt.New(options) go func() { diff --git a/examples/tls-docker/config.json b/examples/tls-docker/config.json new file mode 100644 index 00000000..bec91ef2 --- /dev/null +++ b/examples/tls-docker/config.json @@ -0,0 +1,118 @@ +{ + "listeners": [ + { + "type": "tcp", + "id": "file-tcp1", + "address": ":1883", + "tls_cert": { + "cert_file": "certs/cert.pem", + "key_file": "certs/key.pem" + } + }, + { + "type": "ws", + "id": "file-websocket", + "address": ":1882", + "tls_cert": { + "cert_file": "certs/cert.pem", + "key_file": "certs/key.pem" + } + }, + { + "type": "healthcheck", + "id": "file-healthcheck", + "address": ":1880", + "tls_cert": { + "cert_file": "certs/cert.pem", + "key_file": "certs/key.pem" + } + }, + { + "type": "sysinfo", + "id": "stats", + "address": ":1881", + "tls_cert": { + "cert_file": "certs/cert.pem", + "key_file": "certs/key.pem" + } + } + ], + "hooks": { + "debug": { + "enable": true + }, + "storage": { + "pebble": { + "path": "pebble.db", + "mode": "NoSync" + }, + "badger": { + "path": "badger.db", + "gc_interval": 3, + "gc_discard_ratio": 0.5 + }, + "bolt": { + "path": "bolt.db", + "bucket": "mochi" + }, + "redis": { + "h_prefix": "mc", + "username": "mochi", + "password": "melon", + "address": "localhost:6379", + "database": 1 + } + }, + "auth": { + "allow_all": false, + "ledger": { + "auth": [ + { + "username": "peach", + "password": "password1", + "allow": true + } + ], + "acl": [ + { + "remote": "127.0.0.1:*" + }, + { + "username": "melon", + "filters": null, + "melon/#": 3, + "updates/#": 2 + } + ] + } + } + }, + "options": { + "client_net_write_buffer_size": 2048, + "client_net_read_buffer_size": 2048, + "sys_topic_resend_interval": 10, + "inline_client": true, + "capabilities": { + "maximum_message_expiry_interval": 100, + "maximum_client_writes_pending": 8192, + "maximum_session_expiry_interval": 86400, + "maximum_packet_size": 0, + "receive_maximum": 1024, + "maximum_inflight": 8192, + "topic_alias_maximum": 65535, + "shared_sub_available": 1, + "minimum_protocol_version": 3, + "maximum_qos": 2, + "retain_available": 1, + "wildcard_sub_available": 1, + "sub_id_available": 1, + "compatibilities": { + "obscure_not_authorized": true, + "passive_client_disconnect": false, + "always_return_response_info": false, + "restore_sys_info_on_restart": false, + "no_inherited_properties_on_ack": false + } + } + } +} \ No newline at end of file diff --git a/examples/tls-docker/config.yaml b/examples/tls-docker/config.yaml new file mode 100644 index 00000000..895d6da7 --- /dev/null +++ b/examples/tls-docker/config.yaml @@ -0,0 +1,85 @@ +listeners: + - type: "tcp" + id: "file-tcp1" + address: ":1883" + tls_cert: + cert_file: "certs/cert.pem" + key_file: "certs/cert.key" + - type: "ws" + id: "file-websocket" + address: ":1882" + tls_cert: + cert_file: "certs/cert.pem" + key_file: "certs/cert.key" + - type: "healthcheck" + id: "file-healthcheck" + address: ":1880" + tls_cert: + cert_file: "certs/cert.pem" + key_file: "certs/cert.key" + - type: "sysinfo" + id: "stats" + address: ":1881" + tls_cert: + cert_file: "certs/cert.pem" + key_file: "certs/cert.key" +hooks: + debug: + enable: true + storage: + badger: + path: badger.db + gc_interval: 3 + gc_discard_ratio: 0.5 + pebble: + path: pebble.db + mode: "NoSync" + bolt: + path: bolt.db + bucket: "mochi" + redis: + h_prefix: "mc" + username: "mochi" + password: "melon" + address: "localhost:6379" + database: 1 + auth: + allow_all: false + ledger: + auth: + - username: peach + password: password1 + allow: true + acl: + - remote: 127.0.0.1:* + - username: melon + filters: + melon/#: 3 + updates/#: 2 +options: + client_net_write_buffer_size: 2048 + client_net_read_buffer_size: 2048 + sys_topic_resend_interval: 10 + inline_client: true + capabilities: + maximum_message_expiry_interval: 100 + maximum_client_writes_pending: 8192 + maximum_session_expiry_interval: 86400 + maximum_packet_size: 0 + receive_maximum: 1024 + maximum_inflight: 8192 + topic_alias_maximum: 65535 + shared_sub_available: 1 + minimum_protocol_version: 3 + maximum_qos: 2 + retain_available: 1 + wildcard_sub_available: 1 + sub_id_available: 1 + compatibilities: + obscure_not_authorized: true + passive_client_disconnect: false + always_return_response_info: false + restore_sys_info_on_restart: false + no_inherited_properties_on_ack: false +logging: + level: INFO diff --git a/listeners/listeners.go b/listeners/listeners.go index ded7c370..58620896 100644 --- a/listeners/listeners.go +++ b/listeners/listeners.go @@ -17,10 +17,17 @@ type Config struct { Type string ID string Address string + TLSCert *TlsCertConfig `yaml:"tls_cert" json:"tls_cert"` // TLSConfig is a tls.Config configuration to be used with the listener. See examples folder for basic and mutual-tls use. TLSConfig *tls.Config } +// TlsCertConfig contains file paths for TLS certificate and key files. +type TlsCertConfig struct { + CertFile *string `yaml:"cert_file" json:"cert_file"` + KeyFile *string `yaml:"key_file" json:"key_file"` +} + // EstablishFn is a callback function for establishing new clients. type EstablishFn func(id string, c net.Conn) error