From 2c3d418e538cf291a32efb6203134d9090300022 Mon Sep 17 00:00:00 2001 From: tstoner <33665760+tstoner@users.noreply.github.com> Date: Fri, 27 Jul 2018 12:40:39 -0400 Subject: [PATCH] Nxapi ssl (#42905) * NXAPI ssl ciphers & protocols default values * TLSv1, TLSv1.1, TLSv1.2 and weak cipher support * NXOS NXAPI weak/strong cipher & TLSv 1.2, 1.1 & 1.0 support * Version checking for strong/weak ciphers & TLS 1.2, 1.1 & 1.0 support * Cleaned up erroneously committed changes. * Specific NXOS platform checking for nxapi ssl ciphers & protocols * Fixed ansibot reported errors. * Resolved ansibot reported error. * Added network_os_version to mocked up N7K unit test device_info * Calling get_capabilities() once in main and passing results into methods. * Removed raising exceptions when platform capabilities return None per reviewers request. Skipping nxapi ssl options when capabilities are None and generating a warning when these options are skipped * Cleaned up explicit checks for None/not None --- .../modules/network/nxos/nxos_nxapi.py | 129 ++++++++- .../nxos_nxapi/tests/cli/configure.yaml | 1 - .../nxos_nxapi/tests/cli/nxapi_ssl.yaml | 246 ++++++++++++++++++ .../modules/network/nxos/test_nxos_nxapi.py | 2 +- 4 files changed, 362 insertions(+), 16 deletions(-) create mode 100644 test/integration/targets/nxos_nxapi/tests/cli/nxapi_ssl.yaml diff --git a/lib/ansible/modules/network/nxos/nxos_nxapi.py b/lib/ansible/modules/network/nxos/nxos_nxapi.py index 31af55a56d6..504edc40da6 100644 --- a/lib/ansible/modules/network/nxos/nxos_nxapi.py +++ b/lib/ansible/modules/network/nxos/nxos_nxapi.py @@ -94,6 +94,43 @@ options: choices: ['present', 'absent'] required: false default: present + ssl_strong_ciphers: + description: + - Controls the use of whether strong or weak ciphers are configured. + By default, this feature is disabled and weak ciphers are + configured. To enable the use of strong ciphers, set the value of + this argument to True. + required: false + default: no + type: bool + version_added: "2.7" + tlsv1_0: + description: + - Controls the use of the Transport Layer Security version 1.0 is + configured. By default, this feature is enabled. To disable the + use of TLSV1.0, set the value of this argument to True. + required: false + default: yes + type: bool + version_added: "2.7" + tlsv1_1: + description: + - Controls the use of the Transport Layer Security version 1.1 is + configured. By default, this feature is disabled. To enable the + use of TLSV1.1, set the value of this argument to True. + required: false + default: no + type: bool + version_added: "2.7" + tlsv1_2: + description: + - Controls the use of the Transport Layer Security version 1.2 is + configured. By default, this feature is disabled. To enable the + use of TLSV1.2, set the value of this argument to True. + required: false + default: no + type: bool + version_added: "2.7" """ EXAMPLES = """ @@ -124,6 +161,7 @@ updates: """ import re +from distutils.version import LooseVersion from ansible.module_utils.network.nxos.nxos import run_commands, load_config from ansible.module_utils.network.nxos.nxos import nxos_argument_spec from ansible.module_utils.network.nxos.nxos import get_capabilities @@ -131,14 +169,12 @@ from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.six import iteritems -def check_args(module, warnings): - device_info = get_capabilities(module) - - network_api = device_info.get('network_api', 'nxapi') +def check_args(module, warnings, capabilities): + network_api = capabilities.get('network_api', 'nxapi') if network_api == 'nxapi': module.fail_json(msg='module not supported over nxapi transport') - os_platform = device_info['device_info']['network_os_platform'] + os_platform = capabilities['device_info']['network_os_platform'] if '7K' not in os_platform and module.params['sandbox']: module.fail_json(msg='sandbox or enable_sandbox is supported on NX-OS 7K series of switches') @@ -161,9 +197,20 @@ def check_args(module, warnings): return warnings -def map_obj_to_commands(want, have, module): +def map_obj_to_commands(want, have, module, warnings, capabilities): send_commands = list() commands = dict() + os_platform = None + os_version = None + + device_info = capabilities.get('device_info') + if device_info: + os_version = device_info.get('network_os_version') + if os_version: + os_version = os_version[:3] + os_platform = device_info.get('network_os_platform') + if os_platform: + os_platform = os_platform[:3] def needs_update(x): return want.get(x) is not None and (want.get(x) != have.get(x)) @@ -191,8 +238,30 @@ def map_obj_to_commands(want, have, module): if not want['sandbox']: commands['sandbox'] = 'no %s' % commands['sandbox'] - for parameter in commands.keys(): - send_commands.append(commands[parameter]) + if os_platform and os_version: + if (os_platform == 'N9K' or os_platform == 'N3K') and LooseVersion(os_version) >= "9.2": + if needs_update('ssl_strong_ciphers'): + commands['ssl_strong_ciphers'] = 'nxapi ssl ciphers weak' + if want['ssl_strong_ciphers'] is True: + commands['ssl_strong_ciphers'] = 'no nxapi ssl ciphers weak' + + have_ssl_protocols = '' + want_ssl_protocols = '' + for key, value in {'tlsv1_2': 'TLSv1.2', 'tlsv1_1': 'TLSv1.1', 'tlsv1_0': 'TLSv1'}.items(): + if needs_update(key): + if want.get(key) is True: + want_ssl_protocols = " ".join([want_ssl_protocols, value]) + elif have.get(key) is True: + have_ssl_protocols = " ".join([have_ssl_protocols, value]) + + if len(want_ssl_protocols) > 0: + commands['ssl_protocols'] = 'nxapi ssl protocols%s' % (" ".join([want_ssl_protocols, have_ssl_protocols])) + else: + warnings.append('os_version and/or os_platform keys from ' + 'platform capabilities are not available. ' + 'Any NXAPI SSL optional arguments will be ignored') + + send_commands.extend(commands.values()) return send_commands @@ -231,6 +300,27 @@ def parse_sandbox(data): return {'sandbox': value} +def parse_ssl_strong_ciphers(data): + ciphers_res = [r'(\w+) nxapi ssl ciphers weak'] + value = None + + for regex in ciphers_res: + match = re.search(regex, data, re.M) + if match: + value = match.group(1) + break + + return {'ssl_strong_ciphers': value == 'no'} + + +def parse_ssl_protocols(data): + tlsv1_0 = re.search(r'(?=') diff --git a/test/units/modules/network/nxos/test_nxos_nxapi.py b/test/units/modules/network/nxos/test_nxos_nxapi.py index c83432b12c2..405272fdc24 100644 --- a/test/units/modules/network/nxos/test_nxos_nxapi.py +++ b/test/units/modules/network/nxos/test_nxos_nxapi.py @@ -39,7 +39,7 @@ class TestNxosNxapiModule(TestNxosModule): self.mock_get_capabilities = patch('ansible.modules.network.nxos.nxos_nxapi.get_capabilities') self.get_capabilities = self.mock_get_capabilities.start() - self.get_capabilities.return_value = {'device_info': {'network_os_platform': 'N7K-C7018'}, 'network_api': 'cliconf'} + self.get_capabilities.return_value = {'device_info': {'network_os_platform': 'N7K-C7018', 'network_os_version': '8.3(1)'}, 'network_api': 'cliconf'} def tearDown(self): super(TestNxosNxapiModule, self).tearDown()