Adds tls_version argument to mqtt module (#58264)
Fixes: #22034 This patch adds support for a tls_version parameter that allows the TLS version used to be configurable. By default the module will let the underlying system libraries pick the maximum supported version. This parameter is useful for servers that are unable to support newer versions of TLS
This commit is contained in:
parent
ac101f7f33
commit
48af9bdfec
9 changed files with 270 additions and 15 deletions
|
@ -87,9 +87,16 @@ options:
|
||||||
authentication. Support for this feature is broker dependent.
|
authentication. Support for this feature is broker dependent.
|
||||||
version_added: 2.3
|
version_added: 2.3
|
||||||
aliases: [ keyfile ]
|
aliases: [ keyfile ]
|
||||||
|
tls_version:
|
||||||
|
description:
|
||||||
# informational: requirements for nodes
|
- Specifies the version of the SSL/TLS protocol to be used.
|
||||||
|
- By default (if the python version supports it) the highest TLS version is
|
||||||
|
detected. If unavailable, TLS v1 is used.
|
||||||
|
type: str
|
||||||
|
choices:
|
||||||
|
- tlsv1.1
|
||||||
|
- tlsv1.2
|
||||||
|
version_added: 2.9
|
||||||
requirements: [ mosquitto ]
|
requirements: [ mosquitto ]
|
||||||
notes:
|
notes:
|
||||||
- This module requires a connection to an MQTT broker such as Mosquitto
|
- This module requires a connection to an MQTT broker such as Mosquitto
|
||||||
|
@ -112,7 +119,10 @@ EXAMPLES = '''
|
||||||
#
|
#
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import ssl
|
||||||
import traceback
|
import traceback
|
||||||
|
import platform
|
||||||
|
from distutils.version import LooseVersion
|
||||||
|
|
||||||
HAS_PAHOMQTT = True
|
HAS_PAHOMQTT = True
|
||||||
PAHOMQTT_IMP_ERR = None
|
PAHOMQTT_IMP_ERR = None
|
||||||
|
@ -132,6 +142,10 @@ from ansible.module_utils._text import to_native
|
||||||
#
|
#
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
tls_map = {
|
||||||
|
'tlsv1.2': ssl.PROTOCOL_TLSv1_2,
|
||||||
|
'tlsv1.1': ssl.PROTOCOL_TLSv1_1,
|
||||||
|
}
|
||||||
|
|
||||||
module = AnsibleModule(
|
module = AnsibleModule(
|
||||||
argument_spec=dict(
|
argument_spec=dict(
|
||||||
|
@ -147,6 +161,7 @@ def main():
|
||||||
ca_cert=dict(default=None, type='path', aliases=['ca_certs']),
|
ca_cert=dict(default=None, type='path', aliases=['ca_certs']),
|
||||||
client_cert=dict(default=None, type='path', aliases=['certfile']),
|
client_cert=dict(default=None, type='path', aliases=['certfile']),
|
||||||
client_key=dict(default=None, type='path', aliases=['keyfile']),
|
client_key=dict(default=None, type='path', aliases=['keyfile']),
|
||||||
|
tls_version=dict(default=None, choices=['tlsv1.1', 'tlsv1.2'])
|
||||||
),
|
),
|
||||||
supports_check_mode=True
|
supports_check_mode=True
|
||||||
)
|
)
|
||||||
|
@ -166,6 +181,7 @@ def main():
|
||||||
ca_certs = module.params.get("ca_cert", None)
|
ca_certs = module.params.get("ca_cert", None)
|
||||||
certfile = module.params.get("client_cert", None)
|
certfile = module.params.get("client_cert", None)
|
||||||
keyfile = module.params.get("client_key", None)
|
keyfile = module.params.get("client_key", None)
|
||||||
|
tls_version = module.params.get("tls_version", None)
|
||||||
|
|
||||||
if client_id is None:
|
if client_id is None:
|
||||||
client_id = "%s_%s" % (socket.getfqdn(), os.getpid())
|
client_id = "%s_%s" % (socket.getfqdn(), os.getpid())
|
||||||
|
@ -179,21 +195,42 @@ def main():
|
||||||
|
|
||||||
tls = None
|
tls = None
|
||||||
if ca_certs is not None:
|
if ca_certs is not None:
|
||||||
tls = {'ca_certs': ca_certs, 'certfile': certfile,
|
if tls_version:
|
||||||
'keyfile': keyfile}
|
tls_version = tls_map.get(tls_version, ssl.PROTOCOL_SSLv23)
|
||||||
|
else:
|
||||||
|
if LooseVersion(platform.python_version()) <= "3.5.2":
|
||||||
|
# Specifying `None` on later versions of python seems sufficient to
|
||||||
|
# instruct python to autonegotiate the SSL/TLS connection. On versions
|
||||||
|
# 3.5.2 and lower though we need to specify the version.
|
||||||
|
#
|
||||||
|
# Note that this is an alias for PROTOCOL_TLS, but PROTOCOL_TLS was
|
||||||
|
# not available until 3.5.3.
|
||||||
|
tls_version = ssl.PROTOCOL_SSLv23
|
||||||
|
|
||||||
|
tls = {
|
||||||
|
'ca_certs': ca_certs,
|
||||||
|
'certfile': certfile,
|
||||||
|
'keyfile': keyfile,
|
||||||
|
'tls_version': tls_version,
|
||||||
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
mqtt.single(topic, payload,
|
mqtt.single(
|
||||||
|
topic,
|
||||||
|
payload,
|
||||||
qos=qos,
|
qos=qos,
|
||||||
retain=retain,
|
retain=retain,
|
||||||
client_id=client_id,
|
client_id=client_id,
|
||||||
hostname=server,
|
hostname=server,
|
||||||
port=port,
|
port=port,
|
||||||
auth=auth,
|
auth=auth,
|
||||||
tls=tls)
|
tls=tls
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
module.fail_json(msg="unable to publish to MQTT broker %s" % to_native(e),
|
module.fail_json(
|
||||||
exception=traceback.format_exc())
|
msg="unable to publish to MQTT broker %s" % to_native(e),
|
||||||
|
exception=traceback.format_exc()
|
||||||
|
)
|
||||||
|
|
||||||
module.exit_json(changed=False, topic=topic)
|
module.exit_json(changed=False, topic=topic)
|
||||||
|
|
||||||
|
|
5
test/integration/targets/mqtt/aliases
Normal file
5
test/integration/targets/mqtt/aliases
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
notification/mqtt
|
||||||
|
shippable/posix/group1
|
||||||
|
skip/osx
|
||||||
|
skip/freebsd
|
||||||
|
skip/rhel
|
2
test/integration/targets/mqtt/meta/main.yml
Normal file
2
test/integration/targets/mqtt/meta/main.yml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
dependencies:
|
||||||
|
- setup_mosquitto
|
4
test/integration/targets/mqtt/tasks/main.yml
Normal file
4
test/integration/targets/mqtt/tasks/main.yml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
- include: ubuntu.yml
|
||||||
|
when:
|
||||||
|
- ansible_distribution == 'Ubuntu'
|
||||||
|
- ansible_distribution_release != 'trusty'
|
142
test/integration/targets/mqtt/tasks/ubuntu.yml
Normal file
142
test/integration/targets/mqtt/tasks/ubuntu.yml
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
- name: Install pip packages
|
||||||
|
pip:
|
||||||
|
name: paho-mqtt>=1.4.0
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: MQTT non-TLS endpoint
|
||||||
|
mqtt:
|
||||||
|
topic: /node/s/bar/blurb
|
||||||
|
payload: foo
|
||||||
|
qos: 1
|
||||||
|
client_id: me001
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- result is success
|
||||||
|
|
||||||
|
- name: Send a test message to TLS1.1 endpoint, no client version specified
|
||||||
|
mqtt:
|
||||||
|
topic: /node/s/bar/blurb
|
||||||
|
payload: foo-tls
|
||||||
|
qos: 1
|
||||||
|
client_id: me001
|
||||||
|
ca_certs: /tls/ca_certificate.pem
|
||||||
|
certfile: /tls/client_certificate.pem
|
||||||
|
keyfile: /tls/client_key.pem
|
||||||
|
port: 8883
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- result is success
|
||||||
|
|
||||||
|
- name: Send a test message to TLS1.2 endpoint, no client version specified
|
||||||
|
mqtt:
|
||||||
|
topic: /node/s/bar/blurb
|
||||||
|
payload: foo-tls
|
||||||
|
qos: 1
|
||||||
|
client_id: me001
|
||||||
|
ca_certs: /tls/ca_certificate.pem
|
||||||
|
certfile: /tls/client_certificate.pem
|
||||||
|
keyfile: /tls/client_key.pem
|
||||||
|
port: 8884
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- result is success
|
||||||
|
|
||||||
|
# TODO(Uncomment when TLS1.3 is supported in moquitto and ubuntu version)
|
||||||
|
#
|
||||||
|
# - name: Send a test message to TLS1.3 endpoint
|
||||||
|
# mqtt:
|
||||||
|
# topic: /node/s/bar/blurb
|
||||||
|
# payload: foo-tls
|
||||||
|
# qos: 1
|
||||||
|
# client_id: me001
|
||||||
|
# ca_certs: /tls/ca_certificate.pem
|
||||||
|
# certfile: /tls/client_certificate.pem
|
||||||
|
# keyfile: /tls/client_key.pem
|
||||||
|
# port: 8885
|
||||||
|
# register: result
|
||||||
|
|
||||||
|
#- assert:
|
||||||
|
# that:
|
||||||
|
# - result is success
|
||||||
|
|
||||||
|
- name: Send a message, client TLS1.1, server (required) TLS1.2 - Expected failure
|
||||||
|
mqtt:
|
||||||
|
topic: /node/s/bar/blurb
|
||||||
|
payload: foo-tls
|
||||||
|
qos: 1
|
||||||
|
client_id: me001
|
||||||
|
ca_certs: /tls/ca_certificate.pem
|
||||||
|
certfile: /tls/client_certificate.pem
|
||||||
|
keyfile: /tls/client_key.pem
|
||||||
|
tls_version: tlsv1.1
|
||||||
|
port: 8884
|
||||||
|
register: result
|
||||||
|
failed_when: result is success
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- result is success
|
||||||
|
|
||||||
|
# TODO(Uncomment when TLS1.3 is supported in moquitto and ubuntu version)
|
||||||
|
#
|
||||||
|
# - name: Send a message, client TLS1.1, server (required) TLS1.3 - Expected failure
|
||||||
|
# mqtt:
|
||||||
|
# topic: /node/s/bar/blurb
|
||||||
|
# payload: foo-tls
|
||||||
|
# qos: 1
|
||||||
|
# client_id: me001
|
||||||
|
# ca_certs: /tls/ca_certificate.pem
|
||||||
|
# certfile: /tls/client_certificate.pem
|
||||||
|
# keyfile: /tls/client_key.pem
|
||||||
|
# tls_version: tlsv1.1
|
||||||
|
# port: 8885
|
||||||
|
# register: result
|
||||||
|
# failed_when: result is success
|
||||||
|
|
||||||
|
# - assert:
|
||||||
|
# that:
|
||||||
|
# - result is success
|
||||||
|
|
||||||
|
- name: Send a message, client TLS1.2, server (required) TLS1.1 - Expected failure
|
||||||
|
mqtt:
|
||||||
|
topic: /node/s/bar/blurb
|
||||||
|
payload: foo-tls
|
||||||
|
qos: 1
|
||||||
|
client_id: me001
|
||||||
|
ca_certs: /tls/ca_certificate.pem
|
||||||
|
certfile: /tls/client_certificate.pem
|
||||||
|
keyfile: /tls/client_key.pem
|
||||||
|
tls_version: tlsv1.2
|
||||||
|
port: 8883
|
||||||
|
register: result
|
||||||
|
failed_when: result is success
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- result is success
|
||||||
|
|
||||||
|
# TODO(Uncomment when TLS1.3 is supported in moquitto and ubuntu version)
|
||||||
|
#
|
||||||
|
# - name: Send a message, client TLS1.2, server (required) TLS1.3 - Expected failure
|
||||||
|
# mqtt:
|
||||||
|
# topic: /node/s/bar/blurb
|
||||||
|
# payload: foo-tls
|
||||||
|
# qos: 1
|
||||||
|
# client_id: me001
|
||||||
|
# ca_certs: /tls/ca_certificate.pem
|
||||||
|
# certfile: /tls/client_certificate.pem
|
||||||
|
# keyfile: /tls/client_key.pem
|
||||||
|
# tls_version: tlsv1.2
|
||||||
|
# port: 8885
|
||||||
|
# register: result
|
||||||
|
# failed_when: result is success
|
||||||
|
|
||||||
|
# - assert:
|
||||||
|
# that:
|
||||||
|
# - result is success
|
|
@ -0,0 +1,35 @@
|
||||||
|
# Plain MQTT protocol
|
||||||
|
listener 1883
|
||||||
|
|
||||||
|
# MQTT over TLS 1.1
|
||||||
|
listener 8883
|
||||||
|
tls_version tlsv1.1
|
||||||
|
cafile /tls/ca_certificate.pem
|
||||||
|
certfile /tls/server_certificate.pem
|
||||||
|
keyfile /tls/server_key.pem
|
||||||
|
|
||||||
|
# MQTT over TLS 1.2
|
||||||
|
listener 8884
|
||||||
|
tls_version tlsv1.2
|
||||||
|
cafile /tls/ca_certificate.pem
|
||||||
|
certfile /tls/server_certificate.pem
|
||||||
|
keyfile /tls/server_key.pem
|
||||||
|
|
||||||
|
# TODO(This does not appear to be supported on Ubuntu 18.04. Re-try on 20.04 or next LTS release)
|
||||||
|
# MQTT over TLS 1.3
|
||||||
|
#
|
||||||
|
# listener 8885
|
||||||
|
# tls_version tlsv1.3
|
||||||
|
# cafile /tls/ca_certificate.pem
|
||||||
|
# certfile /tls/server_certificate.pem
|
||||||
|
# keyfile /tls/server_key.pem
|
||||||
|
|
||||||
|
log_dest syslog
|
||||||
|
|
||||||
|
log_type error
|
||||||
|
log_type warning
|
||||||
|
log_type notice
|
||||||
|
log_type information
|
||||||
|
log_type debug
|
||||||
|
|
||||||
|
connection_messages true
|
3
test/integration/targets/setup_mosquitto/meta/main.yml
Normal file
3
test/integration/targets/setup_mosquitto/meta/main.yml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
dependencies:
|
||||||
|
- setup_tls
|
3
test/integration/targets/setup_mosquitto/tasks/main.yml
Normal file
3
test/integration/targets/setup_mosquitto/tasks/main.yml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
- include: ubuntu.yml
|
||||||
|
when: ansible_distribution == 'Ubuntu'
|
24
test/integration/targets/setup_mosquitto/tasks/ubuntu.yml
Normal file
24
test/integration/targets/setup_mosquitto/tasks/ubuntu.yml
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
- name: Install https transport for apt
|
||||||
|
apt:
|
||||||
|
name: apt-transport-https
|
||||||
|
state: latest
|
||||||
|
force: yes
|
||||||
|
|
||||||
|
- name: Install Mosquitto Server
|
||||||
|
apt:
|
||||||
|
name: mosquitto
|
||||||
|
state: latest
|
||||||
|
register: result
|
||||||
|
until: result is success
|
||||||
|
delay: 3
|
||||||
|
retries: 10
|
||||||
|
|
||||||
|
- name: Ensure TLS config
|
||||||
|
copy:
|
||||||
|
src: mosquitto.conf
|
||||||
|
dest: /etc/mosquitto/mosquitto.conf
|
||||||
|
|
||||||
|
- name: Start Mosquitto service
|
||||||
|
service:
|
||||||
|
name: mosquitto
|
||||||
|
state: restarted
|
Loading…
Reference in a new issue