mosquitto: Add role to install and configure mosquitto

This commit is contained in:
Thomas Basler 2024-10-02 21:09:02 +02:00
parent 79af417b4f
commit 42538dc019
9 changed files with 205 additions and 0 deletions

View File

@ -0,0 +1,4 @@
Ansible Role: Mosquitto
=========
Install and configure [Mosquitto](https://mosquitto.org/) MQTT message broker.

View File

@ -0,0 +1,46 @@
---
mosquitto_packages:
- mosquitto
- mosquitto-clients
mosquitto_listeners:
# Listeners for Mosquitto MQTT Broker
- name: "default"
listener: "1883 localhost"
protocol: "mqtt"
use_username_as_clientid: "true"
allow_zero_length_clientid: "true"
allow_anonymous: "false"
users: []
# Users for Mosquitto MQTT Broker
# Type: Arrays of Objects with following parameters defined:
# - username: <string>
# password: <string>
# acl: <Array> of Objects as follows:
# - permissions: <string> Acceptable Value: either `read`, `readwrite`, `write`, `deny`
# - topic: <string> Acceptable Value: your/mqtt/topic (wildcards `+`, and `*` allowed)
auth_anonymous: []
# Topics which are accessable with anonymous access
# Example
# - "topic read topic_name"
auth_patterns: []
# %c to match the client id of the client
# %u to match the username of the client
# Example
# - "pattern write $SYS/broker/connection/%c/state"
mosquitto_bridges: []
# Bridges for Mosquitto MQTT Broker
# Type: Arrays of Objects with following parameters defined:
# - connection: <string>
# address: <string>
# bridge_insecure: <boolean>
# bridge_capath: <string>
# remote_password: <string>
# remote_username: <string>
# remote_clientid: <string>
# try_private: <boolean>
# topics:
# - topic: # in 0 down/ to-level/02/line/
# - topic: # out 0 up/ from-level/02/line/

View File

@ -0,0 +1,34 @@
# mosquitto_passwd.py: Custom Jinja2 filter plugin to generate valid PBKDF2_SHA512
# hash digests for plain-text passwords in `users` file for
# Eclipse Mosquitto Broker
from ansible.errors import AnsibleError
def mosquitto_passwd(passwd):
try:
import passlib.hash
except Exception as e:
raise AnsibleError(
'mosquitto_passlib custom filter requires the passlib pip package installed')
SALT_SIZE = 12
ITERATIONS = 101
salt = passwd[:SALT_SIZE]
salt = bytes(salt, 'utf-8')
salt += b"0" * (SALT_SIZE - len(salt))
digest = passlib.hash.pbkdf2_sha512.using(salt_size=SALT_SIZE, rounds=ITERATIONS, salt=salt) \
.hash(passwd) \
.replace("pbkdf2-sha512", "7") \
.replace(".", "+")
return digest + "=="
class FilterModule(object):
def filters(self):
return {
'mosquitto_passwd': mosquitto_passwd,
}

View File

@ -0,0 +1,6 @@
---
- name: Restart Mosquitto
ansible.builtin.service:
name: mosquitto
state: restarted

View File

@ -0,0 +1,11 @@
---
galaxy_info:
author: Thomas Basler
description: Install Mosquitto
license: None
platforms:
- name: Debian
min_ansible_version: "2.4"
dependencies: []

View File

@ -0,0 +1,35 @@
---
- name: Mosquitto | Install Mosquitto packages
ansible.builtin.apt:
name: "{{ item }}"
state: present
with_items: "{{ mosquitto_packages }}"
notify: Restart Mosquitto
- name: Mosquitto | Generating Configuration File
ansible.builtin.template:
src: mosquitto.conf.j2
dest: /etc/mosquitto/conf.d/mosquitto.conf
mode: "0755"
notify: Restart Mosquitto
- name: Mosquitto | Generating Authentication Users File
ansible.builtin.template:
src: users.j2
dest: "/etc/mosquitto/users_{{ item.name }}"
mode: "0755"
vars:
mosquitto_users: "{{ item.users }}"
with_items: "{{ mosquitto_listeners }}"
notify: Restart Mosquitto
- name: Mosquitto | Generating Access Control List File
ansible.builtin.template:
src: acl.j2
dest: "/etc/mosquitto/acl_{{ item.name }}"
mode: "0755"
vars:
listener: "{{ item }}"
with_items: "{{ mosquitto_listeners }}"
notify: Restart Mosquitto

View File

@ -0,0 +1,28 @@
{{ ansible_managed | comment }}
{% for entry in listener.auth_anonymous | default([]) %}
{% if loop.first %}
# Anonymous access
{% endif %}
{{ entry }}
{% endfor %}
{% for user in listener.users %}
{% if loop.first %}
# User access
{% endif %}
user {{ user.username }}
{% for access_list in user.acl | default([]) %}
topic {{ access_list.permissions }} {{ access_list.topic }}
{% if loop.last %}
{% endif %}
{% endfor %}
{% endfor %}
{% for entry in listener.auth_patterns | default([]) %}
{% if loop.first %}
# Global patterns
{% endif %}
{{ entry }}
{% endfor %}

View File

@ -0,0 +1,36 @@
{{ ansible_managed | comment }}
# Logging Configuration
log_timestamp true
log_type all
# Listener
per_listener_settings true
{% for elem in mosquitto_listeners %}
### Listener '{{ elem.name }}'
listener {{ elem.listener }}
{% for key, value in elem | dictsort %}
{% if key not in ["listener", "name", "users", "auth_anonymous", "auth_patterns"] %}
{{ key }} {{ value }}
{% endif %}
{% endfor %}
password_file /etc/mosquitto/users_{{ elem.name }}
acl_file /etc/mosquitto/acl_{{ elem.name }}
{% endfor %}
{% for elem in mosquitto_bridges %}
{% if loop.first %}
# Bridges
{% endif %}
connection {{ elem.connection }}
{% for key, value in elem | dictsort %}
{% if key not in ["connection", "topics"] %}
{{ key }} {{ value }}
{% endif %}
{% endfor %}
{% for topic in elem.topics %}
topic {{ topic.topic }}
{% endfor %}
{% endfor %}

View File

@ -0,0 +1,5 @@
{{ ansible_managed | comment }}
{% for user in mosquitto_users %}
{{ user.username }}:{{ user.password | mosquitto_passwd }}
{% endfor %}