diff --git a/ironic/common/images.py b/ironic/common/images.py
index 4273d25e29..1bd1755fdb 100644
--- a/ironic/common/images.py
+++ b/ironic/common/images.py
@@ -19,6 +19,7 @@
 Handling of VM disk images.
 """
 
+import contextlib
 import os
 import shutil
 
@@ -154,8 +155,67 @@ def _generate_cfg(kernel_params, template, options):
     return utils.render_template(template, options)
 
 
-def create_isolinux_image_for_bios(output_file, kernel, ramdisk,
-                                   kernel_params=None):
+def _read_dir(root_dir, prefix_dir=None):
+    """Gather files under given directory.
+
+    :param root_dir: a directory to traverse.
+    :returns: a dict mapping absolute paths to relative to the `root_dir`.
+    """
+    files_info = {}
+
+    if not prefix_dir:
+        prefix_dir = root_dir
+
+    for entry in os.listdir(root_dir):
+        path = os.path.join(root_dir, entry)
+        if os.path.isdir(path):
+            files_info.update(_read_dir(path, prefix_dir))
+
+        else:
+            files_info[path] = path[len(prefix_dir) + 1:]
+
+    return files_info
+
+
+@contextlib.contextmanager
+def _collect_files(image_path):
+    """Mount image and return a dictionary of paths found there.
+
+    Mounts given image under a temporary directory, walk its contents
+    and produce a dictionary of absolute->relative paths found on the
+    image.
+
+    :param image_path: ISO9660 or FAT-formatted image to mount.
+    :raises: ImageCreationFailed, if image inspection failed.
+    :returns: a dict mapping absolute paths to relative to the mount point.
+    """
+    if not image_path:
+        yield {}
+        return
+
+    with utils.tempdir() as mount_dir:
+        try:
+            utils.mount(image_path, mount_dir, '-o', 'loop')
+
+        except processutils.ProcessExecutionError as e:
+            LOG.exception("Mounting filesystem image %(image)s "
+                          "failed", {'image': image_path})
+            raise exception.ImageCreationFailed(image_type='iso', error=e)
+
+        try:
+            yield _read_dir(mount_dir)
+
+        except EnvironmentError as e:
+            LOG.exception(
+                "Examining image %(images)s failed: ", {'image': image_path})
+            _umount_without_raise(mount_dir)
+            raise exception.ImageCreationFailed(image_type='iso', error=e)
+
+        _umount_without_raise(mount_dir)
+
+
+def create_isolinux_image_for_bios(
+        output_file, kernel, ramdisk, kernel_params=None, configdrive=None):
     """Creates an isolinux image on the specified file.
 
     Copies the provided kernel, ramdisk to a directory, generates the isolinux
@@ -169,6 +229,8 @@ def create_isolinux_image_for_bios(output_file, kernel, ramdisk,
     :param kernel_params: a list of strings(each element being a string like
         'K=V' or 'K' or combination of them like 'K1=V1,K2,...') to be added
         as the kernel cmdline.
+    :param configdrive: ISO9660 or FAT-formatted OpenStack config drive
+        image. This image will be written onto the built ISO image. Optional.
     :raises: ImageCreationFailed, if image creation failed while copying files
         or while running command to generate iso.
     """
@@ -200,11 +262,15 @@ def create_isolinux_image_for_bios(output_file, kernel, ramdisk,
         if ldlinux_src:
             files_info[ldlinux_src] = LDLINUX_BIN
 
-        try:
-            _create_root_fs(tmpdir, files_info)
-        except (OSError, IOError) as e:
-            LOG.exception("Creating the filesystem root failed.")
-            raise exception.ImageCreationFailed(image_type='iso', error=e)
+        with _collect_files(configdrive) as cfgdrv_files:
+            files_info.update(cfgdrv_files)
+
+            try:
+                _create_root_fs(tmpdir, files_info)
+
+            except EnvironmentError as e:
+                LOG.exception("Creating the filesystem root failed.")
+                raise exception.ImageCreationFailed(image_type='iso', error=e)
 
         cfg = _generate_cfg(kernel_params,
                             CONF.isolinux_config_template, options)
@@ -213,7 +279,8 @@ def create_isolinux_image_for_bios(output_file, kernel, ramdisk,
         utils.write_to_file(isolinux_cfg, cfg)
 
         try:
-            utils.execute('mkisofs', '-r', '-V', "VMEDIA_BOOT_ISO",
+            utils.execute('mkisofs', '-r', '-V',
+                          'config-2' if configdrive else 'VMEDIA_BOOT_ISO',
                           '-cache-inodes', '-J', '-l', '-no-emul-boot',
                           '-boot-load-size', '4', '-boot-info-table',
                           '-b', ISOLINUX_BIN, '-o', output_file, tmpdir)
@@ -222,9 +289,9 @@ def create_isolinux_image_for_bios(output_file, kernel, ramdisk,
             raise exception.ImageCreationFailed(image_type='iso', error=e)
 
 
-def create_esp_image_for_uefi(output_file, kernel, ramdisk,
-                              deploy_iso=None, esp_image=None,
-                              kernel_params=None):
+def create_esp_image_for_uefi(
+        output_file, kernel, ramdisk, deploy_iso=None, esp_image=None,
+        kernel_params=None, configdrive=None):
     """Creates an ESP image on the specified file.
 
     Copies the provided kernel, ramdisk and EFI system partition image (ESP) to
@@ -244,6 +311,8 @@ def create_esp_image_for_uefi(output_file, kernel, ramdisk,
     :param kernel_params: a list of strings(each element being a string like
         'K=V' or 'K' or combination of them like 'K1=V1,K2,...') to be added
         as the kernel cmdline.
+    :param configdrive: ISO9660 or FAT-formatted OpenStack config drive
+        image. This image will be written onto the built ISO image. Optional.
     :raises: ImageCreationFailed, if image creation failed while copying files
         or while running command to generate iso.
     """
@@ -290,16 +359,20 @@ def create_esp_image_for_uefi(output_file, kernel, ramdisk,
 
             files_info.update(uefi_path_info)
 
-            try:
-                _create_root_fs(tmpdir, files_info)
+            with _collect_files(configdrive) as cfgdrv_files:
+                files_info.update(cfgdrv_files)
 
-            except (OSError, IOError) as e:
-                LOG.exception("Creating the filesystem root failed.")
-                raise exception.ImageCreationFailed(image_type='iso', error=e)
+                try:
+                    _create_root_fs(tmpdir, files_info)
 
-            finally:
-                if deploy_iso:
-                    _umount_without_raise(mountdir)
+                except EnvironmentError as e:
+                    LOG.exception("Creating the filesystem root failed.")
+                    raise exception.ImageCreationFailed(
+                        image_type='iso', error=e)
+
+                finally:
+                    if deploy_iso:
+                        _umount_without_raise(mountdir)
 
         # Generate and copy grub config file.
         grub_conf = _generate_cfg(kernel_params,
@@ -308,8 +381,9 @@ def create_esp_image_for_uefi(output_file, kernel, ramdisk,
 
         # Create the boot_iso.
         try:
-            utils.execute('mkisofs', '-r', '-V', "VMEDIA_BOOT_ISO", '-l',
-                          '-e', e_img_rel_path, '-no-emul-boot',
+            utils.execute('mkisofs', '-r', '-V',
+                          'config-2' if configdrive else 'VMEDIA_BOOT_ISO',
+                          '-l', '-e', e_img_rel_path, '-no-emul-boot',
                           '-o', output_file, tmpdir)
 
         except processutils.ProcessExecutionError as e:
@@ -437,7 +511,8 @@ def get_temp_url_for_glance_image(context, image_uuid):
 
 def create_boot_iso(context, output_filename, kernel_href,
                     ramdisk_href, deploy_iso_href=None, esp_image_href=None,
-                    root_uuid=None, kernel_params=None, boot_mode=None):
+                    root_uuid=None, kernel_params=None, boot_mode=None,
+                    configdrive_href=None):
     """Creates a bootable ISO image for a node.
 
     Given the hrefs for kernel, ramdisk, root partition's UUID and
@@ -455,12 +530,15 @@ def create_boot_iso(context, output_filename, kernel_href,
         ISO is desired.
     :param esp_image_href: URL or glance UUID of FAT12/16/32-formatted EFI
         system partition image containing the EFI boot loader (e.g. GRUB2)
-        for each hardware architecture to boot. This image will be embedded
-        into the ISO image. If not specified, the `deploy_iso_href` option
+        for each hardware architecture to boot. This image will be written
+        onto the ISO image. If not specified, the `deploy_iso_href` option
         is only required for building UEFI-bootable ISO.
     :param kernel_params: a string containing whitespace separated values
         kernel cmdline arguments of the form K=V or K (optional).
     :boot_mode: the boot mode in which the deploy is to happen.
+    :param configdrive_href: URL to ISO9660 or FAT-formatted OpenStack config
+        drive image. This image will be embedded into the built ISO image.
+        Optional.
     :raises: ImageCreationFailed, if creating boot ISO failed.
     """
     with utils.tempdir() as tmpdir:
@@ -470,6 +548,14 @@ def create_boot_iso(context, output_filename, kernel_href,
         fetch(context, kernel_href, kernel_path)
         fetch(context, ramdisk_href, ramdisk_path)
 
+        if configdrive_href:
+            configdrive_path = os.path.join(
+                tmpdir, configdrive_href.split('/')[-1])
+            fetch(context, configdrive_href, configdrive_path)
+
+        else:
+            configdrive_path = None
+
         params = []
         if root_uuid:
             params.append('root=UUID=%s' % root_uuid)
@@ -493,17 +579,15 @@ def create_boot_iso(context, output_filename, kernel_href,
             elif CONF.esp_image:
                 esp_image_path = CONF.esp_image
 
-            create_esp_image_for_uefi(output_filename,
-                                      kernel_path,
-                                      ramdisk_path,
-                                      deploy_iso=deploy_iso_path,
-                                      esp_image=esp_image_path,
-                                      kernel_params=params)
+            create_esp_image_for_uefi(
+                output_filename, kernel_path, ramdisk_path,
+                deploy_iso=deploy_iso_path, esp_image=esp_image_path,
+                kernel_params=params, configdrive=configdrive_path)
+
         else:
-            create_isolinux_image_for_bios(output_filename,
-                                           kernel_path,
-                                           ramdisk_path,
-                                           params)
+            create_isolinux_image_for_bios(
+                output_filename, kernel_path, ramdisk_path,
+                kernel_params=params, configdrive=configdrive_path)
 
 
 def is_whole_disk_image(ctx, instance_info):
diff --git a/ironic/drivers/modules/redfish/boot.py b/ironic/drivers/modules/redfish/boot.py
index 107dd42beb..f842a04fdc 100644
--- a/ironic/drivers/modules/redfish/boot.py
+++ b/ironic/drivers/modules/redfish/boot.py
@@ -20,6 +20,7 @@ from urllib import parse as urlparse
 
 from ironic_lib import utils as ironic_utils
 from oslo_log import log
+from oslo_serialization import base64
 from oslo_utils import importutils
 
 from ironic.common import boot_devices
@@ -411,7 +412,8 @@ class RedfishVirtualMediaBoot(base.BootInterface):
 
     @classmethod
     def _prepare_iso_image(cls, task, kernel_href, ramdisk_href,
-                           bootloader_href=None, root_uuid=None, params=None):
+                           bootloader_href=None, configdrive=None,
+                           root_uuid=None, params=None):
         """Prepare an ISO to boot the node.
 
         Build bootable ISO out of `kernel_href` and `ramdisk_href` (and
@@ -423,6 +425,9 @@ class RedfishVirtualMediaBoot(base.BootInterface):
         :param ramdisk_href: URL or Glance UUID of the ramdisk to use
         :param bootloader_href: URL or Glance UUID of the EFI bootloader
              image to use when creating UEFI bootbable ISO
+        :param configdrive: URL to or a compressed blob of a ISO9660 or
+            FAT-formatted OpenStack config drive image. This image will be
+            written onto the built ISO image. Optional.
         :param root_uuid: optional uuid of the root partition.
         :param params: a dictionary containing 'parameter name'->'value'
             mapping to be passed to kernel command line.
@@ -467,24 +472,48 @@ class RedfishVirtualMediaBoot(base.BootInterface):
                        'params': kernel_params})
 
         with tempfile.NamedTemporaryFile(
-                dir=CONF.tempdir, suffix='.iso') as fileobj:
-            boot_iso_tmp_file = fileobj.name
-            images.create_boot_iso(
-                task.context, boot_iso_tmp_file,
-                kernel_href, ramdisk_href,
-                esp_image_href=bootloader_href,
-                root_uuid=root_uuid,
-                kernel_params=kernel_params,
-                boot_mode=boot_mode)
+                dir=CONF.tempdir, suffix='.iso') as boot_fileobj:
 
-            iso_object_name = cls._get_iso_image_name(task.node)
+            with tempfile.NamedTemporaryFile(
+                    dir=CONF.tempdir, suffix='.img') as cfgdrv_fileobj:
 
-            image_url = cls._publish_image(boot_iso_tmp_file, iso_object_name)
+                configdrive_href = configdrive
 
-        LOG.debug("Created ISO %(name)s in Swift for node %(node)s, exposed "
-                  "as temporary URL %(url)s", {'node': task.node.uuid,
-                                               'name': iso_object_name,
-                                               'url': image_url})
+                if configdrive:
+                    parsed_url = urlparse.urlparse(configdrive)
+                    if not parsed_url.scheme:
+                        cfgdrv_blob = base64.decode_as_bytes(configdrive)
+
+                        with open(cfgdrv_fileobj.name, 'wb') as f:
+                            f.write(cfgdrv_blob)
+
+                        configdrive_href = urlparse.urlunparse(
+                            ('file', '', cfgdrv_fileobj.name, '', '', ''))
+
+                    LOG.info("Burning configdrive %(url)s to boot ISO image "
+                             "for node %(node)s", {'url': configdrive_href,
+                                                   'node': task.node.uuid})
+
+                boot_iso_tmp_file = boot_fileobj.name
+                images.create_boot_iso(
+                    task.context, boot_iso_tmp_file,
+                    kernel_href, ramdisk_href,
+                    esp_image_href=bootloader_href,
+                    configdrive_href=configdrive_href,
+                    root_uuid=root_uuid,
+                    kernel_params=kernel_params,
+                    boot_mode=boot_mode)
+
+                iso_object_name = cls._get_iso_image_name(task.node)
+
+                image_url = cls._publish_image(
+                    boot_iso_tmp_file, iso_object_name)
+
+        LOG.debug("Created ISO %(name)s in object store for node %(node)s, "
+                  "exposed as temporary URL "
+                  "%(url)s", {'node': task.node.uuid,
+                              'name': iso_object_name,
+                              'url': image_url})
 
         return image_url
 
diff --git a/ironic/tests/unit/common/test_images.py b/ironic/tests/unit/common/test_images.py
index ddfd5b1501..9aa711f877 100644
--- a/ironic/tests/unit/common/test_images.py
+++ b/ironic/tests/unit/common/test_images.py
@@ -413,6 +413,21 @@ class FsImageTestCase(base.TestCase):
                                    options)
         self.assertEqual(expected_cfg, cfg)
 
+    @mock.patch.object(images, 'os', autospec=True)
+    def test__read_dir(self, mock_os):
+        mock_os.path.join = os.path.join
+        mock_os.path.isdir.side_effect = (False, True, False)
+        mock_os.listdir.side_effect = [['a', 'b'], ['c']]
+
+        file_info = images._read_dir('/mnt')
+
+        expected = {
+            '/mnt/a': 'a',
+            '/mnt/b/c': 'b/c'
+        }
+
+        self.assertEqual(expected, file_info)
+
     @mock.patch.object(os.path, 'relpath', autospec=True)
     @mock.patch.object(os, 'walk', autospec=True)
     @mock.patch.object(utils, 'mount', autospec=True)
@@ -749,8 +764,8 @@ class FsImageTestCase(base.TestCase):
         params = ['root=UUID=root-uuid', 'kernel-params']
         create_isolinux_mock.assert_called_once_with(
             'output_file', 'tmpdir/kernel-uuid', 'tmpdir/ramdisk-uuid',
-            deploy_iso='tmpdir/deploy_iso-uuid', esp_image=None,
-            kernel_params=params)
+            deploy_iso='tmpdir/deploy_iso-uuid',
+            esp_image=None, kernel_params=params, configdrive=None)
 
     @mock.patch.object(images, 'create_esp_image_for_uefi', autospec=True)
     @mock.patch.object(images, 'fetch', autospec=True)
@@ -778,7 +793,7 @@ class FsImageTestCase(base.TestCase):
         create_isolinux_mock.assert_called_once_with(
             'output_file', 'tmpdir/kernel-uuid', 'tmpdir/ramdisk-uuid',
             deploy_iso=None, esp_image='tmpdir/efiboot-uuid',
-            kernel_params=params)
+            kernel_params=params, configdrive=None)
 
     @mock.patch.object(images, 'create_esp_image_for_uefi', autospec=True)
     @mock.patch.object(images, 'fetch', autospec=True)
@@ -805,8 +820,8 @@ class FsImageTestCase(base.TestCase):
         params = ['root=UUID=root-uuid', 'kernel-params']
         create_isolinux_mock.assert_called_once_with(
             'output_file', 'tmpdir/kernel-href', 'tmpdir/ramdisk-href',
-            deploy_iso='tmpdir/deploy_iso-href', esp_image=None,
-            kernel_params=params)
+            deploy_iso='tmpdir/deploy_iso-href',
+            esp_image=None, kernel_params=params, configdrive=None)
 
     @mock.patch.object(images, 'create_esp_image_for_uefi', autospec=True)
     @mock.patch.object(images, 'fetch', autospec=True)
@@ -834,7 +849,7 @@ class FsImageTestCase(base.TestCase):
         create_isolinux_mock.assert_called_once_with(
             'output_file', 'tmpdir/kernel-href', 'tmpdir/ramdisk-href',
             deploy_iso=None, esp_image='tmpdir/efiboot-href',
-            kernel_params=params)
+            kernel_params=params, configdrive=None)
 
     @mock.patch.object(images, 'create_isolinux_image_for_bios', autospec=True)
     @mock.patch.object(images, 'fetch', autospec=True)
@@ -847,25 +862,27 @@ class FsImageTestCase(base.TestCase):
 
         images.create_boot_iso('ctx', 'output_file', 'kernel-uuid',
                                'ramdisk-uuid', 'deploy_iso-uuid',
-                               'efiboot-uuid', 'root-uuid', 'kernel-params',
-                               'bios')
+                               'efiboot-uuid', 'root-uuid',
+                               'kernel-params', 'bios', 'configdrive')
 
         fetch_images_mock.assert_any_call(
             'ctx', 'kernel-uuid', 'tmpdir/kernel-uuid')
         fetch_images_mock.assert_any_call(
             'ctx', 'ramdisk-uuid', 'tmpdir/ramdisk-uuid')
+        fetch_images_mock.assert_any_call(
+            'ctx', 'configdrive', 'tmpdir/configdrive')
+
         # Note (NobodyCam): the original assert asserted that fetch_images
         #                   was not called with parameters, this did not
         #                   work, So I instead assert that there were only
         #                   Two calls to the mock validating the above
         #                   asserts.
-        self.assertEqual(2, fetch_images_mock.call_count)
+        self.assertEqual(3, fetch_images_mock.call_count)
 
         params = ['root=UUID=root-uuid', 'kernel-params']
-        create_isolinux_mock.assert_called_once_with('output_file',
-                                                     'tmpdir/kernel-uuid',
-                                                     'tmpdir/ramdisk-uuid',
-                                                     params)
+        create_isolinux_mock.assert_called_once_with(
+            'output_file', 'tmpdir/kernel-uuid', 'tmpdir/ramdisk-uuid',
+            kernel_params=params, configdrive='tmpdir/configdrive')
 
     @mock.patch.object(images, 'create_isolinux_image_for_bios', autospec=True)
     @mock.patch.object(images, 'fetch', autospec=True)
@@ -879,19 +896,20 @@ class FsImageTestCase(base.TestCase):
 
         images.create_boot_iso('ctx', 'output_file', 'kernel-uuid',
                                'ramdisk-uuid', 'deploy_iso-uuid',
-                               'efiboot-uuid', 'root-uuid', 'kernel-params',
-                               None)
+                               'efiboot-uuid', 'root-uuid',
+                               'kernel-params', None, 'http://configdrive')
 
         fetch_images_mock.assert_any_call(
             'ctx', 'kernel-uuid', 'tmpdir/kernel-uuid')
         fetch_images_mock.assert_any_call(
             'ctx', 'ramdisk-uuid', 'tmpdir/ramdisk-uuid')
+        fetch_images_mock.assert_any_call(
+            'ctx', 'http://configdrive', 'tmpdir/configdrive')
 
         params = ['root=UUID=root-uuid', 'kernel-params']
-        create_isolinux_mock.assert_called_once_with('output_file',
-                                                     'tmpdir/kernel-uuid',
-                                                     'tmpdir/ramdisk-uuid',
-                                                     params)
+        create_isolinux_mock.assert_called_once_with(
+            'output_file', 'tmpdir/kernel-uuid', 'tmpdir/ramdisk-uuid',
+            configdrive='tmpdir/configdrive', kernel_params=params)
 
     @mock.patch.object(image_service, 'get_image_service', autospec=True)
     def test_get_glance_image_properties_no_such_prop(self,
diff --git a/ironic/tests/unit/drivers/modules/redfish/test_boot.py b/ironic/tests/unit/drivers/modules/redfish/test_boot.py
index aa072fa0f7..c1d86486a7 100644
--- a/ironic/tests/unit/drivers/modules/redfish/test_boot.py
+++ b/ironic/tests/unit/drivers/modules/redfish/test_boot.py
@@ -364,6 +364,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
             mock_create_boot_iso.assert_called_once_with(
                 mock.ANY, mock.ANY, 'http://kernel/img', 'http://ramdisk/img',
                 boot_mode='uefi', esp_image_href='http://bootloader/img',
+                configdrive_href=mock.ANY,
                 kernel_params='nofb nomodeset vga=normal',
                 root_uuid='1be26c0b-03f2-4d2e-ae87-c02d7f33c123')
 
@@ -393,6 +394,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
             mock_create_boot_iso.assert_called_once_with(
                 mock.ANY, mock.ANY, 'http://kernel/img', 'http://ramdisk/img',
                 boot_mode=None, esp_image_href=None,
+                configdrive_href=mock.ANY,
                 kernel_params='nofb nomodeset vga=normal',
                 root_uuid='1be26c0b-03f2-4d2e-ae87-c02d7f33c123')
 
@@ -416,6 +418,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
             mock_create_boot_iso.assert_called_once_with(
                 mock.ANY, mock.ANY, 'http://kernel/img', 'http://ramdisk/img',
                 boot_mode=None, esp_image_href=None,
+                configdrive_href=mock.ANY,
                 kernel_params=kernel_params,
                 root_uuid='1be26c0b-03f2-4d2e-ae87-c02d7f33c123')