Do not pass credentials to the ramdisk on cleaning

Currently the driver_info is passed as is to the ramdisk when calling
get_clean_steps or execute_clean_step. This may lead to their exposure,
as ironic<->ramdisk communication is currently not secure.

This change applies the same logic we use in the API to filter
the fields.

Change-Id: I4fd44786fea6c7092d2b0029cea6d680d31babde
Closes-Bug: #1744836
This commit is contained in:
Dmitry Tantsur 2018-01-23 16:13:29 +01:00
parent ccf5e16773
commit c2185469c4
5 changed files with 34 additions and 5 deletions

View File

@ -170,7 +170,7 @@ class AgentClient(object):
@METRICS.timer('AgentClient.get_clean_steps') @METRICS.timer('AgentClient.get_clean_steps')
def get_clean_steps(self, node, ports): def get_clean_steps(self, node, ports):
params = { params = {
'node': node.as_dict(), 'node': node.as_dict(secure=True),
'ports': [port.as_dict() for port in ports] 'ports': [port.as_dict() for port in ports]
} }
return self._command(node=node, return self._command(node=node,
@ -182,7 +182,7 @@ class AgentClient(object):
def execute_clean_step(self, step, node, ports): def execute_clean_step(self, step, node, ports):
params = { params = {
'step': step, 'step': step,
'node': node.as_dict(), 'node': node.as_dict(secure=True),
'ports': [port.as_dict() for port in ports], 'ports': [port.as_dict() for port in ports],
'clean_version': node.driver_internal_info.get( 'clean_version': node.driver_internal_info.get(
'hardware_manager_version') 'hardware_manager_version')

View File

@ -134,6 +134,15 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
'traits': object_fields.ObjectField('TraitList', nullable=True), 'traits': object_fields.ObjectField('TraitList', nullable=True),
} }
def as_dict(self, secure=False):
d = super(Node, self).as_dict()
if secure:
d['driver_info'] = strutils.mask_dict_password(
d.get('driver_info', {}), "******")
d['instance_info'] = strutils.mask_dict_password(
d.get('instance_info', {}), "******")
return d
def _validate_property_values(self, properties): def _validate_property_values(self, properties):
"""Check if the input of local_gb, cpus and memory_mb are valid. """Check if the input of local_gb, cpus and memory_mb are valid.

View File

@ -43,7 +43,8 @@ class MockNode(object):
} }
self.instance_info = {} self.instance_info = {}
def as_dict(self): def as_dict(self, secure=False):
assert secure, 'agent_client must pass secure=True'
return { return {
'uuid': self.uuid, 'uuid': self.uuid,
'driver_internal_info': self.driver_internal_info, 'driver_internal_info': self.driver_internal_info,
@ -245,7 +246,7 @@ class TestAgentClient(base.TestCase):
self.client._command = mock.MagicMock(spec_set=[]) self.client._command = mock.MagicMock(spec_set=[])
ports = [] ports = []
expected_params = { expected_params = {
'node': self.node.as_dict(), 'node': self.node.as_dict(secure=True),
'ports': [] 'ports': []
} }
@ -261,7 +262,7 @@ class TestAgentClient(base.TestCase):
step = {'priority': 10, 'step': 'erase_devices', 'interface': 'deploy'} step = {'priority': 10, 'step': 'erase_devices', 'interface': 'deploy'}
expected_params = { expected_params = {
'step': step, 'step': step,
'node': self.node.as_dict(), 'node': self.node.as_dict(secure=True),
'ports': [], 'ports': [],
'clean_version': 'clean_version':
self.node.driver_internal_info['hardware_manager_version'] self.node.driver_internal_info['hardware_manager_version']

View File

@ -35,6 +35,20 @@ class TestNodeObject(db_base.DbTestCase, obj_utils.SchemasTestMixIn):
self.fake_node = db_utils.get_test_node() self.fake_node = db_utils.get_test_node()
self.node = obj_utils.get_test_node(self.ctxt, **self.fake_node) self.node = obj_utils.get_test_node(self.ctxt, **self.fake_node)
def test_as_dict_insecure(self):
self.node.driver_info['ipmi_password'] = 'fake'
self.node.instance_info['configdrive'] = 'data'
d = self.node.as_dict()
self.assertEqual('fake', d['driver_info']['ipmi_password'])
self.assertEqual('data', d['instance_info']['configdrive'])
def test_as_dict_secure(self):
self.node.driver_info['ipmi_password'] = 'fake'
self.node.instance_info['configdrive'] = 'data'
d = self.node.as_dict(secure=True)
self.assertEqual('******', d['driver_info']['ipmi_password'])
self.assertEqual('******', d['instance_info']['configdrive'])
def test_get_by_id(self): def test_get_by_id(self):
node_id = self.fake_node['id'] node_id = self.fake_node['id']
with mock.patch.object(self.dbapi, 'get_node_by_id', with mock.patch.object(self.dbapi, 'get_node_by_id',

View File

@ -0,0 +1,5 @@
---
security:
- |
Sensitive information is now removed from a node's ``driver_info`` and
``instance_info`` fields before sending it to the ramdisk during cleaning.