diff --git a/changelogs/fragments/7550-irc-use_tls-validate_certs.yml b/changelogs/fragments/7550-irc-use_tls-validate_certs.yml new file mode 100644 index 0000000000..0c99d8fd6f --- /dev/null +++ b/changelogs/fragments/7550-irc-use_tls-validate_certs.yml @@ -0,0 +1,5 @@ +minor_changes: + - "irc - add ``validate_certs`` option, and rename ``use_ssl`` to ``use_tls``, while keeping ``use_ssl`` as an alias. + The default value for ``validate_certs`` is ``false`` for backwards compatibility. We recommend to every user of + this module to explicitly set ``use_tls=true`` and `validate_certs=true`` whenever possible, especially when + communicating to IRC servers over the internet (https://github.com/ansible-collections/community.general/pull/7550)." diff --git a/plugins/modules/irc.py b/plugins/modules/irc.py index df9d026ac9..7cdf80633c 100644 --- a/plugins/modules/irc.py +++ b/plugins/modules/irc.py @@ -79,11 +79,17 @@ options: - Timeout to use while waiting for successful registration and join messages, this is to prevent an endless loop default: 30 - use_ssl: + use_tls: description: - Designates whether TLS/SSL should be used when connecting to the IRC server + - O(use_tls) is available since community.general 8.1.0, before the option + was exlusively called O(use_ssl). The latter is now an alias of O(use_tls). + - B(Note:) for security reasons, you should always set O(use_tls=true) and + O(validate_certs=true) whenever possible. type: bool default: false + aliases: + - use_ssl part: description: - Designates whether user should part from channel after sending message or not. @@ -96,6 +102,16 @@ options: - Text style for the message. Note italic does not work on some clients choices: [ "bold", "underline", "reverse", "italic", "none" ] default: none + validate_certs: + description: + - If set to V(false), the SSL certificates will not be validated. + - This should always be set to V(true). Using V(false) is unsafe and should only be done + if the network between between Ansible and the IRC server is known to be safe. + - B(Note:) for security reasons, you should always set O(use_tls=true) and + O(validate_certs=true) whenever possible. + default: false + type: bool + version_added: 8.1.0 # informational: requirements for nodes requirements: [ socket ] @@ -108,6 +124,8 @@ EXAMPLES = ''' - name: Send a message to an IRC channel from nick ansible community.general.irc: server: irc.example.net + use_tls: true + validate_certs: true channel: #t1 msg: Hello world @@ -116,6 +134,8 @@ EXAMPLES = ''' module: irc port: 6669 server: irc.example.net + use_tls: true + validate_certs: true channel: #t1 msg: 'All finished at {{ ansible_date_time.iso8601 }}' color: red @@ -126,6 +146,8 @@ EXAMPLES = ''' module: irc port: 6669 server: irc.example.net + use_tls: true + validate_certs: true channel: #t1 nick_to: - nick1 @@ -150,7 +172,8 @@ from ansible.module_utils.basic import AnsibleModule def send_msg(msg, server='localhost', port='6667', channel=None, nick_to=None, key=None, topic=None, - nick="ansible", color='none', passwd=False, timeout=30, use_ssl=False, part=True, style=None): + nick="ansible", color='none', passwd=False, timeout=30, use_tls=False, validate_certs=True, + part=True, style=None): '''send message to IRC''' nick_to = [] if nick_to is None else nick_to @@ -194,14 +217,19 @@ def send_msg(msg, server='localhost', port='6667', channel=None, nick_to=None, k message = styletext + colortext + msg irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - if use_ssl: - if getattr(ssl, 'PROTOCOL_TLS', None) is not None: - # Supported since Python 2.7.13 - context = ssl.SSLContext(ssl.PROTOCOL_TLS) + if use_tls: + if validate_certs: + try: + context = ssl.create_default_context() + except AttributeError: + raise Exception('Need at least Python 2.7.9 for SSL certificate validation') else: - context = ssl.SSLContext() - context.verify_mode = ssl.CERT_NONE - # TODO: create a secure context with `context = ssl.create_default_context()` instead! + if getattr(ssl, 'PROTOCOL_TLS', None) is not None: + # Supported since Python 2.7.13 + context = ssl.SSLContext(ssl.PROTOCOL_TLS) + else: + context = ssl.SSLContext() + context.verify_mode = ssl.CERT_NONE irc = context.wrap_socket(irc) irc.connect((server, int(port))) @@ -282,7 +310,8 @@ def main(): passwd=dict(no_log=True), timeout=dict(type='int', default=30), part=dict(type='bool', default=True), - use_ssl=dict(type='bool', default=False) + use_tls=dict(type='bool', default=False, aliases=['use_ssl']), + validate_certs=dict(type='bool', default=False), ), supports_check_mode=True, required_one_of=[['channel', 'nick_to']] @@ -301,12 +330,13 @@ def main(): key = module.params["key"] passwd = module.params["passwd"] timeout = module.params["timeout"] - use_ssl = module.params["use_ssl"] + use_tls = module.params["use_tls"] part = module.params["part"] style = module.params["style"] + validate_certs = module.params["validate_certs"] try: - send_msg(msg, server, port, channel, nick_to, key, topic, nick, color, passwd, timeout, use_ssl, part, style) + send_msg(msg, server, port, channel, nick_to, key, topic, nick, color, passwd, timeout, use_tls, validate_certs, part, style) except Exception as e: module.fail_json(msg="unable to send to IRC: %s" % to_native(e), exception=traceback.format_exc())