Allow configuring shred's final overwrite with zeros

Introduce shred_final_overwrite_with_zeros, a new configuration option
to control whether devices will receive a final overwrite with zeros
during cleaning. Additionally, rename erase_devices_iterations to
shred_random_overwrite_iterations to clarify the true meaning of this
configuration option.

Also, ensure a warning is raised in the logs to raise awareness around
the potential security risk of running cleaning with iterations=0 and
overwrite_with_zeros=False.

Change-Id: I0dd3f488ab2cd0df778f34a5a23948fa0c6c4334
Closes-Bug: #1568811
Depends-On: I7053034f5b5bc6737b535ee601e6fb71284d4a83
This commit is contained in:
Mathieu Mitchell 2016-04-11 08:27:08 -04:00
parent 9996949e8e
commit c47c6d2ab5
4 changed files with 109 additions and 16 deletions

View File

@ -907,9 +907,19 @@
# set to 0, will not run during cleaning. (integer value)
#erase_devices_priority = <None>
# Number of iterations to be run for erasing devices. (integer
# value)
#erase_devices_iterations = 1
# During shred, overwrite all block devices N times with
# random data. This is only used if a device could not be ATA
# Secure Erased. Defaults to 1. (integer value)
# Minimum value: 0
# Deprecated group/name - [deploy]/erase_devices_iterations
#shred_random_overwrite_iterations = 1
# Whether to write zeros to a node's block devices after
# writing random data. This will write zeros to the device
# even when deploy.shred_random_overwrite_interations is 0.
# This option is only used if a device could not be ATA Secure
# Erased. Defaults to True. (boolean value)
#shred_final_overwrite_with_zeros = true
# Whether to power off a node after deploy failure. Defaults
# to True. (boolean value)

View File

@ -49,12 +49,12 @@ from ironic import objects
deploy_opts = [
cfg.StrOpt('http_url',
help='ironic-conductor node\'s HTTP server URL. '
'Example: http://192.1.2.3:8080',
help=_("ironic-conductor node's HTTP server URL. "
"Example: http://192.1.2.3:8080"),
deprecated_group='pxe'),
cfg.StrOpt('http_root',
default='/httpboot',
help='ironic-conductor node\'s HTTP root path.',
help=_("ironic-conductor node's HTTP root path."),
deprecated_group='pxe'),
cfg.IntOpt('erase_devices_priority',
help=_('Priority to run in-band erase devices via the Ironic '
@ -62,9 +62,23 @@ deploy_opts = [
'set in the ramdisk (defaults to 10 for the '
'GenericHardwareManager). If set to 0, will not run '
'during cleaning.')),
cfg.IntOpt('erase_devices_iterations',
# TODO(mmitchell): Remove the deprecated name/group during Ocata cycle.
cfg.IntOpt('shred_random_overwrite_iterations',
deprecated_name='erase_devices_iterations',
deprecated_group='deploy',
default=1,
help=_('Number of iterations to be run for erasing devices.')),
min=0,
help=_('During shred, overwrite all block devices N times with '
'random data. This is only used if a device could not '
'be ATA Secure Erased. Defaults to 1.')),
cfg.BoolOpt('shred_final_overwrite_with_zeros',
default=True,
help=_("Whether to write zeros to a node's block devices "
"after writing random data. This will write zeros to "
"the device even when "
"deploy.shred_random_overwrite_interations is 0. This "
"option is only used if a device could not be ATA "
"Secure Erased. Defaults to True.")),
cfg.BoolOpt('power_off_after_deploy_failure',
default=True,
help=_('Whether to power off a node after deploy failure. '
@ -97,6 +111,19 @@ SUPPORTED_CAPABILITIES = {
DISK_LAYOUT_PARAMS = ('root_gb', 'swap_mb', 'ephemeral_gb')
def warn_about_unsafe_shred_parameters():
iterations = CONF.deploy.shred_random_overwrite_iterations
overwrite_with_zeros = CONF.deploy.shred_final_overwrite_with_zeros
if iterations == 0 and overwrite_with_zeros is False:
LOG.warning(_LW('With shred_random_overwrite_iterations set to 0 and '
'shred_final_overwrite_with_zeros set to False, disks '
'may NOT be shredded at all, unless they support ATA '
'Secure Erase. This is a possible SECURITY ISSUE!'))
warn_about_unsafe_shred_parameters()
# All functions are called from deploy() directly or indirectly.
# They are split for stub-out.
@ -629,8 +656,12 @@ def agent_add_clean_params(task):
:param task: a TaskManager instance.
"""
info = task.node.driver_internal_info
passes = CONF.deploy.erase_devices_iterations
info['agent_erase_devices_iterations'] = passes
random_iterations = CONF.deploy.shred_random_overwrite_iterations
info['agent_erase_devices_iterations'] = random_iterations
zeroize = CONF.deploy.shred_final_overwrite_with_zeros
info['agent_erase_devices_zeroize'] = zeroize
task.node.driver_internal_info = info
task.node.save()

View File

@ -1287,7 +1287,8 @@ class OtherFunctionTestCase(db_base.DbTestCase):
log_calls=calls)
def test_set_failed_state_no_poweroff(self):
cfg.CONF.deploy.power_off_after_deploy_failure = False
cfg.CONF.set_override('power_off_after_deploy_failure', False,
'deploy')
exc_state = exception.InvalidState('invalid state')
exc_param = exception.InvalidParameterValue('invalid parameter')
mock_call = mock.call(mock.ANY)
@ -1343,6 +1344,37 @@ class OtherFunctionTestCase(db_base.DbTestCase):
mock_clean_up_caches.assert_called_once_with(None, 'master_dir',
[('uuid', 'path')])
@mock.patch.object(utils, 'LOG', autospec=True)
def test_warn_about_unsafe_shred_parameters_defaults(self, log_mock):
utils.warn_about_unsafe_shred_parameters()
self.assertFalse(log_mock.warning.called)
@mock.patch.object(utils, 'LOG', autospec=True)
def test_warn_about_unsafe_shred_parameters_zeros(self, log_mock):
cfg.CONF.set_override('shred_random_overwrite_iterations', 0, 'deploy')
cfg.CONF.set_override('shred_final_overwrite_with_zeros', True,
'deploy')
utils.warn_about_unsafe_shred_parameters()
self.assertFalse(log_mock.warning.called)
@mock.patch.object(utils, 'LOG', autospec=True)
def test_warn_about_unsafe_shred_parameters_random_no_zeros(self,
log_mock):
cfg.CONF.set_override('shred_random_overwrite_iterations', 1, 'deploy')
cfg.CONF.set_override('shred_final_overwrite_with_zeros', False,
'deploy')
utils.warn_about_unsafe_shred_parameters()
self.assertFalse(log_mock.warning.called)
@mock.patch.object(utils, 'LOG', autospec=True)
def test_warn_about_unsafe_shred_parameters_produces_a_warning(self,
log_mock):
cfg.CONF.set_override('shred_random_overwrite_iterations', 0, 'deploy')
cfg.CONF.set_override('shred_final_overwrite_with_zeros', False,
'deploy')
utils.warn_about_unsafe_shred_parameters()
self.assertTrue(log_mock.warning.called)
class VirtualMediaDeployUtilsTestCase(db_base.DbTestCase):
@ -1680,12 +1712,16 @@ class AgentMethodsTestCase(db_base.DbTestCase):
self.assertEqual(states.CLEANWAIT, response)
def test_agent_add_clean_params(self):
cfg.CONF.deploy.erase_devices_iterations = 2
cfg.CONF.set_override('shred_random_overwrite_iterations', 2, 'deploy')
cfg.CONF.set_override('shred_final_overwrite_with_zeros', False,
'deploy')
with task_manager.acquire(
self.context, self.node.uuid, shared=False) as task:
utils.agent_add_clean_params(task)
self.assertEqual(task.node.driver_internal_info.get(
'agent_erase_devices_iterations'), 2)
self.assertEqual(2, task.node.driver_internal_info.get(
'agent_erase_devices_iterations'))
self.assertEqual(False, task.node.driver_internal_info.get(
'agent_erase_devices_zeroize'))
@mock.patch('ironic.dhcp.neutron.NeutronDHCPApi.delete_cleaning_ports',
autospec=True)
@ -1749,8 +1785,10 @@ class AgentMethodsTestCase(db_base.DbTestCase):
utils.prepare_inband_cleaning(task, manage_boot=manage_boot))
prepare_cleaning_ports_mock.assert_called_once_with(task)
power_mock.assert_called_once_with(task, states.REBOOT)
self.assertEqual(task.node.driver_internal_info.get(
'agent_erase_devices_iterations'), 1)
self.assertEqual(1, task.node.driver_internal_info.get(
'agent_erase_devices_iterations'))
self.assertEqual(True, task.node.driver_internal_info.get(
'agent_erase_devices_zeroize'))
if manage_boot:
prepare_ramdisk_mock.assert_called_once_with(
mock.ANY, mock.ANY, {'a': 'b', 'c': 'd'})

View File

@ -0,0 +1,14 @@
---
features:
- A new configuration option, `shred_final_overwrite_with_zeros` is now
available. This option controls the final overwrite with zeros done on
all block devices for a node under cleaning. This feature was previously
always enabled and not configurable. This option is only used when a
block device could not be ATA Secure Erased.
deprecations:
- The [deploy]/erase_devices_iterations config is deprecated and will
be removed in the Ocata cycle. It has been replaced by the
[deploy]/shred_random_overwrite_iterations config. This configuration
option controls the number of times block devices are overwritten with
random data. This option is only used when a block device could not be
ATA Secure Erased.