diff --git a/os_brick/initiator/connectors/scaleio.py b/os_brick/initiator/connectors/scaleio.py index 0f65b960d..1ae65ab1a 100644 --- a/os_brick/initiator/connectors/scaleio.py +++ b/os_brick/initiator/connectors/scaleio.py @@ -30,6 +30,7 @@ from os_brick import utils LOG = logging.getLogger(__name__) DEVICE_SCAN_ATTEMPTS_DEFAULT = 3 +CONNECTOR_CONF_PATH = '/opt/emc/scaleio/openstack/connector.conf' synchronized = lockutils.synchronized_with_prefix('os-brick-') @@ -86,6 +87,19 @@ class ScaleIOConnector(base.BaseLinuxConnector): LOG.error(msg) raise exception.BrickException(message=msg) + @staticmethod + def _get_connector_password(config_group, failed_over): + LOG.info("Get ScaleIO connector password from configuration file") + try: + return priv_scaleio.get_connector_password(CONNECTOR_CONF_PATH, + config_group, + failed_over) + except Exception as e: + msg = _("Error getting ScaleIO connector password from " + "configuration file: %s") % e + LOG.error(msg) + raise exception.BrickException(message=msg) + def _rescan_vols(self): LOG.info("ScaleIO rescan volumes") @@ -306,8 +320,10 @@ class ScaleIOConnector(base.BaseLinuxConnector): self.server_ip = connection_properties['serverIP'] self.server_port = connection_properties['serverPort'] self.server_username = connection_properties['serverUsername'] - self.server_password = connection_properties['serverPassword'] - self.server_token = connection_properties['serverToken'] + self.server_password = self._get_connector_password( + connection_properties['config_group'], + connection_properties['failed_over'], + ) self.iops_limit = connection_properties['iopsLimit'] self.bandwidth_limit = connection_properties['bandwidthLimit'] device_info = {'type': 'block', diff --git a/os_brick/privileged/scaleio.py b/os_brick/privileged/scaleio.py index 322289e3f..4b619b45f 100644 --- a/os_brick/privileged/scaleio.py +++ b/os_brick/privileged/scaleio.py @@ -11,12 +11,14 @@ # under the License. from binascii import hexlify +import configparser from contextlib import contextmanager from fcntl import ioctl import os import struct import uuid +from os_brick import exception from os_brick import privileged SCINI_DEVICE_PATH = '/dev/scini' @@ -70,3 +72,32 @@ def rescan_vols(op_code): with open_scini_device() as fd: ioctl(fd, op_code, struct.pack('Q', 0)) + + +@privileged.default.entrypoint +def get_connector_password(filename, config_group, failed_over): + """Read ScaleIO connector configuration file and get appropriate password. + + :param filename: path to connector configuration file + :type filename: str + :param config_group: name of section in configuration file + :type config_group: str + :param failed_over: flag representing if storage is in failed over state + :type failed_over: bool + :return: connector password + :rtype: str + """ + + if not os.path.isfile(filename): + msg = ( + "ScaleIO connector configuration file " + "is not found in path %s." % filename + ) + raise exception.BrickException(message=msg) + + conf = configparser.ConfigParser() + conf.read(filename) + password_key = ( + "replicating_san_password" if failed_over else "san_password" + ) + return conf[config_group][password_key] diff --git a/os_brick/tests/initiator/connectors/test_scaleio.py b/os_brick/tests/initiator/connectors/test_scaleio.py index 70f5546be..88129bde5 100644 --- a/os_brick/tests/initiator/connectors/test_scaleio.py +++ b/os_brick/tests/initiator/connectors/test_scaleio.py @@ -46,8 +46,8 @@ class ScaleIOConnectorTestCase(test_connector.ConnectorTestCase): 'scaleIO_volume_id': self.vol['provider_id'], 'serverPort': 443, 'serverUsername': 'test', - 'serverPassword': 'fake', - 'serverToken': 'fake_token', + 'config_group': 'test', + 'failed_over': False, 'iopsLimit': None, 'bandwidthLimit': None } @@ -84,6 +84,9 @@ class ScaleIOConnectorTestCase(test_connector.ConnectorTestCase): return_value=["emc-vol-{}".format(self.vol['id'])]) # Patch scaleio privileged calls + self.get_password_mock = self.mock_object(scaleio.priv_scaleio, + 'get_connector_password', + return_value='fake_password') self.get_guid_mock = self.mock_object(scaleio.priv_scaleio, 'get_guid', return_value=self.fake_guid) self.rescan_vols_mock = self.mock_object(scaleio.priv_scaleio, @@ -169,6 +172,7 @@ class ScaleIOConnectorTestCase(test_connector.ConnectorTestCase): self.connector.connect_volume(self.fake_connection_properties) self.get_guid_mock.assert_called_once_with( self.connector.GET_GUID_OP_CODE) + self.get_password_mock.assert_called_once() def test_connect_volume_without_volume_id(self): """Successful connect to volume without a Volume Id""" diff --git a/releasenotes/notes/bug-1823200-victoria-b414a1806cba3998.yaml b/releasenotes/notes/bug-1823200-victoria-b414a1806cba3998.yaml new file mode 100644 index 000000000..ec8dfa4c2 --- /dev/null +++ b/releasenotes/notes/bug-1823200-victoria-b414a1806cba3998.yaml @@ -0,0 +1,29 @@ +--- +security: + - | + Dell EMC VxFlex OS driver: This release contains a fix for + `Bug #1823200 `_. + See `OSSN-0086 `_ + for details. +upgrade: + - | + The fix for `Bug #1823200 + `_ requires that a + configuration file be deployed on compute nodes, cinder nodes, and + anywhere you would perform a volume attachment in your deployment, + when using Cinder with a Dell EMC VxFlex OS backend. See the + `Dell EMC VxFlex OS (ScaleIO) Storage driver + `_ + documentation for details about this configuration file. +fixes: + - | + `Bug #1823200 `_: + This release contains an updated connector for use with the Dell EMC + VxFlex OS backend. It requires that a configuration file be deployed + on compute nodes, cinder nodes, and anywhere you would perform a + volume attachment in your deployment. See the + `Dell EMC VxFlex OS (ScaleIO) Storage driver + `_ + documentation for details about the configuration file, and see + `OSSN-0086 `_ for + more information about the security vulnerability.