diff --git a/cinder/tests/unit/test_pure.py b/cinder/tests/unit/test_pure.py index 46ca32bb673..d80a81608f6 100644 --- a/cinder/tests/unit/test_pure.py +++ b/cinder/tests/unit/test_pure.py @@ -343,6 +343,8 @@ class PureDriverTestCase(test.TestCase): self.mock_config.volume_backend_name = VOLUME_BACKEND_NAME self.mock_config.safe_get.return_value = None self.mock_config.pure_eradicate_on_delete = False + self.mock_config.driver_ssl_cert_verify = False + self.mock_config.driver_ssl_cert_path = None self.array = mock.Mock() self.array.get.return_value = GET_ARRAY_PRIMARY self.array.array_name = GET_ARRAY_PRIMARY["array_name"] @@ -352,6 +354,7 @@ class PureDriverTestCase(test.TestCase): self.array2.array_id = GET_ARRAY_SECONDARY["id"] self.array2.get.return_value = GET_ARRAY_SECONDARY self.purestorage_module = pure.purestorage + self.purestorage_module.VERSION = '1.4.0' self.purestorage_module.PureHTTPError = FakePureStorageHTTPError def fake_get_array(*args, **kwargs): @@ -392,6 +395,7 @@ class PureBaseSharedDriverTestCase(PureDriverTestCase): super(PureBaseSharedDriverTestCase, self).tearDown() +@ddt.ddt class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase): def setUp(self): super(PureBaseVolumeDriverTestCase, self).setUp() @@ -1885,6 +1889,58 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase): remvollist=[VOLUME_PURITY_NAME] ) + @ddt.data(dict(version='1.5.0'), dict(version='2.0.0')) + @ddt.unpack + def test_get_flasharray_verify_https(self, version): + self.purestorage_module.VERSION = version + san_ip = '1.2.3.4' + api_token = 'abcdef' + cert_path = '/my/ssl/certs' + self.purestorage_module.FlashArray.return_value = mock.MagicMock() + + self.driver._get_flasharray(san_ip, + api_token, + verify_https=True, + ssl_cert_path=cert_path) + self.purestorage_module.FlashArray.assert_called_with( + san_ip, + api_token=api_token, + rest_version=None, + verify_https=True, + ssl_cert=cert_path + ) + + def test_get_flasharray_dont_verify_https_version_too_old(self): + self.purestorage_module.VERSION = '1.4.0' + san_ip = '1.2.3.4' + api_token = 'abcdef' + self.purestorage_module.FlashArray.return_value = mock.MagicMock() + + self.driver._get_flasharray(san_ip, + api_token, + verify_https=False, + ssl_cert_path=None) + self.purestorage_module.FlashArray.assert_called_with( + san_ip, + api_token=api_token, + rest_version=None + ) + + def test_get_flasharray_verify_https_version_too_old(self): + self.purestorage_module.VERSION = '1.4.0' + san_ip = '1.2.3.4' + api_token = 'abcdef' + self.purestorage_module.FlashArray.return_value = mock.MagicMock() + + self.assertRaises( + exception.PureDriverException, + self.driver._get_flasharray, + san_ip, + api_token, + verify_https=True, + ssl_cert_path='/my/ssl/certs' + ) + class PureISCSIDriverTestCase(PureDriverTestCase): diff --git a/cinder/volume/drivers/pure.py b/cinder/volume/drivers/pure.py index b2f0fc06a3a..1b48157b60f 100644 --- a/cinder/volume/drivers/pure.py +++ b/cinder/volume/drivers/pure.py @@ -168,7 +168,14 @@ class PureBaseVolumeDriver(san.SanDriver): backend_id = replication_device["backend_id"] san_ip = replication_device["san_ip"] api_token = replication_device["api_token"] - target_array = self._get_flasharray(san_ip, api_token) + verify_https = replication_device.get("ssl_cert_verify", False) + ssl_cert_path = replication_device.get("ssl_cert_path", None) + target_array = self._get_flasharray( + san_ip, + api_token, + verify_https=verify_https, + ssl_cert_path=ssl_cert_path + ) target_array._backend_id = backend_id LOG.debug("Adding san_ip %(san_ip)s to replication_targets.", {"san_ip": san_ip}) @@ -210,8 +217,10 @@ class PureBaseVolumeDriver(san.SanDriver): self.SUPPORTED_REST_API_VERSIONS self._array = self._get_flasharray( self.configuration.san_ip, - api_token=self.configuration.pure_api_token) - + api_token=self.configuration.pure_api_token, + verify_https=self.configuration.driver_ssl_cert_verify, + ssl_cert_path=self.configuration.driver_ssl_cert_path + ) self._array._backend_id = self._backend_name LOG.debug("Primary array backend_id: %s", self.configuration.config_group) @@ -942,10 +951,31 @@ class PureBaseVolumeDriver(san.SanDriver): self._rename_volume_object(snap_name, unmanaged_snap_name) @staticmethod - def _get_flasharray(san_ip, api_token, rest_version=None): - array = purestorage.FlashArray(san_ip, - api_token=api_token, - rest_version=rest_version) + def _get_flasharray(san_ip, api_token, rest_version=None, + verify_https=None, ssl_cert_path=None): + # Older versions of the module (1.4.0) do not support setting ssl certs + # TODO(patrickeast): In future releases drop support for 1.4.0 + module_version = purestorage.VERSION.split('.') + major_version = int(module_version[0]) + minor_version = int(module_version[1]) + if major_version > 1 or (major_version == 1 and minor_version > 4): + array = purestorage.FlashArray(san_ip, + api_token=api_token, + rest_version=rest_version, + verify_https=verify_https, + ssl_cert=ssl_cert_path) + else: + if verify_https or ssl_cert_path is not None: + msg = _('HTTPS certificate verification was requested ' + 'but cannot be enabled with purestorage ' + 'module version %(version)s. Upgrade to a ' + 'newer version to enable this feature.') % { + 'version': purestorage.VERSION + } + raise exception.PureDriverException(reason=msg) + array = purestorage.FlashArray(san_ip, + api_token=api_token, + rest_version=rest_version) array_info = array.get() array.array_name = array_info["array_name"] array.array_id = array_info["id"] @@ -1135,7 +1165,9 @@ class PureBaseVolumeDriver(san.SanDriver): target_array = self._get_flasharray( secondary_array._target, api_token=secondary_array._api_token, - rest_version='1.3' + rest_version='1.3', + verify_https=secondary_array._verify_https, + ssl_cert_path=secondary_array._ssl_cert ) else: target_array = secondary_array diff --git a/releasenotes/notes/pure-verify-https-requests-464320c97ba77a1f.yaml b/releasenotes/notes/pure-verify-https-requests-464320c97ba77a1f.yaml new file mode 100644 index 00000000000..3c227aaa65e --- /dev/null +++ b/releasenotes/notes/pure-verify-https-requests-464320c97ba77a1f.yaml @@ -0,0 +1,5 @@ +--- +security: + - Pure Storage Volume Drivers can now utilize driver_ssl_cert_verify and + driver_ssl_cert_path config options to allow for secure https requests to + the FlashArray.