diff --git a/ironic/drivers/modules/agent_client.py b/ironic/drivers/modules/agent_client.py index e908bd646c..2fb09a99be 100644 --- a/ironic/drivers/modules/agent_client.py +++ b/ironic/drivers/modules/agent_client.py @@ -159,7 +159,7 @@ class AgentClient(object): @METRICS.timer('AgentClient.get_clean_steps') def get_clean_steps(self, node, ports): params = { - 'node': node.as_dict(), + 'node': node.as_dict(secure=True), 'ports': [port.as_dict() for port in ports] } return self._command(node=node, @@ -171,7 +171,7 @@ class AgentClient(object): def execute_clean_step(self, step, node, ports): params = { 'step': step, - 'node': node.as_dict(), + 'node': node.as_dict(secure=True), 'ports': [port.as_dict() for port in ports], 'clean_version': node.driver_internal_info.get( 'hardware_manager_version') diff --git a/ironic/objects/node.py b/ironic/objects/node.py index cffd53d9b8..64a08ad2b5 100644 --- a/ironic/objects/node.py +++ b/ironic/objects/node.py @@ -127,6 +127,15 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat): 'vendor_interface': object_fields.StringField(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): """Check if the input of local_gb, cpus and memory_mb are valid. diff --git a/ironic/tests/unit/drivers/modules/test_agent_client.py b/ironic/tests/unit/drivers/modules/test_agent_client.py index 5f81decaa0..99b7e59ff3 100644 --- a/ironic/tests/unit/drivers/modules/test_agent_client.py +++ b/ironic/tests/unit/drivers/modules/test_agent_client.py @@ -44,7 +44,8 @@ class MockNode(object): } self.instance_info = {} - def as_dict(self): + def as_dict(self, secure=False): + assert secure, 'agent_client must pass secure=True' return { 'uuid': self.uuid, 'driver_internal_info': self.driver_internal_info, @@ -227,7 +228,7 @@ class TestAgentClient(base.TestCase): self.client._command = mock.MagicMock(spec_set=[]) ports = [] expected_params = { - 'node': self.node.as_dict(), + 'node': self.node.as_dict(secure=True), 'ports': [] } @@ -243,7 +244,7 @@ class TestAgentClient(base.TestCase): step = {'priority': 10, 'step': 'erase_devices', 'interface': 'deploy'} expected_params = { 'step': step, - 'node': self.node.as_dict(), + 'node': self.node.as_dict(secure=True), 'ports': [], 'clean_version': self.node.driver_internal_info['hardware_manager_version'] diff --git a/ironic/tests/unit/objects/test_node.py b/ironic/tests/unit/objects/test_node.py index 9dcfc2f188..008c015b17 100644 --- a/ironic/tests/unit/objects/test_node.py +++ b/ironic/tests/unit/objects/test_node.py @@ -34,6 +34,20 @@ class TestNodeObject(db_base.DbTestCase, obj_utils.SchemasTestMixIn): self.fake_node = db_utils.get_test_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): node_id = self.fake_node['id'] with mock.patch.object(self.dbapi, 'get_node_by_id', diff --git a/releasenotes/notes/node-credentials-cleaning-b1903f49ffeba029.yaml b/releasenotes/notes/node-credentials-cleaning-b1903f49ffeba029.yaml new file mode 100644 index 0000000000..ca4829afa8 --- /dev/null +++ b/releasenotes/notes/node-credentials-cleaning-b1903f49ffeba029.yaml @@ -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.