From 57b3039f2c769b298349096a3704c88b93d7fc5e Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Mon, 19 Jul 2021 13:24:34 -0500 Subject: [PATCH] roles/mosquitto: Update for Mosquitto 2.x Mosquitto 2.x included two significant changes from 1.6: * There is no longer a "default" listener; all listeners are configured in the same way * The daemon drops privileges *before* reading TLS certificates and private keys --- group_vars/home-assistant.yml | 8 +- roles/mosquitto/tasks/main.yml | 9 +- roles/mosquitto/templates/mosquitto.conf.j2 | 338 +++++++------------- 3 files changed, 130 insertions(+), 225 deletions(-) diff --git a/group_vars/home-assistant.yml b/group_vars/home-assistant.yml index dfd0a36..a8aee10 100644 --- a/group_vars/home-assistant.yml +++ b/group_vars/home-assistant.yml @@ -1,6 +1,10 @@ samba_interfaces: - '{{ dch_networks.blue.ipv4_address }}' mosquitto_port: 8883 -mosquitto_certfile: /etc/pki/tls/certs/localhost.crt -mosquitto_keyfile: /etc/pki/tls/private/localhost.key +mosquitto_certfile: /etc/pki/tls/certs/mosquitto.cer +mosquitto_keyfile: /etc/pki/tls/private/mosquitto.key mosquitto_allow_anonymous: false +mosquitto_listeners: +- port: 1883 + address: ::1 +mosquitto_password_file: /etc/mosquitto/passwd diff --git a/roles/mosquitto/tasks/main.yml b/roles/mosquitto/tasks/main.yml index dc9265c..8ad6223 100644 --- a/roles/mosquitto/tasks/main.yml +++ b/roles/mosquitto/tasks/main.yml @@ -9,6 +9,8 @@ copy: src: certs/mosquitto/{{ inventory_hostname }}.cer dest: '{{ mosquitto_certfile }}' + owner: root + group: mosquitto mode: '0644' notify: - restart mosquitto @@ -17,7 +19,10 @@ copy: src: certs/mosquitto/{{ inventory_hostname }}.key dest: '{{ mosquitto_keyfile }}' - mode: '0400' + owner: root + group: mosquitto + mode: '0440' + diff: false notify: - restart mosquitto when: mosquitto_keyfile is defined @@ -39,4 +44,4 @@ - name: ensure mosquitto is running service: name: mosquitto - state: started \ No newline at end of file + state: started diff --git a/roles/mosquitto/templates/mosquitto.conf.j2 b/roles/mosquitto/templates/mosquitto.conf.j2 index f791a3a..dbbf051 100644 --- a/roles/mosquitto/templates/mosquitto.conf.j2 +++ b/roles/mosquitto/templates/mosquitto.conf.j2 @@ -31,20 +31,6 @@ #per_listener_settings false -# If a client is subscribed to multiple subscriptions that overlap, e.g. foo/# -# and foo/+/baz , then MQTT expects that when the broker receives a message on -# a topic that matches both subscriptions, such as foo/bar/baz, then the client -# should only receive the message once. -# Mosquitto keeps track of which clients a message has been sent to in order to -# meet this requirement. The allow_duplicate_messages option allows this -# behaviour to be disabled, which may be useful if you have a large number of -# clients subscribed to the same set of topics and are very concerned about -# minimising memory usage. -# It can be safely set to true if you know in advance that your clients will -# never have overlapping subscriptions, otherwise your clients must be able to -# correctly deal with duplicate messages even when then have QoS=2. -#allow_duplicate_messages false - # This option controls whether a client is allowed to connect with a zero # length client id or not. This option only affects clients using MQTT v3.1.1 # and later. If set to false, clients connecting with a zero length client id @@ -111,12 +97,16 @@ # be queued until the first limit is reached. #max_queued_bytes 0 +# Set the maximum QoS supported. Clients publishing at a QoS higher than +# specified here will be disconnected. +#max_qos 2 + # The maximum number of QoS 1 and 2 messages to hold in a queue per client -# above those that are currently in-flight. Defaults to 100. Set +# above those that are currently in-flight. Defaults to 1000. Set # to 0 for no maximum (not recommended). # See also queue_qos0_messages. # See also max_queued_bytes. -#max_queued_messages 100 +#max_queued_messages 1000 # # This option sets the maximum number of heap memory bytes that the broker will # allocate, and hence sets a hard limit on memory use by the broker. Memory @@ -155,7 +145,7 @@ # Write process id to a file. Default is a blank string which means # a pid file shouldn't be written. -# This should be set to /var/run/mosquitto.pid if mosquitto is +# This should be set to /var/run/mosquitto/mosquitto.pid if mosquitto is # being run automatically on boot with an init script and # start-stop-daemon or similar. #pid_file @@ -192,177 +182,15 @@ # When run as root, drop privileges to this user and its primary # group. # Set to root to stay as root, but this is not recommended. +# If set to "mosquitto", or left unset, and the "mosquitto" user does not exist +# then it will drop privileges to the "nobody" user instead. # If run as a non-root user, this setting has no effect. -# Note that on Windows this has no effect and so mosquitto should -# be started by the user you wish it to run as. +# Note that on Windows this has no effect and so mosquitto should be started by +# the user you wish it to run as. #user mosquitto # ================================================================= -# Default listener -# ================================================================= - -# IP address/hostname to bind the default listener to. If not -# given, the default listener will not be bound to a specific -# address and so will be accessible to all network interfaces. -# bind_address ip-address/host name -#bind_address - -# Port to use for the default listener. -{% if mosquitto_port|d is not none %} -port {{ mosquitto_port }} -{% endif %} - -# Bind the listener to a specific interface. This is similar to -# bind_address above but is useful when an interface has multiple addresses or -# the address may change. It is valid to use this with the bind_address option, -# but take care that the interface you are binding to contains the address you -# are binding to, otherwise you will not be able to connect. -# Example: bind_interface eth0 -#bind_interface - -# When a listener is using the websockets protocol, it is possible to serve -# http data as well. Set http_dir to a directory which contains the files you -# wish to serve. If this option is not specified, then no normal http -# connections will be possible. -#http_dir - -# The maximum number of client connections to allow. This is -# a per listener setting. -# Default is -1, which means unlimited connections. -# Note that other process limits mean that unlimited connections -# are not really possible. Typically the default maximum number of -# connections possible is around 1024. -#max_connections -1 - -# Choose the protocol to use when listening. -# This can be either mqtt or websockets. -# Websockets support is currently disabled by default at compile time. -# Certificate based TLS may be used with websockets, except that -# only the cafile, certfile, keyfile and ciphers options are supported. -#protocol mqtt - -# Set use_username_as_clientid to true to replace the clientid that a client -# connected with with its username. This allows authentication to be tied to -# the clientid, which means that it is possible to prevent one client -# disconnecting another by using the same clientid. -# If a client connects with no username it will be disconnected as not -# authorised when this option is set to true. -# Do not use in conjunction with clientid_prefixes. -# See also use_identity_as_username. -#use_username_as_clientid - -# ----------------------------------------------------------------- -# Certificate based SSL/TLS support -# ----------------------------------------------------------------- -# The following options can be used to enable SSL/TLS support for -# this listener. Note that the recommended port for MQTT over TLS -# is 8883, but this must be set manually. -# -# See also the mosquitto-tls man page. - -# At least one of cafile or capath must be defined. They both -# define methods of accessing the PEM encoded Certificate -# Authority certificates that have signed your server certificate -# and that you wish to trust. -# cafile defines the path to a file containing the CA certificates. -# capath defines a directory that will be searched for files -# containing the CA certificates. For capath to work correctly, the -# certificate files must have ".crt" as the file ending and you must run -# "openssl rehash " each time you add/remove a certificate. -#cafile -#capath - -# Path to the PEM encoded server certificate. -{% if mosquitto_certfile|d is not none %} -certfile {{ mosquitto_certfile }} -{% endif %} - -# Path to the PEM encoded keyfile. -{% if mosquitto_keyfile|d is not none %} -keyfile {{ mosquitto_keyfile }} -{% endif %} - - -# If you have require_certificate set to true, you can create a certificate -# revocation list file to revoke access to particular client certificates. If -# you have done this, use crlfile to point to the PEM encoded revocation file. -#crlfile - -# If you wish to control which encryption ciphers are used, use the ciphers -# option. The list of available ciphers can be obtained using the "openssl -# ciphers" command and should be provided in the same format as the output of -# that command. -# If unset defaults to DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2:@STRENGTH -#ciphers DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2:@STRENGTH - -# To allow the use of ephemeral DH key exchange, which provides forward -# security, the listener must load DH parameters. This can be specified with -# the dhparamfile option. The dhparamfile can be generated with the command -# e.g. "openssl dhparam -out dhparam.pem 2048" -#dhparamfile - -# By default a TLS enabled listener will operate in a similar fashion to a -# https enabled web server, in that the server has a certificate signed by a CA -# and the client will verify that it is a trusted certificate. The overall aim -# is encryption of the network traffic. By setting require_certificate to true, -# the client must provide a valid certificate in order for the network -# connection to proceed. This allows access to the broker to be controlled -# outside of the mechanisms provided by MQTT. -#require_certificate false - -# This option defines the version of the TLS protocol to use for this listener. -# The default value allows all of v1.3, v1.2 and v1.1. The valid values are -# tlsv1.3 tlsv1.2 and tlsv1.1. -#tls_version - -# If require_certificate is true, you may set use_identity_as_username to true -# to use the CN value from the client certificate as a username. If this is -# true, the password_file option will not be used for this listener. -# This takes priority over use_subject_as_username. -# See also use_subject_as_username. -#use_identity_as_username false - -# If require_certificate is true, you may set use_subject_as_username to true -# to use the complete subject value from the client certificate as a username. -# If this is true, the password_file option will not be used for this listener. -# See also use_identity_as_username -#use_subject_as_username false - -# ----------------------------------------------------------------- -# Pre-shared-key based SSL/TLS support -# ----------------------------------------------------------------- -# The following options can be used to enable PSK based SSL/TLS support for -# this listener. Note that the recommended port for MQTT over TLS is 8883, but -# this must be set manually. -# -# See also the mosquitto-tls man page and the "Certificate based SSL/TLS -# support" section. Only one of certificate or PSK encryption support can be -# enabled for any listener. - -# The psk_hint option enables pre-shared-key support for this listener and also -# acts as an identifier for this listener. The hint is sent to clients and may -# be used locally to aid authentication. The hint is a free form string that -# doesn't have much meaning in itself, so feel free to be creative. -# If this option is provided, see psk_file to define the pre-shared keys to be -# used or create a security plugin to handle them. -#psk_hint - -# When using PSK, the encryption ciphers used will be chosen from the list of -# available PSK ciphers. If you want to control which ciphers are available, -# use the "ciphers" option. The list of available ciphers can be obtained -# using the "openssl ciphers" command and should be provided in the same format -# as the output of that command. -#ciphers - -# Set use_identity_as_username to have the psk identity sent by the client used -# as its username. Authentication will be carried out using the PSK rather than -# the MQTT username/password and so password_file will not be used for this -# listener. -#use_identity_as_username false - - -# ================================================================= -# Extra listeners +# Listeners # ================================================================= # Listen on a port/ip address combination. By using this variable @@ -376,16 +204,37 @@ keyfile {{ mosquitto_keyfile }} # interface. By default, mosquitto will listen on all interfaces. # Note that for a websockets listener it is not possible to bind to a host # name. -# listener port-number [ip address/host name] -#listener +# +# On systems that support Unix Domain Sockets, it is also possible +# to create a # Unix socket rather than opening a TCP socket. In +# this case, the port number should be set to 0 and a unix socket +# path must be provided, e.g. +# listener 0 /tmp/mosquitto.sock +# +# listener port-number [ip address/host name/unix socket path] +{% if mosquitto_port|d is not none %} +listener {{ mosquitto_port }} +{% endif %} + +# By default, a listener will attempt to listen on all supported IP protocol +# versions. If you do not have an IPv4 or IPv6 interface you may wish to +# disable support for either of those protocol versions. In particular, note +# that due to the limitations of the websockets library, it will only ever +# attempt to open IPv6 sockets if IPv6 support is compiled in, and so will fail +# if IPv6 is not available. +# +# Set to `ipv4` to force the listener to only use IPv4, or set to `ipv6` to +# force the listener to only use IPv6. If you want support for both IPv4 and +# IPv6, then do not use the socket_domain option. +# +#socket_domain # Bind the listener to a specific interface. This is similar to # the [ip address/host name] part of the listener definition, but is useful -# when an interface has multiple addresses or the address may change. It is -# valid to use this with the [ip address/host name] part of the listener -# definition, but take care that the interface you are binding to contains the -# address you are binding to, otherwise you will not be able to connect. -# Only available on Linux and requires elevated privileges. +# when an interface has multiple addresses or the address may change. If used +# with the [ip address/host name] part of the listener definition, then the +# bind_interface option will take priority. +# Not available on Windows. # # Example: bind_interface eth0 #bind_interface @@ -413,7 +262,7 @@ keyfile {{ mosquitto_keyfile }} # Choose the protocol to use when listening. # This can be either mqtt or websockets. # Certificate based TLS may be used with websockets, except that only the -# cafile, certfile, keyfile and ciphers options are supported. +# cafile, certfile, keyfile, ciphers, and ciphers_tls13 options are supported. #protocol mqtt # Set use_username_as_clientid to true to replace the clientid that a client @@ -444,31 +293,30 @@ keyfile {{ mosquitto_keyfile }} # support" section. Only one of certificate or PSK encryption support can be # enabled for any listener. -# At least one of cafile or capath must be defined to enable certificate based -# TLS encryption. They both define methods of accessing the PEM encoded -# Certificate Authority certificates that have signed your server certificate -# and that you wish to trust. -# cafile defines the path to a file containing the CA certificates. -# capath defines a directory that will be searched for files -# containing the CA certificates. For capath to work correctly, the -# certificate files must have ".crt" as the file ending and you must run -# "openssl rehash " each time you add/remove a certificate. -#cafile -#capath +# Both of certfile and keyfile must be defined to enable certificate based +# TLS encryption. # Path to the PEM encoded server certificate. -#certfile +{% if mosquitto_certfile|d is not none %} +certfile {{ mosquitto_certfile }} +{% endif %} # Path to the PEM encoded keyfile. -#keyfile - +{% if mosquitto_keyfile|d is not none %} +keyfile {{ mosquitto_keyfile }} +{% endif %} # If you wish to control which encryption ciphers are used, use the ciphers # option. The list of available ciphers can be optained using the "openssl # ciphers" command and should be provided in the same format as the output of -# that command. +# that command. This applies to TLS 1.2 and earlier versions only. Use +# ciphers_tls1.3 for TLS v1.3. #ciphers +# Choose which TLS v1.3 ciphersuites are used for this listener. +# Defaults to "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256" +#ciphers_tls1.3 + # If you have require_certificate set to true, you can create a certificate # revocation list file to revoke access to particular client certificates. If # you have done this, use crlfile to point to the PEM encoded revocation file. @@ -489,6 +337,18 @@ keyfile {{ mosquitto_keyfile }} # outside of the mechanisms provided by MQTT. #require_certificate false +# cafile and capath define methods of accessing the PEM encoded +# Certificate Authority certificates that will be considered trusted when +# checking incoming client certificates. +# cafile defines the path to a file containing the CA certificates. +# capath defines a directory that will be searched for files +# containing the CA certificates. For capath to work correctly, the +# certificate files must have ".crt" as the file ending and you must run +# "openssl rehash " each time you add/remove a certificate. +#cafile +#capath + + # If require_certificate is true, you may set use_identity_as_username to true # to use the CN value from the client certificate as a username. If this is # true, the password_file option will not be used for this listener. @@ -525,6 +385,14 @@ keyfile {{ mosquitto_keyfile }} # the MQTT username/password and so password_file will not be used for this # listener. #use_identity_as_username false +{% for listener in mosquitto_listeners %} + + +listener {{ listener.port }} {{ listener.address|d('') }} +{% for option in listener.options|d(()) %} +{{ option }} +{% endfor %} +{% endfor %} # ================================================================= @@ -557,9 +425,9 @@ keyfile {{ mosquitto_keyfile }} # the path. #persistence_file mosquitto.db -# Location for persistent database. Must include trailing / +# Location for persistent database. # Default is an empty string (current directory). -# Set to e.g. /var/lib/mosquitto/ if running as a proper service on Linux or +# Set to e.g. /var/lib/mosquitto if running as a proper service on Linux or # similar. #persistence_location @@ -570,7 +438,7 @@ keyfile {{ mosquitto_keyfile }} # Places to log to. Use multiple log_dest lines for multiple # logging destinations. -# Possible destinations are: stdout stderr syslog topic file +# Possible destinations are: stdout stderr syslog topic file dlt # # stdout and stderr log to the console on the named output. # @@ -588,6 +456,9 @@ keyfile {{ mosquitto_keyfile }} # closed and reopened when the broker receives a HUP signal. Only a single file # destination may be configured. # +# The dlt destination is for the automotive `Diagnostic Log and Trace` tool. +# This requires that Mosquitto has been compiled with DLT support. +# # Note that if the broker is running as a Windows service it will default to # "log_dest none" and neither stdout nor stderr logging is available. # Use "log_dest none" if you wish to disable logging. @@ -649,11 +520,9 @@ keyfile {{ mosquitto_keyfile }} # false then a password file should be created (see the # password_file option) to control authenticated client access. # -# Defaults to true if no other security options are set. If `password_file` or -# `psk_file` is set, or if an authentication plugin is loaded which implements -# username/password or TLS-PSK checks, then `allow_anonymous` defaults to -# false. -# +# Defaults to false, unless there are no listeners defined in the configuration +# file, in which case it is set to true, but connections are only allowed from +# the local machine. {% if mosquitto_allow_anonymous|d is not none %} allow_anonymous {{ mosquitto_allow_anonymous|bool|string|lower }} {% endif %} @@ -674,7 +543,9 @@ allow_anonymous {{ mosquitto_allow_anonymous|bool|string|lower }} # See the TLS client require_certificate and use_identity_as_username options # for alternative authentication options. If an auth_plugin is used as well as # password_file, the auth_plugin check will be made first. -#password_file +{% if mosquitto_password_file|d is not none %} +password_file {{ mosquitto_password_file }} +{% endif %} # Access may also be controlled using a pre-shared-key file. This requires # TLS-PSK support and a listener configured to use it. The file should be text @@ -691,13 +562,17 @@ allow_anonymous {{ mosquitto_allow_anonymous|bool|string|lower }} # comment. # Topic access is added with lines of the format: # -# topic [read|write|readwrite] +# topic [read|write|readwrite|deny] # -# The access type is controlled using "read", "write" or "readwrite". This -# parameter is optional (unless contains a space character) - if not -# given then the access is read/write. can contain the + or # +# The access type is controlled using "read", "write", "readwrite" or "deny". +# This parameter is optional (unless contains a space character) - if +# not given then the access is read/write. can contain the + or # # wildcards as in subscriptions. # +# The "deny" option can used to explicity deny access to a topic that would +# otherwise be granted by a broader read/write/readwrite statement. Any "deny" +# topics are handled before topics that grant read/write access. +# # The first set of topics are applied to anonymous clients, assuming # allow_anonymous is true. User specific topic ACLs are added after a # user line as follows: @@ -801,6 +676,10 @@ allow_anonymous {{ mosquitto_allow_anonymous|bool|string|lower }} #address [:] [[:]] #topic [[[out | in | both] qos-level] local-prefix remote-prefix] +# If you need to have the bridge connect over a particular network interface, +# use bridge_bind_address to tell the bridge which local IP address the socket +# should bind to, e.g. `bridge_bind_address 192.168.1.10` +#bridge_bind_address # If a bridge has topics that have "out" direction, the default behaviour is to # send an unsubscribe request to the remote broker on that topic. This means @@ -811,7 +690,7 @@ allow_anonymous {{ mosquitto_allow_anonymous|bool|string|lower }} #bridge_attempt_unsubscribe true # Set the version of the MQTT protocol to use with for this bridge. Can be one -# of mqttv311 or mqttv11. Defaults to mqttv311. +# of mqttv50, mqttv311 or mqttv31. Defaults to mqttv311. #bridge_protocol_version mqttv311 # Set the clean session variable for this bridge. @@ -929,6 +808,23 @@ allow_anonymous {{ mosquitto_allow_anonymous|bool|string|lower }} # properly. #try_private true +# Some MQTT brokers do not allow retained messages. MQTT v5 gives a mechanism +# for brokers to tell clients that they do not support retained messages, but +# this is not possible for MQTT v3.1.1 or v3.1. If you need to bridge to a +# v3.1.1 or v3.1 broker that does not support retained messages, set the +# bridge_outgoing_retain option to false. This will remove the retain bit on +# all outgoing messages to that bridge, regardless of any other setting. +#bridge_outgoing_retain true + +# If you wish to restrict the size of messages sent to a remote bridge, use the +# bridge_max_packet_size option. This sets the maximum number of bytes for +# the total message, including headers and payload. +# Note that MQTT v5 brokers may provide their own maximum-packet-size property. +# In this case, the smaller of the two limits will be used. +# Set to 0 for "unlimited". +#bridge_max_packet_size 0 + + # ----------------------------------------------------------------- # Certificate based SSL/TLS support # -----------------------------------------------------------------