From 9567bbf292c31cc982735e2e9072717b1181e191 Mon Sep 17 00:00:00 2001 From: PhiBo Date: Sat, 12 Nov 2022 09:47:52 +0100 Subject: [PATCH] Add new api option force_no_cert (#124) * Add new option force_no_cert Connect to a router without a certificate by using ADH ciphers. This can be useful when setting up a device. * Changelog * Update plugins/doc_fragments/api.py Co-authored-by: Felix Fontein * Update changelogs/fragments/124-api.yml Co-authored-by: Felix Fontein Co-authored-by: Felix Fontein --- README.md | 1 + changelogs/fragments/124-api.yml | 3 +++ docs/docsite/rst/api-guide.rst | 1 + plugins/doc_fragments/api.py | 11 +++++++++++ plugins/module_utils/api.py | 9 +++++++-- 5 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 changelogs/fragments/124-api.yml diff --git a/README.md b/README.md index d5b538b5..379ae216 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,7 @@ Example playbook: password: "{{ password }}" username: "{{ username }}" tls: true + force_no_cert: false validate_certs: true validate_cert_hostname: true ca_path: /path/to/ca-certificate.pem diff --git a/changelogs/fragments/124-api.yml b/changelogs/fragments/124-api.yml new file mode 100644 index 00000000..6299ceab --- /dev/null +++ b/changelogs/fragments/124-api.yml @@ -0,0 +1,3 @@ +minor_changes: + - api* modules - Add new option ``force_no_cert`` to connect with ADH ciphers + (https://github.com/ansible-collections/community.routeros/pull/124). diff --git a/docs/docsite/rst/api-guide.rst b/docs/docsite/rst/api-guide.rst index 92a96745..f3bb6295 100644 --- a/docs/docsite/rst/api-guide.rst +++ b/docs/docsite/rst/api-guide.rst @@ -107,6 +107,7 @@ Setting up encryption It is recommended to always use ``tls: true`` when connecting with the API, even if you are only connecting to the device through a trusted network. The following options control how TLS/SSL is used: +:force_no_cert: Setting to ``true`` connects to the device without a certificate. **This is discouraged to use in production and is susceptible to Man-in-the-Middle attacks**, but might be useful when setting the device up. The default value is ``false``. :validate_certs: Setting to ``false`` disables any certificate validation. **This is discouraged to use in production**, but is needed when setting the device up. The default value is ``true``. :validate_cert_hostname: Setting to ``false`` (default) disables hostname verification during certificate validation. This is needed if the hostnames specified in the certificate do not match the hostname used for connecting (usually the device's IP). It is recommended to set up the certificate correctly and set this to ``true``; the default ``false`` is chosen for backwards compatibility to an older version of the module. :ca_path: If you are not using a commerically trusted CA certificate to sign your device's certificate, or have not included your CA certificate in Python's truststore, you need to point this option to the CA certificate. diff --git a/plugins/doc_fragments/api.py b/plugins/doc_fragments/api.py index 6b92d288..dea374b9 100644 --- a/plugins/doc_fragments/api.py +++ b/plugins/doc_fragments/api.py @@ -46,6 +46,17 @@ class ModuleDocFragment(object): - RouterOS api port. If I(tls) is set, port will apply to TLS/SSL connection. - Defaults are C(8728) for the HTTP API, and C(8729) for the HTTPS API. type: int + force_no_cert: + description: + - Set to C(true) to connect without a certificate when I(tls=true). + - See also I(validate_certs). + - B(Note:) this forces the use of anonymous Diffie-Hellman (ADH) ciphers. The protocol is susceptible + to Man-in-the-Middle attacks, because the keys used in the exchange are not authenticated. + Instead of simply connecting without a certificate to "make things work" have a look at + I(validate_certs) and I(ca_path). + type: bool + default: false + version_added: 2.4.0 validate_certs: description: - Set to C(false) to skip validation of TLS certificates. diff --git a/plugins/module_utils/api.py b/plugins/module_utils/api.py index 1783f9aa..6ffa1a52 100644 --- a/plugins/module_utils/api.py +++ b/plugins/module_utils/api.py @@ -41,6 +41,7 @@ def api_argument_spec(): hostname=dict(type='str', required=True), port=dict(type='int'), tls=dict(type='bool', default=False, aliases=['ssl']), + force_no_cert=dict(type='bool', default=False), validate_certs=dict(type='bool', default=True), validate_cert_hostname=dict(type='bool', default=False), ca_path=dict(type='path'), @@ -49,7 +50,7 @@ def api_argument_spec(): ) -def _ros_api_connect(module, username, password, host, port, use_tls, validate_certs, validate_cert_hostname, ca_path, encoding, timeout): +def _ros_api_connect(module, username, password, host, port, use_tls, force_no_cert, validate_certs, validate_cert_hostname, ca_path, encoding, timeout): '''Connect to RouterOS API.''' if not port: if use_tls: @@ -68,7 +69,10 @@ def _ros_api_connect(module, username, password, host, port, use_tls, validate_c if use_tls: ctx = ssl.create_default_context(cafile=ca_path) wrap_context = ctx.wrap_socket - if not validate_certs: + if force_no_cert: + ctx.check_hostname = False + ctx.set_ciphers("ADH:@SECLEVEL=0") + elif not validate_certs: ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE elif not validate_cert_hostname: @@ -101,6 +105,7 @@ def create_api(module): module.params['hostname'], module.params['port'], module.params['tls'], + module.params['force_no_cert'], module.params['validate_certs'], module.params['validate_cert_hostname'], module.params['ca_path'],