diff --git a/devstack/lib/ironic b/devstack/lib/ironic index a53cc6824a..d1c98f5979 100644 --- a/devstack/lib/ironic +++ b/devstack/lib/ironic @@ -1703,12 +1703,14 @@ function configure_ironic_conductor { local kernel_append_params="nofb nomodeset console=${IRONIC_TTY_DEV}" kernel_append_params+=" systemd.journald.forward_to_console=yes" - if is_service_enabled tls-proxy; then - kernel_append_params+=" ipa-insecure=1" - fi - if [[ -n "kernel_append_params" ]]; then - iniset $IRONIC_CONF_FILE redfish kernel_append_params "$kernel_append_params" + # NOTE(dtantsur): avoid setting ipa-insecure for redfish, we have a way to + # pass the TLS certificate. + iniset $IRONIC_CONF_FILE redfish kernel_append_params "$kernel_append_params" + + if is_service_enabled tls-proxy; then + deploy_int_CA "$IRONIC_STATE_PATH/ironic-ca.pem" + iniset $IRONIC_CONF_FILE agent api_ca_file "$IRONIC_STATE_PATH/ironic-ca.pem" fi # Set these options for scenarios in which the agent fetches the image diff --git a/ironic/common/images.py b/ironic/common/images.py index 3f9fb88379..778f9a12df 100644 --- a/ironic/common/images.py +++ b/ironic/common/images.py @@ -58,6 +58,8 @@ def _create_root_fs(root_directory, files_info): :raises: IOError, if copying any of the files failed. """ for src_file, path in files_info.items(): + LOG.debug('Injecting %(path)s into an ISO from %(source)r', + {'path': path, 'source': src_file}) target_file = os.path.join(root_directory, path) dirname = os.path.dirname(target_file) if dirname: diff --git a/ironic/conf/agent.py b/ironic/conf/agent.py index 55e9aea1c5..33b8b65548 100644 --- a/ironic/conf/agent.py +++ b/ironic/conf/agent.py @@ -159,6 +159,10 @@ opts = [ 'ramdisk. Set to True to use the system default CA ' 'storage. Set to False to disable validation. Ignored ' 'when automatic TLS setup is used.')), + cfg.StrOpt('api_ca_file', + help=_('Path to the TLS CA that is used to start the bare ' + 'metal API. In some boot methods this file can be ' + 'passed to the ramdisk.')), ] diff --git a/ironic/drivers/modules/image_utils.py b/ironic/drivers/modules/image_utils.py index b50ffe867f..b8d2f0c161 100644 --- a/ironic/drivers/modules/image_utils.py +++ b/ironic/drivers/modules/image_utils.py @@ -388,6 +388,12 @@ def _find_param(param_str, param_dict): return val +_TLS_REMOTE_FILE = 'etc/ironic-python-agent/ironic.crt' +_TLS_CONFIG_TEMPLATE = """[DEFAULT] +cafile = /%s +""" % _TLS_REMOTE_FILE + + def prepare_deploy_iso(task, params, mode, d_info): """Prepare deploy or rescue ISO image @@ -430,6 +436,11 @@ def prepare_deploy_iso(task, params, mode, d_info): bootloader_href=bootloader_href, params=params) inject_files = {} + if CONF.agent.api_ca_file: + inject_files[CONF.agent.api_ca_file] = _TLS_REMOTE_FILE + inject_files[_TLS_CONFIG_TEMPLATE.encode('utf-8')] = \ + 'etc/ironic-python-agent.d/ironic-tls.conf' + network_data = task.driver.network.get_node_network_data(task) if network_data: LOG.debug('Injecting custom network data for node %s', diff --git a/ironic/tests/unit/drivers/modules/test_image_utils.py b/ironic/tests/unit/drivers/modules/test_image_utils.py index 7c177a5522..d555ab3f3e 100644 --- a/ironic/tests/unit/drivers/modules/test_image_utils.py +++ b/ironic/tests/unit/drivers/modules/test_image_utils.py @@ -14,6 +14,7 @@ # under the License. import os +import tempfile from unittest import mock from oslo_utils import importutils @@ -430,6 +431,52 @@ class RedfishImageUtilsTestCase(db_base.DbTestCase): find_mock.assert_has_calls(find_call_list) + @mock.patch.object(image_utils, '_find_param', autospec=True) + @mock.patch.object(image_utils, '_prepare_iso_image', autospec=True) + def test_prepare_deploy_iso_tls(self, mock__prepare_iso_image, + find_mock): + with tempfile.NamedTemporaryFile(delete=False) as tf: + temp_name = tf.name + self.addCleanup(lambda: os.unlink(temp_name)) + self.config(api_ca_file=temp_name, group='agent') + tf.write(b'I can haz SSLz') + + with task_manager.acquire(self.context, self.node.uuid, + shared=True) as task: + + d_info = { + 'ilo_deploy_kernel': 'kernel', + 'ilo_deploy_ramdisk': 'ramdisk', + 'ilo_bootloader': 'bootloader' + } + task.node.driver_info.update(d_info) + + find_call_list = [ + mock.call('deploy_kernel', d_info), + mock.call('deploy_ramdisk', d_info), + mock.call('bootloader', d_info) + ] + find_mock.side_effect = [ + 'kernel', 'ramdisk', 'bootloader' + ] + + task.node.instance_info.update(deploy_boot_mode='uefi') + + image_utils.prepare_deploy_iso(task, {}, 'deploy', d_info) + + expected_files = { + b"""[DEFAULT] +cafile = /etc/ironic-python-agent/ironic.crt +""": 'etc/ironic-python-agent.d/ironic-tls.conf', + temp_name: 'etc/ironic-python-agent/ironic.crt' + } + + mock__prepare_iso_image.assert_called_once_with( + task, 'kernel', 'ramdisk', 'bootloader', params={}, + inject_files=expected_files) + + find_mock.assert_has_calls(find_call_list) + @mock.patch.object(image_utils, '_find_param', autospec=True) @mock.patch.object(image_utils, '_prepare_iso_image', autospec=True) @mock.patch.object(images, 'create_boot_iso', autospec=True) diff --git a/releasenotes/notes/vmedia-tls-117daa5ae0a9e30d.yaml b/releasenotes/notes/vmedia-tls-117daa5ae0a9e30d.yaml new file mode 100644 index 0000000000..627f6e8f1f --- /dev/null +++ b/releasenotes/notes/vmedia-tls-117daa5ae0a9e30d.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + A new option ``[agent]api_ca_file`` allows passing a CA file to the + ramdisk when ``redfish-virtual-media`` boot is used. Requires + ironic-python-agent from the Wallaby cycle.